Initial import package libnl: Convenience library for kernel netlink sockets
[external/libnl.git] / lib / route / 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 /** @} */