libnl  1.1
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-2006 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  * realms 0
24  * protocol RTPROT_STATIC
25  * prio 0
26  * family AF_UNSPEC
27  * type RTN_UNICAST
28  * oif RTNL_LINK_NOT_FOUND
29  * iif NULL
30  * mpalgo IP_MP_ALG_NONE
31  * @endcode
32  *
33  * @{
34  */
35 
36 #include <netlink-local.h>
37 #include <netlink/netlink.h>
38 #include <netlink/cache.h>
39 #include <netlink/utils.h>
40 #include <netlink/data.h>
41 #include <netlink/route/rtnl.h>
42 #include <netlink/route/route.h>
43 #include <netlink/route/link.h>
44 
45 /** @cond SKIP */
46 #define ROUTE_ATTR_FAMILY 0x000001
47 #define ROUTE_ATTR_TOS 0x000002
48 #define ROUTE_ATTR_TABLE 0x000004
49 #define ROUTE_ATTR_PROTOCOL 0x000008
50 #define ROUTE_ATTR_SCOPE 0x000010
51 #define ROUTE_ATTR_TYPE 0x000020
52 #define ROUTE_ATTR_FLAGS 0x000040
53 #define ROUTE_ATTR_DST 0x000080
54 #define ROUTE_ATTR_SRC 0x000100
55 #define ROUTE_ATTR_IIF 0x000200
56 #define ROUTE_ATTR_OIF 0x000400
57 #define ROUTE_ATTR_GATEWAY 0x000800
58 #define ROUTE_ATTR_PRIO 0x001000
59 #define ROUTE_ATTR_PREF_SRC 0x002000
60 #define ROUTE_ATTR_METRICS 0x004000
61 #define ROUTE_ATTR_MULTIPATH 0x008000
62 #define ROUTE_ATTR_REALMS 0x010000
63 #define ROUTE_ATTR_CACHEINFO 0x020000
64 #define ROUTE_ATTR_MP_ALGO 0x040000
65 /** @endcond */
66 
67 static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p);
68 
69 static void route_constructor(struct nl_object *c)
70 {
71  struct rtnl_route *r = (struct rtnl_route *) c;
72 
73  nl_init_list_head(&r->rt_nexthops);
74 }
75 
76 static void route_free_data(struct nl_object *c)
77 {
78  struct rtnl_route *r = (struct rtnl_route *) c;
79  struct rtnl_nexthop *nh, *tmp;
80 
81  if (r == NULL)
82  return;
83 
84  nl_addr_put(r->rt_dst);
85  nl_addr_put(r->rt_src);
86  nl_addr_put(r->rt_gateway);
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(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  if (src->rt_dst)
102  if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
103  goto errout;
104 
105  if (src->rt_src)
106  if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
107  goto errout;
108 
109  if (src->rt_gateway)
110  if (!(dst->rt_gateway = nl_addr_clone(src->rt_gateway)))
111  goto errout;
112 
113  if (src->rt_pref_src)
114  if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
115  goto errout;
116 
117  nl_init_list_head(&dst->rt_nexthops);
118  nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
119  new = rtnl_route_nh_clone(nh);
120  if (!new)
121  goto errout;
122 
123  rtnl_route_add_nexthop(dst, new);
124  }
125 
126  return 0;
127 errout:
128  return nl_get_errno();
129 }
130 
131 static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p)
132 {
133  struct rtnl_route *r = (struct rtnl_route *) a;
134  struct nl_cache *link_cache;
135  char buf[64];
136 
137  link_cache = nl_cache_mngt_require("route/link");
138 
139  if (!(r->ce_mask & ROUTE_ATTR_DST) ||
140  nl_addr_get_len(r->rt_dst) == 0)
141  dp_dump(p, "default ");
142  else
143  dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
144 
145  if (r->ce_mask & ROUTE_ATTR_OIF) {
146  if (link_cache)
147  dp_dump(p, "dev %s ",
148  rtnl_link_i2name(link_cache, r->rt_oif,
149  buf, sizeof(buf)));
150  else
151  dp_dump(p, "dev %d ", r->rt_oif);
152  }
153 
154  if (r->ce_mask & ROUTE_ATTR_GATEWAY)
155  dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf,
156  sizeof(buf)));
157  else if (r->ce_mask & ROUTE_ATTR_MULTIPATH)
158  dp_dump(p, "via nexthops ");
159 
160  if (r->ce_mask & ROUTE_ATTR_SCOPE)
161  dp_dump(p, "scope %s ",
162  rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
163 
164  if (r->ce_mask & ROUTE_ATTR_FLAGS && r->rt_flags) {
165  int flags = r->rt_flags;
166 
167  dp_dump(p, "<");
168 
169 #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
170  flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
171  PRINT_FLAG(DEAD);
172  PRINT_FLAG(ONLINK);
173  PRINT_FLAG(PERVASIVE);
174 #undef PRINT_FLAG
175 
176 #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
177  flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
178  PRINT_FLAG(NOTIFY);
179  PRINT_FLAG(CLONED);
180  PRINT_FLAG(EQUALIZE);
181  PRINT_FLAG(PREFIX);
182 #undef PRINT_FLAG
183 
184  dp_dump(p, ">");
185  }
186 
187  dp_dump(p, "\n");
188 
189  return 1;
190 }
191 
192 static int route_dump_full(struct nl_object *a, struct nl_dump_params *p)
193 {
194  struct rtnl_route *r = (struct rtnl_route *) a;
195  struct nl_cache *link_cache;
196  char buf[128];
197  int i, line;
198 
199  link_cache = nl_cache_mngt_require("route/link");
200  line = route_dump_brief(a, p);
201 
202  if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
203  struct rtnl_nexthop *nh;
204 
205  nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
206  dp_dump_line(p, line++, " via ");
207 
208  if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
209  dp_dump(p, "%s ",
210  nl_addr2str(nh->rtnh_gateway,
211  buf, sizeof(buf)));
212  if (link_cache) {
213  dp_dump(p, "dev %s ",
214  rtnl_link_i2name(link_cache,
215  nh->rtnh_ifindex,
216  buf, sizeof(buf)));
217  } else
218  dp_dump(p, "dev %d ", nh->rtnh_ifindex);
219 
220  dp_dump(p, "weight %u <%s>\n", nh->rtnh_weight,
221  rtnl_route_nh_flags2str(nh->rtnh_flags,
222  buf, sizeof(buf)));
223  }
224  }
225 
226  dp_dump_line(p, line++, " ");
227 
228  if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
229  dp_dump(p, "preferred-src %s ",
230  nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
231 
232  if (r->ce_mask & ROUTE_ATTR_TABLE)
233  dp_dump(p, "table %s ",
234  rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
235 
236  if (r->ce_mask & ROUTE_ATTR_TYPE)
237  dp_dump(p, "type %s ",
238  nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
239 
240  if (r->ce_mask & ROUTE_ATTR_PRIO)
241  dp_dump(p, "metric %#x ", r->rt_prio);
242 
243  if (r->ce_mask & ROUTE_ATTR_FAMILY)
244  dp_dump(p, "family %s ",
245  nl_af2str(r->rt_family, buf, sizeof(buf)));
246 
247  if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
248  dp_dump(p, "protocol %s ",
249  rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
250 
251  dp_dump(p, "\n");
252 
253  if ((r->ce_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS |
254  ROUTE_ATTR_REALMS)) ||
255  ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
256  r->rt_cacheinfo.rtci_error)) {
257  dp_dump_line(p, line++, " ");
258 
259  if (r->ce_mask & ROUTE_ATTR_IIF)
260  dp_dump(p, "iif %s ", r->rt_iif);
261 
262  if (r->ce_mask & ROUTE_ATTR_SRC)
263  dp_dump(p, "src %s ",
264  nl_addr2str(r->rt_src, buf, sizeof(buf)));
265 
266  if (r->ce_mask & ROUTE_ATTR_TOS)
267  dp_dump(p, "tos %#x ", r->rt_tos);
268 
269  if (r->ce_mask & ROUTE_ATTR_REALMS)
270  dp_dump(p, "realm %04x:%04x ",
271  RTNL_REALM_FROM(r->rt_realms),
272  RTNL_REALM_TO(r->rt_realms));
273 
274  if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
275  r->rt_cacheinfo.rtci_error)
276  dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error,
277  strerror(-r->rt_cacheinfo.rtci_error));
278 
279  dp_dump(p, "\n");
280  }
281 
282  if (r->ce_mask & ROUTE_ATTR_METRICS) {
283  dp_dump_line(p, line++, " ");
284  for (i = 0; i < RTAX_MAX; i++)
285  if (r->rt_metrics_mask & (1 << i))
286  dp_dump(p, "%s %u ",
287  rtnl_route_metric2str(i+1,
288  buf, sizeof(buf)),
289  r->rt_metrics[i]);
290  dp_dump(p, "\n");
291  }
292 
293  return line;
294 }
295 
296 static int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
297 {
298  struct rtnl_route *route = (struct rtnl_route *) obj;
299  int line;
300 
301  line = route_dump_full(obj, p);
302 
303  if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
304  struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
305  dp_dump_line(p, line++, " used %u refcnt %u ",
306  ci->rtci_used, ci->rtci_clntref);
307  dp_dump_line(p, line++, "last-use %us expires %us\n",
308  ci->rtci_last_use / nl_get_hz(),
309  ci->rtci_expires / nl_get_hz());
310  }
311 
312  return line;
313 }
314 
315 static int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
316 {
317  struct rtnl_route *route = (struct rtnl_route *) obj;
318  char buf[128];
319  int line = 0;
320 
321  dp_dump_line(p, line++, "<route>\n");
322  dp_dump_line(p, line++, " <family>%s</family>\n",
323  nl_af2str(route->rt_family, buf, sizeof(buf)));
324 
325  if (route->ce_mask & ROUTE_ATTR_DST)
326  dp_dump_line(p, line++, " <dst>%s</dst>\n",
327  nl_addr2str(route->rt_dst, buf, sizeof(buf)));
328 
329  if (route->ce_mask & ROUTE_ATTR_SRC)
330  dp_dump_line(p, line++, " <src>%s</src>\n",
331  nl_addr2str(route->rt_src, buf, sizeof(buf)));
332 
333  if (route->ce_mask & ROUTE_ATTR_GATEWAY)
334  dp_dump_line(p, line++, " <gateway>%s</gateway>\n",
335  nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
336 
337  if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
338  dp_dump_line(p, line++, " <prefsrc>%s</prefsrc>\n",
339  nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
340 
341  if (route->ce_mask & ROUTE_ATTR_IIF)
342  dp_dump_line(p, line++, " <iif>%s</iif>\n", route->rt_iif);
343 
344  if (route->ce_mask & ROUTE_ATTR_REALMS)
345  dp_dump_line(p, line++, " <realms>%u</realms>\n",
346  route->rt_realms);
347 
348  if (route->ce_mask & ROUTE_ATTR_TOS)
349  dp_dump_line(p, line++, " <tos>%u</tos>\n", route->rt_tos);
350 
351  if (route->ce_mask & ROUTE_ATTR_TABLE)
352  dp_dump_line(p, line++, " <table>%u</table>\n",
353  route->rt_table);
354 
355  if (route->ce_mask & ROUTE_ATTR_SCOPE)
356  dp_dump_line(p, line++, " <scope>%s</scope>\n",
357  rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
358 
359  if (route->ce_mask & ROUTE_ATTR_PRIO)
360  dp_dump_line(p, line++, " <metric>%u</metric>\n",
361  route->rt_prio);
362 
363  if (route->ce_mask & ROUTE_ATTR_OIF) {
364  struct nl_cache *link_cache;
365 
366  link_cache = nl_cache_mngt_require("route/link");
367  if (link_cache)
368  dp_dump_line(p, line++, " <oif>%s</oif>\n",
369  rtnl_link_i2name(link_cache,
370  route->rt_oif,
371  buf, sizeof(buf)));
372  else
373  dp_dump_line(p, line++, " <oif>%u</oif>\n",
374  route->rt_oif);
375  }
376 
377  if (route->ce_mask & ROUTE_ATTR_TYPE)
378  dp_dump_line(p, line++, " <type>%s</type>\n",
379  nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
380 
381  dp_dump_line(p, line++, "</route>\n");
382 
383 #if 0
384  uint8_t rt_protocol;
385  uint32_t rt_flags;
386  uint32_t rt_metrics[RTAX_MAX];
387  uint32_t rt_metrics_mask;
388  struct rtnl_nexthop * rt_nexthops;
389  struct rtnl_rtcacheinfo rt_cacheinfo;
390  uint32_t rt_mp_algo;
391 
392 #endif
393 
394  return line;
395 }
396 
397 static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
398 {
399  struct rtnl_route *route = (struct rtnl_route *) obj;
400  char buf[128];
401  int line = 0;
402 
403  dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n",
404  nl_af2str(route->rt_family, buf, sizeof(buf)));
405 
406  if (route->ce_mask & ROUTE_ATTR_DST)
407  dp_dump_line(p, line++, "ROUTE_DST=%s\n",
408  nl_addr2str(route->rt_dst, buf, sizeof(buf)));
409 
410  if (route->ce_mask & ROUTE_ATTR_SRC)
411  dp_dump_line(p, line++, "ROUTE_SRC=%s\n",
412  nl_addr2str(route->rt_src, buf, sizeof(buf)));
413 
414  if (route->ce_mask & ROUTE_ATTR_GATEWAY)
415  dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n",
416  nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
417 
418  if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
419  dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n",
420  nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
421 
422  if (route->ce_mask & ROUTE_ATTR_IIF)
423  dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif);
424 
425  if (route->ce_mask & ROUTE_ATTR_REALMS)
426  dp_dump_line(p, line++, "ROUTE_REALM=%u\n",
427  route->rt_realms);
428 
429  if (route->ce_mask & ROUTE_ATTR_TOS)
430  dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos);
431 
432  if (route->ce_mask & ROUTE_ATTR_TABLE)
433  dp_dump_line(p, line++, "ROUTE_TABLE=%u\n",
434  route->rt_table);
435 
436  if (route->ce_mask & ROUTE_ATTR_SCOPE)
437  dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n",
438  rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
439 
440  if (route->ce_mask & ROUTE_ATTR_PRIO)
441  dp_dump_line(p, line++, "ROUTE_METRIC=%u\n",
442  route->rt_prio);
443 
444  if (route->ce_mask & ROUTE_ATTR_OIF) {
445  struct nl_cache *link_cache;
446 
447  dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n",
448  route->rt_oif);
449 
450  link_cache = nl_cache_mngt_require("route/link");
451  if (link_cache)
452  dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n",
453  rtnl_link_i2name(link_cache,
454  route->rt_oif,
455  buf, sizeof(buf)));
456  }
457 
458  if (route->ce_mask & ROUTE_ATTR_TYPE)
459  dp_dump_line(p, line++, "ROUTE_TYPE=%s\n",
460  nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
461 
462  return line;
463 }
464 
465 static int route_compare(struct nl_object *_a, struct nl_object *_b,
466  uint32_t attrs, int flags)
467 {
468  struct rtnl_route *a = (struct rtnl_route *) _a;
469  struct rtnl_route *b = (struct rtnl_route *) _b;
470  int diff = 0;
471 
472 #define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
473 
474  diff |= ROUTE_DIFF(FAMILY, a->rt_family != b->rt_family);
475  diff |= ROUTE_DIFF(TOS, a->rt_tos != b->rt_tos);
476  diff |= ROUTE_DIFF(TABLE, a->rt_table != b->rt_table);
477  diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol);
478  diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope);
479  diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type);
480  diff |= ROUTE_DIFF(OIF, a->rt_oif != b->rt_oif);
481  diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio);
482  diff |= ROUTE_DIFF(REALMS, a->rt_realms != b->rt_realms);
483  diff |= ROUTE_DIFF(MP_ALGO, a->rt_mp_algo != b->rt_mp_algo);
484  diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst));
485  diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src));
486  diff |= ROUTE_DIFF(IIF, strcmp(a->rt_iif, b->rt_iif));
487  diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src,
488  b->rt_pref_src));
489  diff |= ROUTE_DIFF(GATEWAY, nl_addr_cmp(a->rt_gateway,
490  b->rt_gateway));
491 
492  /* FIXME: Compare metrics, multipath config */
493 
494  if (flags & LOOSE_FLAG_COMPARISON)
495  diff |= ROUTE_DIFF(FLAGS,
496  (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
497  else
498  diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
499 
500 #undef ROUTE_DIFF
501 
502  return diff;
503 }
504 
505 static struct trans_tbl route_attrs[] = {
506  __ADD(ROUTE_ATTR_FAMILY, family)
507  __ADD(ROUTE_ATTR_TOS, tos)
508  __ADD(ROUTE_ATTR_TABLE, table)
509  __ADD(ROUTE_ATTR_PROTOCOL, protocol)
510  __ADD(ROUTE_ATTR_SCOPE, scope)
511  __ADD(ROUTE_ATTR_TYPE, type)
512  __ADD(ROUTE_ATTR_FLAGS, flags)
513  __ADD(ROUTE_ATTR_DST, dst)
514  __ADD(ROUTE_ATTR_SRC, src)
515  __ADD(ROUTE_ATTR_IIF, iif)
516  __ADD(ROUTE_ATTR_OIF, oif)
517  __ADD(ROUTE_ATTR_GATEWAY, gateway)
518  __ADD(ROUTE_ATTR_PRIO, prio)
519  __ADD(ROUTE_ATTR_PREF_SRC, pref_src)
520  __ADD(ROUTE_ATTR_METRICS, metrics)
521  __ADD(ROUTE_ATTR_MULTIPATH, multipath)
522  __ADD(ROUTE_ATTR_REALMS, realms)
523  __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
524  __ADD(ROUTE_ATTR_MP_ALGO, mp_algo)
525 };
526 
527 static char *route_attrs2str(int attrs, char *buf, size_t len)
528 {
529  return __flags2str(attrs, buf, len, route_attrs,
530  ARRAY_SIZE(route_attrs));
531 }
532 
533 /**
534  * @name Allocation/Freeing
535  * @{
536  */
537 
538 struct rtnl_route *rtnl_route_alloc(void)
539 {
540  return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
541 }
542 
543 void rtnl_route_get(struct rtnl_route *route)
544 {
545  nl_object_get((struct nl_object *) route);
546 }
547 
548 void rtnl_route_put(struct rtnl_route *route)
549 {
550  nl_object_put((struct nl_object *) route);
551 }
552 
553 /** @} */
554 
555 /**
556  * @name Attributes
557  * @{
558  */
559 
560 void rtnl_route_set_table(struct rtnl_route *route, int table)
561 {
562  route->rt_table = table;
563  route->ce_mask |= ROUTE_ATTR_TABLE;
564 }
565 
566 int rtnl_route_get_table(struct rtnl_route *route)
567 {
568  if (route->ce_mask & ROUTE_ATTR_TABLE)
569  return route->rt_table;
570  else
571  return RT_TABLE_MAIN;
572 }
573 
574 void rtnl_route_set_scope(struct rtnl_route *route, int scope)
575 {
576  route->rt_scope = scope;
577  route->ce_mask |= ROUTE_ATTR_SCOPE;
578 }
579 
580 int rtnl_route_get_scope(struct rtnl_route *route)
581 {
582  if (route->ce_mask & ROUTE_ATTR_SCOPE)
583  return route->rt_scope;
584  else
585  return RT_SCOPE_NOWHERE;
586 }
587 
588 void rtnl_route_set_tos(struct rtnl_route *route, int tos)
589 {
590  route->rt_tos = tos;
591  route->ce_mask |= ROUTE_ATTR_TOS;
592 }
593 
594 int rtnl_route_get_tos(struct rtnl_route *route)
595 {
596  return route->rt_tos;
597 }
598 
599 void rtnl_route_set_realms(struct rtnl_route *route, realm_t realms)
600 {
601  route->rt_realms = realms;
602  route->ce_mask |= ROUTE_ATTR_REALMS;
603 }
604 
605 realm_t rtnl_route_get_realms(struct rtnl_route *route)
606 {
607  return route->rt_realms;
608 }
609 
610 void rtnl_route_set_protocol(struct rtnl_route *route, int proto)
611 {
612  route->rt_protocol = proto;
613  route->ce_mask |= ROUTE_ATTR_PROTOCOL;
614 }
615 
616 int rtnl_route_get_protocol(struct rtnl_route *route)
617 {
618  if (route->ce_mask & ROUTE_ATTR_PROTOCOL)
619  return route->rt_protocol;
620  else
621  return RTPROT_STATIC;
622 }
623 
624 void rtnl_route_set_prio(struct rtnl_route *route, int prio)
625 {
626  route->rt_prio = prio;
627  route->ce_mask |= ROUTE_ATTR_PRIO;
628 }
629 
630 int rtnl_route_get_prio(struct rtnl_route *route)
631 {
632  return route->rt_prio;
633 }
634 
635 void rtnl_route_set_family(struct rtnl_route *route, int family)
636 {
637  route->rt_family = family;
638  route->ce_mask |= ROUTE_ATTR_FAMILY;
639 }
640 
641 int rtnl_route_get_family(struct rtnl_route *route)
642 {
643  if (route->ce_mask & ROUTE_ATTR_FAMILY)
644  return route->rt_family;
645  else
646  return AF_UNSPEC;
647 }
648 
649 int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
650 {
651  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
652  if (addr->a_family != route->rt_family)
653  return nl_error(EINVAL, "Address family mismatch");
654  } else
655  route->rt_family = addr->a_family;
656 
657  if (route->rt_dst)
658  nl_addr_put(route->rt_dst);
659 
660  nl_addr_get(addr);
661  route->rt_dst = addr;
662 
663  route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
664 
665  return 0;
666 }
667 
668 struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
669 {
670  return route->rt_dst;
671 }
672 
673 int rtnl_route_get_dst_len(struct rtnl_route *route)
674 {
675  if (route->ce_mask & ROUTE_ATTR_DST)
676  return nl_addr_get_prefixlen(route->rt_dst);
677  else
678  return 0;
679 }
680 
681 int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
682 {
683  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
684  if (addr->a_family != route->rt_family)
685  return nl_error(EINVAL, "Address family mismatch");
686  } else
687  route->rt_family = addr->a_family;
688 
689  if (route->rt_src)
690  nl_addr_put(route->rt_src);
691 
692  nl_addr_get(addr);
693  route->rt_src = addr;
694  route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
695 
696  return 0;
697 }
698 
699 struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
700 {
701  return route->rt_src;
702 }
703 
704 int rtnl_route_get_src_len(struct rtnl_route *route)
705 {
706  if (route->ce_mask & ROUTE_ATTR_SRC)
707  return nl_addr_get_prefixlen(route->rt_src);
708  else
709  return 0;
710 }
711 
712 int rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr)
713 {
714  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
715  if (addr->a_family != route->rt_family)
716  return nl_error(EINVAL, "Address family mismatch");
717  } else
718  route->rt_family = addr->a_family;
719 
720  if (route->rt_gateway)
721  nl_addr_put(route->rt_gateway);
722 
723  nl_addr_get(addr);
724  route->rt_gateway = addr;
725  route->ce_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY);
726 
727  return 0;
728 }
729 
730 struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route)
731 {
732  return route->rt_gateway;
733 }
734 
735 void rtnl_route_set_type(struct rtnl_route *route, int type)
736 {
737  route->rt_type = type;
738  route->ce_mask |= ROUTE_ATTR_TYPE;
739 }
740 
741 int rtnl_route_get_type(struct rtnl_route *route)
742 {
743  if (route->ce_mask & ROUTE_ATTR_TYPE)
744  return route->rt_type;
745  else
746  return RTN_UNICAST;
747 }
748 
749 void rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags)
750 {
751  route->rt_flag_mask |= flags;
752  route->rt_flags |= flags;
753  route->ce_mask |= ROUTE_ATTR_FLAGS;
754 }
755 
756 void rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags)
757 {
758  route->rt_flag_mask |= flags;
759  route->rt_flags &= ~flags;
760  route->ce_mask |= ROUTE_ATTR_FLAGS;
761 }
762 
763 unsigned int rtnl_route_get_flags(struct rtnl_route *route)
764 {
765  return route->rt_flags;
766 }
767 
768 int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
769 {
770  if (metric > RTAX_MAX || metric < 1)
771  return nl_error(EINVAL, "Metric out of range (1..%d)",
772  RTAX_MAX);
773 
774  route->rt_metrics[metric - 1] = value;
775  route->rt_metrics_mask |= (1 << (metric - 1));
776 
777  return 0;
778 }
779 
780 int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
781 {
782  if (metric > RTAX_MAX || metric < 1)
783  return nl_error(EINVAL, "Metric out of range (1..%d)",
784  RTAX_MAX);
785 
786  route->rt_metrics_mask &= ~(1 << (metric - 1));
787 
788  return 0;
789 }
790 
791 unsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric)
792 {
793  if (metric > RTAX_MAX || metric < 1)
794  return UINT_MAX;
795 
796  if (!(route->rt_metrics_mask & (1 << (metric - 1))))
797  return UINT_MAX;
798 
799  return route->rt_metrics[metric - 1];
800 }
801 
802 int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
803 {
804  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
805  if (addr->a_family != route->rt_family)
806  return nl_error(EINVAL, "Address family mismatch");
807  } else
808  route->rt_family = addr->a_family;
809 
810  if (route->rt_pref_src)
811  nl_addr_put(route->rt_pref_src);
812 
813  nl_addr_get(addr);
814  route->rt_pref_src = addr;
815  route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
816 
817  return 0;
818 }
819 
820 struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
821 {
822  return route->rt_pref_src;
823 }
824 
825 void rtnl_route_set_oif(struct rtnl_route *route, int ifindex)
826 {
827  route->rt_oif = ifindex;
828  route->ce_mask |= ROUTE_ATTR_OIF;
829 }
830 
831 int rtnl_route_get_oif(struct rtnl_route *route)
832 {
833  if (route->ce_mask & ROUTE_ATTR_OIF)
834  return route->rt_oif;
835  else
836  return RTNL_LINK_NOT_FOUND;
837 }
838 
839 void rtnl_route_set_iif(struct rtnl_route *route, const char *name)
840 {
841  strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1);
842  route->ce_mask |= ROUTE_ATTR_IIF;
843 }
844 
845 char *rtnl_route_get_iif(struct rtnl_route *route)
846 {
847  if (route->ce_mask & ROUTE_ATTR_IIF)
848  return route->rt_iif;
849  else
850  return NULL;
851 }
852 
853 void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
854 {
855  nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
856  route->ce_mask |= ROUTE_ATTR_MULTIPATH;
857 }
858 
859 void rtnl_route_remove_nexthop(struct rtnl_nexthop *nh)
860 {
861  nl_list_del(&nh->rtnh_list);
862 }
863 
864 struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
865 {
866  return &route->rt_nexthops;
867 }
868 
869 void rtnl_route_set_cacheinfo(struct rtnl_route *route,
870  struct rtnl_rtcacheinfo *ci)
871 {
872  memcpy(&route->rt_cacheinfo, ci, sizeof(*ci));
873  route->ce_mask |= ROUTE_ATTR_CACHEINFO;
874 }
875 
876 uint32_t rtnl_route_get_mp_algo(struct rtnl_route *route)
877 {
878  if (route->ce_mask & ROUTE_ATTR_MP_ALGO)
879  return route->rt_mp_algo;
880  else
881  return IP_MP_ALG_NONE;
882 }
883 
884 void rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo)
885 {
886  route->rt_mp_algo = algo;
887  route->ce_mask |= ROUTE_ATTR_MP_ALGO;
888 }
889 
890 /** @} */
891 
892 struct nl_object_ops route_obj_ops = {
893  .oo_name = "route/route",
894  .oo_size = sizeof(struct rtnl_route),
895  .oo_constructor = route_constructor,
896  .oo_free_data = route_free_data,
897  .oo_clone = route_clone,
898  .oo_dump[NL_DUMP_BRIEF] = route_dump_brief,
899  .oo_dump[NL_DUMP_FULL] = route_dump_full,
900  .oo_dump[NL_DUMP_STATS] = route_dump_stats,
901  .oo_dump[NL_DUMP_XML] = route_dump_xml,
902  .oo_dump[NL_DUMP_ENV] = route_dump_env,
903  .oo_compare = route_compare,
904  .oo_attrs2str = route_attrs2str,
905  .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
906  ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
907 };
908 
909 /** @} */