This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.git] / lib / route / route.c
1 /*
2  * lib/route/route.c    Routes
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 rtnl
14  * @defgroup route Routing
15  * @brief
16  * @{
17  */
18
19 #include <netlink-local.h>
20 #include <netlink/netlink.h>
21 #include <netlink/cache.h>
22 #include <netlink/utils.h>
23 #include <netlink/data.h>
24 #include <netlink/route/rtnl.h>
25 #include <netlink/route/route.h>
26 #include <netlink/route/link.h>
27
28 /** @cond SKIP */
29 #define ROUTE_ATTR_FAMILY    0x000001
30 #define ROUTE_ATTR_DST_LEN   0x000002
31 #define ROUTE_ATTR_SRC_LEN   0x000004
32 #define ROUTE_ATTR_TOS       0x000008
33 #define ROUTE_ATTR_TABLE     0x000010
34 #define ROUTE_ATTR_PROTOCOL  0x000020
35 #define ROUTE_ATTR_SCOPE     0x000040
36 #define ROUTE_ATTR_TYPE      0x000080
37 #define ROUTE_ATTR_FLAGS     0x000100
38 #define ROUTE_ATTR_DST       0x000200
39 #define ROUTE_ATTR_SRC       0x000400
40 #define ROUTE_ATTR_IIF       0x000800
41 #define ROUTE_ATTR_OIF       0x001000
42 #define ROUTE_ATTR_GATEWAY   0x002000
43 #define ROUTE_ATTR_PRIO      0x004000
44 #define ROUTE_ATTR_PREF_SRC  0x008000
45 #define ROUTE_ATTR_METRICS   0x010000
46 #define ROUTE_ATTR_MULTIPATH 0x020000
47 #define ROUTE_ATTR_REALMS    0x040000
48 #define ROUTE_ATTR_CACHEINFO 0x080000
49 #define ROUTE_ATTR_MP_ALGO   0x100000
50
51 #define NEXTHOP_HAS_FLAGS   0x000001
52 #define NEXTHOP_HAS_WEIGHT  0x000002
53 #define NEXTHOP_HAS_IFINDEX 0x000004
54 #define NEXTHOP_HAS_GATEWAY 0x000008
55
56 static struct nl_cache_ops rtnl_route_ops;
57 /** @endcond */
58
59 static void route_constructor(struct nl_object *c)
60 {
61         struct rtnl_route *r = (struct rtnl_route *) c;
62
63         nl_init_list_head(&r->rt_nexthops);
64 }
65
66 static void route_free_data(struct nl_object *c)
67 {
68         struct rtnl_route *r = (struct rtnl_route *) c;
69         struct rtnl_nexthop *nh, *tmp;
70
71         if (r == NULL)
72                 return;
73
74         nl_addr_put(r->rt_dst);
75         nl_addr_put(r->rt_src);
76         nl_addr_put(r->rt_gateway);
77         nl_addr_put(r->rt_pref_src);
78
79         nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
80                 rtnl_route_remove_nexthop(nh);
81                 rtnl_route_nh_free(nh);
82         }
83 }
84
85 static struct nla_policy route_policy[RTA_MAX+1] = {
86         [RTA_IIF]       = { .type = NLA_STRING,
87                             .maxlen = IFNAMSIZ, },
88         [RTA_OIF]       = { .type = NLA_U32 },
89         [RTA_PRIORITY]  = { .type = NLA_U32 },
90         [RTA_FLOW]      = { .type = NLA_U32 },
91         [RTA_MP_ALGO]   = { .type = NLA_U32 },
92         [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
93         [RTA_METRICS]   = { .type = NLA_NESTED },
94         [RTA_MULTIPATH] = { .type = NLA_NESTED },
95 };
96
97 static void copy_rtmsg_into_route(struct rtmsg *rtmsg, struct rtnl_route *route)
98 {
99         route->rt_family        = rtmsg->rtm_family;
100         route->rt_dst_len       = rtmsg->rtm_dst_len;
101         route->rt_src_len       = rtmsg->rtm_src_len;
102         route->rt_tos           = rtmsg->rtm_tos;
103         route->rt_table         = rtmsg->rtm_table;
104         route->rt_type          = rtmsg->rtm_type;
105         route->rt_scope         = rtmsg->rtm_scope;
106         route->rt_protocol      = rtmsg->rtm_protocol;
107         route->rt_flags         = rtmsg->rtm_flags;
108
109         route->rt_mask = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_DST_LEN | 
110                           ROUTE_ATTR_SRC_LEN | ROUTE_ATTR_TABLE |
111                           ROUTE_ATTR_PROTOCOL| ROUTE_ATTR_SCOPE |
112                           ROUTE_ATTR_TYPE | ROUTE_ATTR_FLAGS);
113
114         if (route->rt_tos)
115                 route->rt_mask |= ROUTE_ATTR_TOS;
116 }
117
118 static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci,
119                                       struct rtnl_route *route)
120 {
121         route->rt_cacheinfo.rtci_clntref  = ci->rta_clntref;
122         route->rt_cacheinfo.rtci_last_use = ci->rta_lastuse;
123         route->rt_cacheinfo.rtci_expires  = ci->rta_expires;
124         route->rt_cacheinfo.rtci_error    = ci->rta_error;
125         route->rt_cacheinfo.rtci_used     = ci->rta_used;
126         route->rt_cacheinfo.rtci_id       = ci->rta_id;
127         route->rt_cacheinfo.rtci_ts       = ci->rta_ts;
128         route->rt_cacheinfo.rtci_tsage    = ci->rta_tsage;
129
130         route->rt_mask |= ROUTE_ATTR_CACHEINFO;
131 }
132
133 static int route_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
134                             void *arg)
135 {
136         struct nl_parser_param *pp = arg;
137         struct rtnl_route *route;
138         struct nlattr *tb[RTA_MAX + 1];
139         int err;
140
141         route = rtnl_route_alloc();
142         if (!route) {
143                 err = nl_errno(ENOMEM);
144                 goto errout;
145         }
146
147         route->ce_msgtype = nlh->nlmsg_type;
148
149         err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
150                           route_policy);
151         if (err < 0)
152                 goto errout;
153
154         copy_rtmsg_into_route((struct rtmsg *) nlmsg_data(nlh), route);
155
156         if (tb[RTA_DST]) {
157                 route->rt_dst = nla_get_addr(tb[RTA_DST], route->rt_family);
158                 if (!route->rt_dst)
159                         goto errout_errno;
160                 nl_addr_set_prefixlen(route->rt_dst, route->rt_dst_len);
161                 route->rt_mask |= ROUTE_ATTR_DST;
162         }
163
164         if (tb[RTA_SRC]) {
165                 route->rt_src = nla_get_addr(tb[RTA_SRC], route->rt_family);
166                 if (!route->rt_src)
167                         goto errout_errno;
168                 nl_addr_set_prefixlen(route->rt_src, route->rt_src_len);
169                 route->rt_mask |= ROUTE_ATTR_SRC;
170         }
171
172         if (tb[RTA_IIF]) {
173                 nla_strlcpy(route->rt_iif, tb[RTA_IIF], IFNAMSIZ);
174                 route->rt_mask |= ROUTE_ATTR_IIF;
175         }
176
177         if (tb[RTA_OIF]) {
178                 route->rt_oif = nla_get_u32(tb[RTA_OIF]);
179                 route->rt_mask |= ROUTE_ATTR_OIF;
180         }
181
182         if (tb[RTA_GATEWAY]) {
183                 route->rt_gateway = nla_get_addr(tb[RTA_GATEWAY],
184                                                  route->rt_family);
185                 if (!route->rt_gateway)
186                         goto errout_errno;
187                 route->rt_mask |= ROUTE_ATTR_GATEWAY;
188         }
189
190         if (tb[RTA_PRIORITY]) {
191                 route->rt_prio = nla_get_u32(tb[RTA_PRIORITY]);
192                 route->rt_mask |= ROUTE_ATTR_PRIO;
193         }
194
195         if (tb[RTA_PREFSRC]) {
196                 route->rt_pref_src = nla_get_addr(tb[RTA_PREFSRC],
197                                                   route->rt_family);
198                 if (!route->rt_pref_src)
199                         goto errout_errno;
200                 route->rt_mask |= ROUTE_ATTR_PREF_SRC;
201         }
202
203         if (tb[RTA_METRICS]) {
204                 struct nlattr *mtb[RTAX_MAX + 1];
205                 int i;
206
207                 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
208                 if (err < 0)
209                         goto errout;
210
211                 for (i = 1; i <= RTAX_MAX; i++) {
212                         if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
213                                 uint32_t m = nla_get_u32(mtb[i]);
214                                 route->rt_metrics[i-1] = m;
215                                 route->rt_metrics_mask |= (1 << (i - 1));
216                         }
217                 }
218                 
219                 route->rt_mask |= ROUTE_ATTR_METRICS;
220         }
221
222         if (tb[RTA_MULTIPATH]) {
223                 struct rtnl_nexthop *nh;
224                 struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]);
225                 size_t tlen = nla_len(tb[RTA_MULTIPATH]);
226
227                 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
228                         nh = rtnl_route_nh_alloc();
229                         if (!nh)
230                                 goto errout;
231
232                         rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
233                         rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
234                         rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
235
236                         if (rtnh->rtnh_len > sizeof(*rtnh)) {
237                                 struct nlattr *ntb[RTA_MAX + 1];
238                                 nla_parse(ntb, RTA_MAX, (struct nlattr *)
239                                           RTNH_DATA(rtnh),
240                                           rtnh->rtnh_len - sizeof(*rtnh),
241                                           route_policy);
242
243                                 if (ntb[RTA_GATEWAY]) {
244                                         nh->rtnh_gateway = nla_get_addr(
245                                                         ntb[RTA_GATEWAY],
246                                                         route->rt_family);
247                                         nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
248                                 }
249                         }
250
251                         rtnl_route_add_nexthop(route, nh);
252                         tlen -= RTNH_ALIGN(rtnh->rtnh_len);
253                         rtnh = RTNH_NEXT(rtnh);
254                 }
255         }
256
257         if (tb[RTA_FLOW]) {
258                 route->rt_realms = nla_get_u32(tb[RTA_FLOW]);
259                 route->rt_mask |= ROUTE_ATTR_REALMS;
260         }
261
262         if (tb[RTA_CACHEINFO])
263                 copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route);
264
265         if (tb[RTA_MP_ALGO]) {
266                 route->rt_mp_algo = nla_get_u32(tb[RTA_MP_ALGO]);
267                 route->rt_mask |= ROUTE_ATTR_MP_ALGO;
268         }
269
270         err = pp->pp_cb((struct nl_object *) route, pp);
271         if (err < 0)
272                 goto errout;
273
274         return P_ACCEPT;
275
276 errout_errno:
277         err = nl_get_errno();
278 errout:
279         rtnl_route_put(route);
280         return err;
281
282 }
283
284 static int route_request_update(struct nl_cache *c, struct nl_handle *h)
285 {
286         return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP);
287 }
288
289 static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p)
290 {
291         struct rtnl_route *r = (struct rtnl_route *) a;
292         struct nl_cache *link_cache;
293         char buf[64];
294
295         link_cache = nl_cache_mngt_require("route/link");
296
297         if (r->rt_mask & ROUTE_ATTR_DST)
298                 dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
299         else if (r->rt_dst_len)
300                 dp_dump(p, "0/%u ", r->rt_dst_len);
301         else
302                 dp_dump(p, "default ");
303
304         if (r->rt_mask & ROUTE_ATTR_OIF) {
305                 if (link_cache)
306                         dp_dump(p, "dev %s ",
307                                 rtnl_link_i2name(link_cache, r->rt_oif,
308                                                  buf, sizeof(buf)));
309                 else
310                         dp_dump(p, "dev %d ", r->rt_oif);
311         }
312
313         if (r->rt_mask & ROUTE_ATTR_GATEWAY)
314                 dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf,
315                                                   sizeof(buf)));
316         else if (r->rt_mask & ROUTE_ATTR_MULTIPATH)
317                 dp_dump(p, "via nexthops ");
318
319         if (r->rt_mask & ROUTE_ATTR_TABLE)
320                 dp_dump(p, "table %s ",
321                         rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
322
323         if (r->rt_mask & ROUTE_ATTR_SCOPE)
324                 dp_dump(p, "scope %s ",
325                         rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
326
327         if (r->rt_mask & ROUTE_ATTR_FLAGS && r->rt_flags) {
328                 int flags = r->rt_flags;
329
330                 dp_dump(p, "<");
331                 
332 #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
333                 flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
334                 PRINT_FLAG(DEAD);
335                 PRINT_FLAG(ONLINK);
336                 PRINT_FLAG(PERVASIVE);
337 #undef PRINT_FLAG
338
339 #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
340                 flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
341                 PRINT_FLAG(NOTIFY);
342                 PRINT_FLAG(CLONED);
343                 PRINT_FLAG(EQUALIZE);
344                 PRINT_FLAG(PREFIX);
345 #undef PRINT_FLAG
346
347                 dp_dump(p, ">");
348         }
349
350         dp_dump(p, "\n");
351
352         return 1;
353 }
354
355 static int route_dump_full(struct nl_object *a, struct nl_dump_params *p)
356 {
357         struct rtnl_route *r = (struct rtnl_route *) a;
358         struct nl_cache *link_cache;
359         char buf[128];
360         int i, line;
361
362         link_cache = nl_cache_mngt_require("route/link");
363         line = route_dump_brief(a, p);
364
365         if (r->rt_mask & ROUTE_ATTR_MULTIPATH) {
366                 struct rtnl_nexthop *nh;
367
368                 dp_dump_line(p, line++, "  ");
369
370                 nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
371                         dp_dump(p, "nh ");
372
373                         if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
374                                 dp_dump(p, "via %s ",
375                                         nl_addr2str(nh->rtnh_gateway,
376                                                     buf, sizeof(buf)));
377                         if (link_cache)
378                                 dp_dump(p, "dev %s ",
379                                         rtnl_link_i2name(link_cache,
380                                                          nh->rtnh_ifindex,
381                                                          buf, sizeof(buf)));
382                         else
383                                 dp_dump(p, "dev %d ", nh->rtnh_ifindex);
384
385                         dp_dump(p, "weight %u <%s> ", nh->rtnh_weight,
386                                 rtnl_route_nh_flags2str(nh->rtnh_flags,
387                                                         buf, sizeof(buf)));
388                 }
389
390                 dp_dump(p, "\n");
391         }
392
393         dp_dump_line(p, line++, "  ");
394
395         if (r->rt_mask & ROUTE_ATTR_PREF_SRC)
396                 dp_dump(p, "preferred-src %s ",
397                         nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
398
399         if (r->rt_mask & ROUTE_ATTR_TYPE)
400                 dp_dump(p, "type %s ",
401                         nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
402
403         if (r->rt_mask & ROUTE_ATTR_PRIO)
404                 dp_dump(p, "metric %#x ", r->rt_prio);
405
406         if (r->rt_mask & ROUTE_ATTR_FAMILY)
407                 dp_dump(p, "family %s ",
408                         nl_af2str(r->rt_family, buf, sizeof(buf)));
409
410         if (r->rt_mask & ROUTE_ATTR_PROTOCOL)
411                 dp_dump(p, "protocol %s ",
412                         rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
413
414         dp_dump(p, "\n");
415
416         if ((r->rt_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS |
417                            ROUTE_ATTR_REALMS)) || r->rt_src_len ||
418             ((r->rt_mask & ROUTE_ATTR_CACHEINFO) &&
419              r->rt_cacheinfo.rtci_error)) {
420                 dp_dump_line(p, line++, "  ");
421
422                 if (r->rt_mask & ROUTE_ATTR_IIF)
423                         dp_dump(p, "iif %s ", r->rt_iif);
424
425                 if (r->rt_mask & ROUTE_ATTR_SRC)
426                         dp_dump(p, "src %s ",
427                                 nl_addr2str(r->rt_src, buf, sizeof(buf)));
428                 else if (r->rt_src_len)
429                         dp_dump(p, "src 0/%u ", r->rt_src_len);
430
431                 if (r->rt_mask & ROUTE_ATTR_TOS)
432                         dp_dump(p, "tos %#x ", r->rt_tos);
433
434                 if (r->rt_mask & ROUTE_ATTR_REALMS)
435                         dp_dump(p, "realm %04x:%04x ",
436                                 RTNL_REALM_FROM(r->rt_realms),
437                                 RTNL_REALM_TO(r->rt_realms));
438
439                 if ((r->rt_mask & ROUTE_ATTR_CACHEINFO) &&
440                     r->rt_cacheinfo.rtci_error)
441                         dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error,
442                                 strerror(-r->rt_cacheinfo.rtci_error));
443
444                 dp_dump(p, "\n");
445         }
446
447         if (r->rt_mask & ROUTE_ATTR_METRICS) {
448                 dp_dump_line(p, line++, "  ");
449                 for (i = 0; i < RTAX_MAX; i++)
450                         if (r->rt_metrics_mask & (1 << i))
451                                 dp_dump(p, "%s %u ",
452                                         rtnl_route_metric2str(i+1,
453                                                               buf, sizeof(buf)),
454                                         r->rt_metrics[i]);
455                 dp_dump(p, "\n");
456         }
457
458         return line;
459 }
460
461 static int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
462 {
463         struct rtnl_route *route = (struct rtnl_route *) obj;
464         int line;
465
466         line = route_dump_full(obj, p);
467
468         if (route->rt_mask & ROUTE_ATTR_CACHEINFO) {
469                 struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
470                 dp_dump_line(p, line++, "  used %u refcnt %u ",
471                              ci->rtci_used, ci->rtci_clntref);
472                 dp_dump_line(p, line++, "last-use %us expires %us\n",
473                              ci->rtci_last_use / nl_get_hz(),
474                              ci->rtci_expires / nl_get_hz());
475         }
476
477         return line;
478 }
479
480 static int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
481 {
482         struct rtnl_route *route = (struct rtnl_route *) obj;
483         char buf[128];
484         int line = 0;
485         
486         dp_dump_line(p, line++, "<route>\n");
487         dp_dump_line(p, line++, "  <family>%s</family>\n",
488                      nl_af2str(route->rt_family, buf, sizeof(buf)));
489
490         if (route->rt_mask & ROUTE_ATTR_DST)
491                 dp_dump_line(p, line++, "  <dst>%s</dst>\n",
492                              nl_addr2str(route->rt_dst, buf, sizeof(buf)));
493
494         if (route->rt_mask & ROUTE_ATTR_DST_LEN)
495                 dp_dump_line(p, line++, "  <dstlen>%u</dstlen>\n",
496                              route->rt_dst_len);
497
498         if (route->rt_mask & ROUTE_ATTR_SRC)
499                 dp_dump_line(p, line++, "  <src>%s</src>\n",
500                              nl_addr2str(route->rt_src, buf, sizeof(buf)));
501
502         if (route->rt_mask & ROUTE_ATTR_SRC_LEN)
503                 dp_dump_line(p, line++, "  <srclen>%u</srclen>\n",
504                              route->rt_src_len);
505
506         if (route->rt_mask & ROUTE_ATTR_GATEWAY)
507                 dp_dump_line(p, line++, "  <gateway>%s</gateway>\n",
508                              nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
509
510         if (route->rt_mask & ROUTE_ATTR_PREF_SRC)
511                 dp_dump_line(p, line++, "  <prefsrc>%s</prefsrc>\n",
512                              nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
513
514         if (route->rt_mask & ROUTE_ATTR_IIF)
515                 dp_dump_line(p, line++, "  <iif>%s</iif>\n", route->rt_iif);
516
517         if (route->rt_mask & ROUTE_ATTR_REALMS)
518                 dp_dump_line(p, line++, "  <realms>%u</realms>\n",
519                              route->rt_realms);
520
521         if (route->rt_mask & ROUTE_ATTR_TOS)
522                 dp_dump_line(p, line++, "  <tos>%u</tos>\n", route->rt_tos);
523
524         if (route->rt_mask & ROUTE_ATTR_TABLE)
525                 dp_dump_line(p, line++, "  <table>%u</table>\n",
526                              route->rt_table);
527
528         if (route->rt_mask & ROUTE_ATTR_SCOPE)
529                 dp_dump_line(p, line++, "  <scope>%s</scope>\n",
530                              rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
531
532         if (route->rt_mask & ROUTE_ATTR_PRIO)
533                 dp_dump_line(p, line++, "  <metric>%u</metric>\n",
534                              route->rt_prio);
535
536         if (route->rt_mask & ROUTE_ATTR_OIF) {
537                 struct nl_cache *link_cache;
538         
539                 link_cache = nl_cache_mngt_require("route/link");
540                 if (link_cache)
541                         dp_dump_line(p, line++, "  <oif>%s</oif>\n",
542                                      rtnl_link_i2name(link_cache,
543                                                       route->rt_oif,
544                                                       buf, sizeof(buf)));
545                 else
546                         dp_dump_line(p, line++, "  <oif>%u</oif>\n",
547                                      route->rt_oif);
548         }
549
550         if (route->rt_mask & ROUTE_ATTR_TYPE)
551                 dp_dump_line(p, line++, "  <type>%s</type>\n",
552                              nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
553
554         dp_dump_line(p, line++, "</route>\n");
555
556 #if 0
557         uint8_t                 rt_protocol;
558         uint32_t                rt_flags;
559         uint32_t                rt_metrics[RTAX_MAX];
560         uint32_t                rt_metrics_mask;
561         struct rtnl_nexthop *   rt_nexthops;
562         struct rtnl_rtcacheinfo rt_cacheinfo;
563         uint32_t                rt_mp_algo;
564
565 #endif
566
567         return line;
568 }
569
570 static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
571 {
572         struct rtnl_route *route = (struct rtnl_route *) obj;
573         char buf[128];
574         int line = 0;
575
576         dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n",
577                      nl_af2str(route->rt_family, buf, sizeof(buf)));
578
579         if (route->rt_mask & ROUTE_ATTR_DST)
580                 dp_dump_line(p, line++, "ROUTE_DST=%s\n",
581                              nl_addr2str(route->rt_dst, buf, sizeof(buf)));
582
583         if (route->rt_mask & ROUTE_ATTR_DST_LEN)
584                 dp_dump_line(p, line++, "ROUTE_DSTLEN=%u\n",
585                              route->rt_dst_len);
586
587         if (route->rt_mask & ROUTE_ATTR_SRC)
588                 dp_dump_line(p, line++, "ROUTE_SRC=%s\n",
589                              nl_addr2str(route->rt_src, buf, sizeof(buf)));
590
591         if (route->rt_mask & ROUTE_ATTR_SRC_LEN)
592                 dp_dump_line(p, line++, "ROUTE_SRCLEN=%u\n",
593                              route->rt_src_len);
594
595         if (route->rt_mask & ROUTE_ATTR_GATEWAY)
596                 dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n",
597                              nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
598
599         if (route->rt_mask & ROUTE_ATTR_PREF_SRC)
600                 dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n",
601                              nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
602
603         if (route->rt_mask & ROUTE_ATTR_IIF)
604                 dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif);
605
606         if (route->rt_mask & ROUTE_ATTR_REALMS)
607                 dp_dump_line(p, line++, "ROUTE_REALM=%u\n",
608                              route->rt_realms);
609
610         if (route->rt_mask & ROUTE_ATTR_TOS)
611                 dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos);
612
613         if (route->rt_mask & ROUTE_ATTR_TABLE)
614                 dp_dump_line(p, line++, "ROUTE_TABLE=%u\n",
615                              route->rt_table);
616
617         if (route->rt_mask & ROUTE_ATTR_SCOPE)
618                 dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n",
619                              rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
620
621         if (route->rt_mask & ROUTE_ATTR_PRIO)
622                 dp_dump_line(p, line++, "ROUTE_METRIC=%u\n",
623                              route->rt_prio);
624
625         if (route->rt_mask & ROUTE_ATTR_OIF) {
626                 struct nl_cache *link_cache;
627
628                 dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n",
629                              route->rt_oif);
630
631                 link_cache = nl_cache_mngt_require("route/link");
632                 if (link_cache)
633                         dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n",
634                                      rtnl_link_i2name(link_cache,
635                                                       route->rt_oif,
636                                                       buf, sizeof(buf)));
637         }
638
639         if (route->rt_mask & ROUTE_ATTR_TYPE)
640                 dp_dump_line(p, line++, "ROUTE_TYPE=%s\n",
641                              nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
642
643         return line;
644 }
645
646 static int route_filter(struct nl_object *obj, struct nl_object *filter)
647 {
648         struct rtnl_route *o = (struct rtnl_route *) obj;
649         struct rtnl_route *f = (struct rtnl_route *) filter;
650
651 #define REQ(F) (f->rt_mask & ROUTE_ATTR_##F)
652 #define AVAIL(F) (o->rt_mask & ROUTE_ATTR_##F)
653 #define _O(F, EXPR) (REQ(F) && (!AVAIL(F) || (EXPR)))
654 #define _C(F, N) (REQ(F) && (!AVAIL(F) || (o->N != f->N)))
655         if (_C(FAMILY,    rt_family)                                    ||
656             _C(DST_LEN,   rt_dst_len)                                   ||
657             _C(SRC_LEN,   rt_src_len)                                   ||
658             _C(TOS,       rt_tos)                                       ||
659             _C(TABLE,     rt_table)                                     ||
660             _C(PROTOCOL,  rt_protocol)                                  ||
661             _C(SCOPE,     rt_scope)                                     ||
662             _C(TYPE,      rt_type)                                      ||
663             _C(OIF,       rt_oif)                                       ||
664             _C(PRIO,      rt_prio)                                      ||
665             _C(REALMS,    rt_realms)                                    ||
666             _C(MP_ALGO,   rt_mp_algo)                                   ||
667             _O(DST,       nl_addr_cmp(o->rt_dst, f->rt_dst))            ||
668             _O(SRC,       nl_addr_cmp(o->rt_src, f->rt_src))            ||
669             _O(IIF,       strcmp(o->rt_iif, f->rt_iif))                 ||
670             _O(PREF_SRC,  nl_addr_cmp(o->rt_pref_src, f->rt_pref_src))  ||
671             _O(GATEWAY,   nl_addr_cmp(o->rt_gateway, f->rt_gateway))    ||
672             _O(FLAGS,     f->rt_flags ^ (o->rt_flags & f->rt_flag_mask)))
673                 return 0;
674
675         if (REQ(METRICS)) {
676                 int i;
677
678                 if (!AVAIL(METRICS))
679                         return 0;
680
681                 for (i = 0; i < RTAX_MAX; i++) {
682                         if (f->rt_metrics_mask & (1 << i)) {
683                                 if (!(o->rt_metrics_mask & (1 << i)) ||
684                                     f->rt_metrics[i+1] != o->rt_metrics[i+1])
685                                         return 0;
686                         }
687                 }
688         }
689
690         if (REQ(MULTIPATH)) {
691                 /* FIXME */
692         }
693         
694 #undef REQ
695 #undef AVAIL
696 #undef _O
697 #undef _C
698
699         return 1;
700
701 }
702
703 /**
704  * @name Route Object Allocation/Freeage
705  * @{
706  */
707
708 /**
709  * Allocate a new route object
710  * @return New route object
711  */
712 struct rtnl_route *rtnl_route_alloc(void)
713 {
714         return (struct rtnl_route *) nl_object_alloc_from_ops(&rtnl_route_ops);
715 }
716
717 /**
718  * Free route object.
719  * @arg route           Route object to be freed.
720  *
721  * @note Always use rtnl_route_put() unless you're absolutely sure
722  *       that no other user may have a reference on this object.
723  */
724 void rtnl_route_free(struct rtnl_route *route)
725 {
726         nl_object_free((struct nl_object *) route);
727 }
728
729 /** @} */
730
731 /**
732  * @name Route Object Reference Counting
733  * @{
734  */
735
736 void rtnl_route_get(struct rtnl_route *route)
737 {
738         nl_object_get((struct nl_object *) route);
739 }
740
741 void rtnl_route_put(struct rtnl_route *route)
742 {
743         nl_object_put((struct nl_object *) route);
744 }
745
746 /** @} */
747
748 /**
749  * @name Route Cache Management
750  * @{
751  */
752
753 /**
754  * Build a route cache holding all routes currently configured in the kernel
755  * @arg handle          netlink handle
756  *
757  * Allocates a new cache, initializes it properly and updates it to
758  * contain all routes currently configured in the kernel.
759  *
760  * @note The caller is responsible for destroying and freeing the
761  *       cache after using it.
762  * @return The cache or NULL if an error has occured.
763  */
764 struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
765 {
766         struct nl_cache *cache = nl_cache_alloc_from_ops(&rtnl_route_ops);
767
768         if (!cache)
769                 return NULL;
770
771         if (nl_cache_update(handle, cache) < 0) {
772                 free(cache);
773                 return NULL;
774         }
775
776         return cache;
777 }
778
779 /** @} */
780
781 /**
782  * @name Route Addition
783  * @{
784  */
785
786 static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
787                                       int flags)
788 {
789 #if 0
790         struct nl_msg *msg;
791         struct rtmsg rtmsg = {
792                 .rtm_family = tmpl->rt_family,
793         };
794         route->rt_dst_len       = rtmsg->rtm_dst_len;
795         route->rt_src_len       = rtmsg->rtm_src_len;
796         route->rt_tos           = rtmsg->rtm_tos;
797         route->rt_table         = rtmsg->rtm_table;
798         route->rt_type          = rtmsg->rtm_type;
799         route->rt_scope         = rtmsg->rtm_scope;
800         route->rt_protocol      = rtmsg->rtm_protocol;
801         route->rt_flags         = rtmsg->rtm_flags;
802
803         route->rt_mask = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_DST_LEN | 
804                           ROUTE_ATTR_SRC_LEN | ROUTE_ATTR_TABLE |
805                           ROUTE_ATTR_PROTOCOL| ROUTE_ATTR_SCOPE |
806                           ROUTE_ATTR_TYPE | ROUTE_ATTR_FLAGS);
807
808         msg = nlmsg_build_simple(cmd, flags);
809         if (!msg)
810                 return NULL;
811
812         if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), 1) < 0)
813                 goto nla_put_failure;
814
815         NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
816
817         if (tmpl->n_mask & NEIGH_ATTR_LLADDR)
818                 NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
819
820         return msg;
821
822 nla_put_failure:
823         nlmsg_free(msg);
824         return NULL;
825 #endif
826
827         return NULL;
828 }
829
830 /**
831  * Build netlink request message to add a new route
832  * @arg tmpl            template with data of new route
833  * @arg flags           additional netlink message flags
834  *
835  * Builds a new netlink message requesting a addition of a new route.
836  * The netlink message header isn't fully equipped with all relevant
837  * fields and must thus be sent out via nl_send_auto_complete() or
838  * supplemented as needed. \a tmpl must contain the attributes of the
839  * new route set via \c rtnl_route_set_* functions.
840  * 
841  * The following attributes must be set in the template:
842  *  - Interface index (rtnl_neigh_set_ifindex())
843  *  - State (rtnl_neigh_set_state())
844  *  - Destination address (rtnl_neigh_set_dst())
845  *  - Link layer address (rtnl_neigh_set_lladdr())
846  *
847  * @return The netlink message
848  */
849 struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
850 {
851         return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
852 }
853
854 /** @} */
855 /**
856  * @name Attribute: Routing Table
857  * @{
858  */
859
860 /**
861  * Set the table of a route to the specified value
862  * @arg route           route to be changed
863  * @arg table           new table value
864  */
865 void rtnl_route_set_table(struct rtnl_route *route, int table)
866 {
867         route->rt_table = table;
868         route->rt_mask |= ROUTE_ATTR_TABLE;
869 }
870
871 /**
872  * Get the table of a route
873  * @arg route           route handle
874  * @return Table id or -1 if not set
875  */
876 int rtnl_route_get_table(struct rtnl_route *route)
877 {
878         if (route->rt_mask & ROUTE_ATTR_TABLE)
879                 return route->rt_table;
880         else
881                 return -1;
882 }
883
884 /** @} */
885 /**
886  * @name Attribute: Scope
887  * @{
888  */
889
890 /**
891  * Set the scope of a route to the specified value
892  * @arg route           route to be changed
893  * @arg scope           new scope
894  */
895 void rtnl_route_set_scope(struct rtnl_route *route, int scope)
896 {
897         route->rt_scope = scope;
898         route->rt_mask |= ROUTE_ATTR_SCOPE;
899 }
900
901 /**
902  * Get the scope of a route
903  * @arg route           route handle
904  * @return Scope or -1 if not set
905  */
906 int rtnl_route_get_scope(struct rtnl_route *route)
907 {
908         if (route->rt_mask & ROUTE_ATTR_SCOPE)
909                 return route->rt_scope;
910         else
911                 return -1;
912 }
913
914 /** @} */
915 /**
916  * @name Attribute: Type Of Service
917  * @{
918  */
919
920 /**
921  * Set the TOS of a route to the specified value
922  * @arg route           route to be changed
923  * @arg tos             new TOS value
924  */
925 void rtnl_route_set_tos(struct rtnl_route *route, int tos)
926 {
927         route->rt_tos = tos;
928         route->rt_mask |= ROUTE_ATTR_TOS;
929 }
930
931 /**
932  * Get the TOS of a route
933  * @arg route           route handle
934  * @return TOS value or -1 if not set
935  */
936 int rtnl_route_get_tos(struct rtnl_route *route)
937 {
938         if (route->rt_mask & ROUTE_ATTR_TOS)
939                 return route->rt_tos;
940         else
941                 return -1;
942 }
943
944 /** @} */
945 /**
946  * @name Attribute: Realm
947  * @{
948  */
949
950 /**
951  * Set the realms of a route to the specified value
952  * @arg route           route to be changed
953  * @arg realms          New realms value.
954  */
955 void rtnl_route_set_realms(struct rtnl_route *route, realm_t realms)
956 {
957         route->rt_realms = realms;
958         route->rt_mask |= ROUTE_ATTR_REALMS;
959 }
960
961 /**
962  * Get realms of route object.
963  * @arg route           Route object.
964  * @return Realms value or 0 if not set.
965  */
966 realm_t rtnl_route_get_realms(struct rtnl_route *route)
967 {
968         if (route->rt_mask & ROUTE_ATTR_REALMS)
969                 return route->rt_realms;
970         else
971                 return 0;
972 }
973
974 /** @} */
975 /**
976  * @name Attribute: Routing Protocol
977  * @{
978  */
979
980 /**
981  * Set the protocol of a route to the specified value
982  * @arg route           route to be changed
983  * @arg proto           new protocol
984  */
985 void rtnl_route_set_protocol(struct rtnl_route *route, int proto)
986 {
987         route->rt_protocol = proto;
988         route->rt_mask |= ROUTE_ATTR_PROTOCOL;
989 }
990
991 /**
992  * Get the protocol of a route
993  * @arg route           route handle
994  * @return Protocol number or -1 if not set
995  */
996 int rtnl_route_get_protocol(struct rtnl_route *route)
997 {
998         if (route->rt_mask & ROUTE_ATTR_PROTOCOL)
999                 return route->rt_protocol;
1000         else
1001                 return -1;
1002 }
1003
1004 /** @} */
1005 /**
1006  * @name Attribute: Priority/Metric
1007  * @{
1008  */
1009
1010 /**
1011  * Set the priority of a route to the specified value
1012  * @arg route           route to be changed
1013  * @arg prio            new priority
1014  */
1015 void rtnl_route_set_prio(struct rtnl_route *route, int prio)
1016 {
1017         route->rt_prio = prio;
1018         route->rt_mask |= ROUTE_ATTR_PRIO;
1019 }
1020
1021 /**
1022  * Get the priority of a route
1023  * @arg route           route handle
1024  * @return Priority or -1 if not set
1025  */
1026 int rtnl_route_get_prio(struct rtnl_route *route)
1027 {
1028         if (route->rt_mask & ROUTE_ATTR_PRIO)
1029                 return route->rt_prio;
1030         else
1031                 return -1;
1032 }
1033
1034 /** @} */
1035 /**
1036  * @name Attribute: Address Family
1037  * @{
1038  */
1039
1040 /**
1041  * Set the address family of a route to the specified value
1042  * @arg route           route to be changed
1043  * @arg family          new address family
1044  */
1045 void rtnl_route_set_family(struct rtnl_route *route, int family)
1046 {
1047         route->rt_family = family;
1048         route->rt_mask |= ROUTE_ATTR_FAMILY;
1049 }
1050
1051 /**
1052  * Get the address family of a route
1053  * @arg route           route handle
1054  * @return Address family or AF_UNSPEC if not set
1055  */
1056 int rtnl_route_get_family(struct rtnl_route *route)
1057 {
1058         if (route->rt_mask & ROUTE_ATTR_FAMILY)
1059                 return route->rt_family;
1060         else
1061                 return AF_UNSPEC;
1062 }
1063
1064 /** @} */
1065 /**
1066  * @name Attribute: Destination Address
1067  * @{
1068  */
1069
1070 /**
1071  * Set the destination address of a route to the specified address
1072  * @arg route           route to be changed
1073  * @arg addr            new destination address
1074  *
1075  * Assigns the new destination address to the specified \a route,
1076  * overwrites the destination address length (rtnl_route::rt_dst_len),
1077  * and sets the route's address family to the new address's family if
1078  * it is not set already.
1079  *
1080  * If a address family has been specified already via either calling
1081  * rtnl_route_set_family() or by setting one of the other addresses,
1082  * the specified \a addr is automatically validated against this family
1083  * and the assignment fails in case of a mismatch.
1084  * 
1085  * @return 0 on success or a negative error code.
1086  */
1087 int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
1088 {
1089         if (route->rt_mask & ROUTE_ATTR_FAMILY) {
1090                 if (addr->a_family != route->rt_family)
1091                         return nl_error(EINVAL, "Address family mismatch");
1092         } else
1093                 route->rt_family = addr->a_family;
1094
1095         if (route->rt_dst)
1096                 nl_addr_put(route->rt_dst);
1097
1098         nl_addr_get(addr);
1099         route->rt_dst = addr;
1100         
1101         route->rt_mask |= (ROUTE_ATTR_DST|ROUTE_ATTR_FAMILY|ROUTE_ATTR_DST_LEN);
1102
1103         return 0;
1104 }
1105
1106 /**
1107  * Get the destination address of a route
1108  * @arg route           route handle
1109  * @return Destination address or NULL if not set
1110  */
1111 struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
1112 {
1113         if (route->rt_mask & ROUTE_ATTR_DST)
1114                 return route->rt_dst;
1115         else
1116                 return NULL;
1117 }
1118
1119 /**
1120  * Set the destination address prefix length of a route to the specified value
1121  * @arg route           route to be changed
1122  * @arg prefix          new destination address prefix
1123  * @attention The destination address prefix gets overwritten by calls
1124  *            to rtnl_route_set_dst() rtnl_route_set_dst_str().
1125  */
1126 void rtnl_route_set_dst_len(struct rtnl_route *route, int prefix)
1127 {
1128         route->rt_dst_len = prefix;
1129         route->rt_mask |= ROUTE_ATTR_DST_LEN;
1130 }
1131
1132 /**
1133  * Get the destination address prefix length of a route
1134  * @arg route           route handle
1135  * @return Prefix length or -1 if not set
1136  */
1137 int rtnl_route_get_dst_len(struct rtnl_route *route)
1138 {
1139         if (route->rt_mask & ROUTE_ATTR_DST_LEN)
1140                 return route->rt_dst_len;
1141         else
1142                 return -1;
1143 }
1144
1145 /** @} */
1146 /**
1147  * @name Attribute: Source Address
1148  * @{
1149  */
1150
1151 /**
1152  * Set the source address of a route to the specified address
1153  * @arg route           route to be changed
1154  * @arg addr            new source address
1155  *
1156  * Assigns the new source address to the specified \a route,
1157  * overwrites the source address length (rtnl_route::rt_src_len),
1158  * and sets the route's address family to the new address's family if
1159  * it is not set already.
1160  *
1161  * If a address family has been specified already via either calling
1162  * rtnl_route_set_family() or by setting one of the other addresses,
1163  * the specified \a addr is automatically validated against this family
1164  * and the assignment fails in case of a mismatch.
1165  * 
1166  * @return 0 on success or a negative error code.
1167  */
1168 int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
1169 {
1170         if (route->rt_mask & ROUTE_ATTR_FAMILY) {
1171                 if (addr->a_family != route->rt_family)
1172                         return nl_error(EINVAL, "Address family mismatch");
1173         } else
1174                 route->rt_family = addr->a_family;
1175
1176         if (route->rt_src)
1177                 nl_addr_put(route->rt_src);
1178
1179         nl_addr_get(addr);
1180         route->rt_src = addr;
1181         route->rt_mask |= (ROUTE_ATTR_SRC|ROUTE_ATTR_FAMILY|ROUTE_ATTR_SRC_LEN);
1182
1183         return 0;
1184 }
1185
1186 /**
1187  * Get the source address of a route
1188  * @arg route           route handle
1189  * @return Source address or NULL if not set
1190  */
1191 struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
1192 {
1193         if (route->rt_mask & ROUTE_ATTR_SRC)
1194                 return route->rt_src;
1195         else
1196                 return NULL;
1197 }
1198
1199 /**
1200  * Set the source address prefix length of a route to the specified value
1201  * @arg route           route to be changed
1202  * @arg prefix          new source address prefix
1203  * @attention The source address prefix gets overwritten by calls
1204  *            to rtnl_route_src_dst() rtnl_route_set_src_str().
1205  */
1206 void rtnl_route_set_src_len(struct rtnl_route *route, int prefix)
1207 {
1208         route->rt_dst_len = prefix;
1209         route->rt_mask |= ROUTE_ATTR_SRC_LEN;
1210 }
1211
1212 /**
1213  * Get the source address prefix length of a route
1214  * @arg route           route handle
1215  * @return Prefix length or -1 if not set
1216  */
1217 int rtnl_route_get_src_len(struct rtnl_route *route)
1218 {
1219         if (route->rt_mask & ROUTE_ATTR_SRC_LEN)
1220                 return route->rt_src_len;
1221         else
1222                 return -1;
1223 }
1224
1225 /** @} */
1226 /**
1227  * @name Attribute: Gateway Address
1228  * @{
1229  */
1230
1231 /**
1232  * Set the gateway address of a route to the specified address
1233  * @arg route           route to be changed
1234  * @arg addr            new gateway address
1235  *
1236  * Assigns the new gateway address to the specified \a route,
1237  * and sets the route's address family to the new address's family if
1238  * it is not set already.
1239  *
1240  * If a address family has been specified already via either calling
1241  * rtnl_route_set_family() or by setting one of the other addresses,
1242  * the specified \a addr is automatically validated against this family
1243  * and the assignment fails in case of a mismatch.
1244  * 
1245  * @return 0 on success or a negative error code.
1246  */
1247 int rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr)
1248 {
1249         if (route->rt_mask & ROUTE_ATTR_FAMILY) {
1250                 if (addr->a_family != route->rt_family)
1251                         return nl_error(EINVAL, "Address family mismatch");
1252         } else
1253                 route->rt_family = addr->a_family;
1254
1255         if (route->rt_gateway)
1256                 nl_addr_put(route->rt_gateway);
1257
1258         nl_addr_get(addr);
1259         route->rt_gateway = addr;
1260         route->rt_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY);
1261
1262         return 0;
1263 }
1264
1265 /**
1266  * Get the gateway address of a route
1267  * @arg route           route handle
1268  * @return Gateway address or NULL if not set
1269  */
1270 struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route)
1271 {
1272         if (route->rt_mask & ROUTE_ATTR_GATEWAY)
1273                 return route->rt_gateway;
1274         else
1275                 return NULL;
1276 }
1277
1278 /** @} */
1279 /**
1280  * @name Attribute: Type
1281  * @{
1282  */
1283
1284 /**
1285  * Set the type of a route to the specified value
1286  * @arg route           route to be changed
1287  * @arg type            new route type
1288  */
1289 void rtnl_route_set_type(struct rtnl_route *route, int type)
1290 {
1291         route->rt_type = type;
1292         route->rt_mask |= ROUTE_ATTR_TYPE;
1293 }
1294
1295 /**
1296  * Get the type of a route
1297  * @arg route           route handle
1298  * @return Type of route or -1 if not set
1299  */
1300 int rtnl_route_get_type(struct rtnl_route *route)
1301 {
1302         if (route->rt_mask & ROUTE_ATTR_TYPE)
1303                 return route->rt_type;
1304         else
1305                 return -1;
1306 }
1307
1308 /** @} */
1309 /**
1310  * @name Attribute: Flags
1311  * @{
1312  */
1313
1314 /**
1315  * Add flags to a route 
1316  * @arg route           route to be changed
1317  * @arg flags           flags to set
1318  */
1319 void rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags)
1320 {
1321         route->rt_flag_mask |= flags;
1322         route->rt_flags |= flags;
1323         route->rt_mask |= ROUTE_ATTR_FLAGS;
1324 }
1325
1326 /**
1327  * Remove flags from a route 
1328  * @arg route           route to be changed
1329  * @arg flags           flags to unset
1330  */
1331 void rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags)
1332 {
1333         route->rt_flag_mask |= flags;
1334         route->rt_flags &= ~flags;
1335         route->rt_mask |= ROUTE_ATTR_FLAGS;
1336 }
1337
1338 /**
1339  * Get flags of a route
1340  * @arg route           route handle
1341  */
1342 unsigned int rtnl_route_get_flags(struct rtnl_route *route)
1343 {
1344         return route->rt_flags;
1345 }
1346
1347 /** @} */
1348 /**
1349  * @name Attribute: Routing Metrics
1350  * @{
1351  */
1352
1353 /**
1354  * Set a metric of a route to the specified value
1355  * @arg route           route to be changed
1356  * @arg metric          metric to be changed (see XXX)
1357  * @arg value           new metric value
1358  * @return 0 on sucess or a negative error code
1359  */
1360 int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
1361 {
1362         if (metric <= RTAX_MAX || metric < 1)
1363                 return nl_error(EINVAL, "Metric out of range (1..%d)",
1364                     RTAX_MAX);
1365
1366         route->rt_metrics[metric - 1] = value;
1367         route->rt_metrics_mask |= (1 << (metric - 1));
1368
1369         return 0;
1370 }
1371
1372 /**
1373  * Unset a metric of a route
1374  * @arg route           route to be changed
1375  * @arg metric          metric to be unset (see XXX)
1376  * @return 0 on sucess or a negative error code
1377  */
1378 int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
1379 {
1380         if (metric <= RTAX_MAX || metric < 1)
1381                 return nl_error(EINVAL, "Metric out of range (1..%d)",
1382                     RTAX_MAX);
1383
1384         route->rt_metrics_mask &= ~(1 << (metric - 1));
1385
1386         return 0;
1387 }
1388
1389 /**
1390  * Get a metric for a route
1391  * @arg route           route handle
1392  * @arg metric          metric to get
1393  * @return The value for the specified metric or UINT_MAX if not set
1394  */
1395 unsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric)
1396 {
1397         if (metric <= RTAX_MAX || metric < 1)
1398                 return UINT_MAX;
1399
1400         if (!(route->rt_metrics_mask & (1 << (metric - 1))))
1401                 return UINT_MAX;
1402
1403         return route->rt_metrics[metric - 1];
1404 }
1405
1406 /** @} */
1407 /**
1408  * @name Attribute: Preferred Source Address
1409  * @{
1410  */
1411
1412 /**
1413  * Set the preferred source address of a route to the specified address
1414  * @arg route           route to be changed
1415  * @arg addr            new preferred source address
1416  *
1417  * Assigns the new preferred source address to the specified \a route,
1418  * and sets the route's address family to the new address's family if
1419  * it is not set already.
1420  *
1421  * If a address family has been specified already via either calling
1422  * rtnl_route_set_family() or by setting one of the other addresses,
1423  * the specified \a addr is automatically validated against this family
1424  * and the assignment fails in case of a mismatch.
1425  * 
1426  * @return 0 on success or a negative error code.
1427  */
1428 int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
1429 {
1430         if (route->rt_mask & ROUTE_ATTR_FAMILY) {
1431                 if (addr->a_family != route->rt_family)
1432                         return nl_error(EINVAL, "Address family mismatch");
1433         } else
1434                 route->rt_family = addr->a_family;
1435
1436         if (route->rt_pref_src)
1437                 nl_addr_put(route->rt_pref_src);
1438
1439         nl_addr_get(addr);
1440         route->rt_pref_src = addr;
1441         route->rt_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
1442
1443         return 0;
1444 }
1445
1446 /**
1447  * Get the preferred source address of a route
1448  * @arg route           route handle
1449  * @return Preferred source address or NULL if not set
1450  */
1451 struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
1452 {
1453         if (route->rt_mask & ROUTE_ATTR_PREF_SRC)
1454                 return route->rt_pref_src;
1455         else
1456                 return NULL;
1457 }
1458
1459 /** @} */
1460 /**
1461  * @name Attribute: Outgoing Interface Index
1462  * @{
1463  */
1464
1465 /**
1466  * Set the outgoing interface of a route to the specified value
1467  * @arg route           route to be changed
1468  * @arg ifindex         interface index of new outoing interface
1469  */
1470 void rtnl_route_set_oif(struct rtnl_route *route, int ifindex)
1471 {
1472         route->rt_oif = ifindex;
1473         route->rt_mask |= ROUTE_ATTR_OIF;
1474 }
1475
1476 /**
1477  * Get the outgoing interface index of a route
1478  * @arg route           route handle
1479  * @return interface index or RTNL_LINK_NOT_FOUND if not set
1480  */
1481 int rtnl_route_get_oif(struct rtnl_route *route)
1482 {
1483         if (route->rt_mask & ROUTE_ATTR_OIF)
1484                 return route->rt_oif;
1485         else
1486                 return RTNL_LINK_NOT_FOUND;
1487 }
1488
1489 /** @} */
1490 /**
1491  * @name Attribute: Incoming Interface
1492  * @{
1493  */
1494
1495 /**
1496  * Set the incoming interface of a route to the specified value
1497  * @arg route           route to be changed
1498  * @arg name            interface name of the new incoming interface
1499  */
1500 void rtnl_route_set_iif(struct rtnl_route *route, const char *name)
1501 {
1502         strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1);
1503         route->rt_mask |= ROUTE_ATTR_IIF;
1504 }
1505
1506 /**
1507  * Get the incomming interface name of a route
1508  * @arg route           route handle
1509  * @return interface name or NULL if not set
1510  */
1511 char *rtnl_route_get_iif(struct rtnl_route *route)
1512 {
1513         if (route->rt_mask & ROUTE_ATTR_IIF)
1514                 return route->rt_iif;
1515         else
1516                 return NULL;
1517 }
1518
1519 #if 0
1520         struct rtnl_rtcacheinfo rt_cacheinfo;
1521 #endif
1522
1523 /** @} */
1524 /**
1525  * @name Attribute: Nexthop
1526  * @{
1527  */
1528
1529 void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
1530 {
1531         nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
1532         route->rt_mask |= ROUTE_ATTR_MULTIPATH;
1533 }
1534
1535 void rtnl_route_remove_nexthop(struct rtnl_nexthop *nh)
1536 {
1537         nl_list_del(&nh->rtnh_list);
1538 }
1539
1540 struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
1541 {
1542         return &route->rt_nexthops;
1543 }
1544
1545 /** @} */
1546         
1547 /**
1548  * @name Routing Table Identifier Translations
1549  * @{
1550  */
1551
1552 static struct trans_tbl route_tables[] = {
1553         __ADD(RT_TABLE_UNSPEC, unspec)
1554         __ADD(RT_TABLE_DEFAULT, default)
1555         __ADD(RT_TABLE_MAIN, main)
1556         __ADD(RT_TABLE_LOCAL, local)
1557 };
1558
1559 /**
1560  * Convert routing table identifier to character string.
1561  * @arg table           Routing table identifier.
1562  * @arg buf             Destination buffer
1563  * @arg size            Size of destination buffer.
1564  *
1565  * Converts a routing table identifier to a character string and stores
1566  * it in the specified destination buffer.
1567  *
1568  * @return The destination buffer or the type encoded in hexidecimal
1569  *         form if the routing table identifier is unknown.
1570  */
1571 char *rtnl_route_table2str(int table, char *buf, size_t size)
1572 {
1573         return __type2str(table, buf, size, route_tables,
1574                           ARRAY_SIZE(route_tables));
1575 }
1576
1577 /**
1578  * Convert character string to routing table identifier.
1579  * @arg name            Name of routing table.
1580  *
1581  * Converts the provided character string specifying a routing table
1582  * identifier to the corresponding numeric value.
1583  *
1584  * @return Routing table identifier or a negative value if no match was found.
1585  */
1586 int rtnl_route_str2table(const char *name)
1587 {
1588         return __str2type(name, route_tables, ARRAY_SIZE(route_tables));
1589 }
1590
1591
1592 /** @} */
1593
1594 /**
1595  * @name Routing Protocol Translations
1596  * @{
1597  */
1598
1599 static struct trans_tbl route_protos[] = {
1600         __ADD(RTPROT_UNSPEC, unspec)
1601         __ADD(RTPROT_REDIRECT, redirect)
1602         __ADD(RTPROT_KERNEL, kernel)
1603         __ADD(RTPROT_BOOT, boot)
1604         __ADD(RTPROT_STATIC, static)
1605 };
1606
1607 /**
1608  * Convert routing protocol identifier to character string.
1609  * @arg proto           Routing protocol identifier.
1610  * @arg buf             Destination buffer
1611  * @arg size            Size of destination buffer.
1612  *
1613  * Converts a routing protocol identifier to a character string and stores
1614  * it in the specified destination buffer.
1615  *
1616  * @return The destination buffer or the protocol encoded in hexidecimal
1617  *         form if the routing protocol is unknown.
1618  */
1619 char *rtnl_route_proto2str(int proto, char *buf, size_t size)
1620 {
1621         return __type2str(proto, buf, size, route_protos,
1622                           ARRAY_SIZE(route_protos));
1623 }
1624
1625 /**
1626  * Convert character string to routing protocol identifier.
1627  * @arg name            Name of routing protocol.
1628  *
1629  * Converts the provided character string specifying a routing protocl
1630  * identifier to the corresponding numeric value.
1631  *
1632  * @return Routing protocol dentifier or a negative value if no match was found.
1633  */
1634 int rtnl_route_str2proto(const char *name)
1635 {
1636         return __str2type(name, route_protos, ARRAY_SIZE(route_protos));
1637 }
1638
1639 /** @} */
1640
1641 /**
1642  * @name Routing Metrices Translations
1643  * @{
1644  */
1645
1646 static struct trans_tbl route_metrices[] = {
1647         __ADD(RTAX_UNSPEC, unspec)
1648         __ADD(RTAX_LOCK, lock)
1649         __ADD(RTAX_MTU, mtu)
1650         __ADD(RTAX_WINDOW, window)
1651         __ADD(RTAX_RTT, rtt)
1652         __ADD(RTAX_RTTVAR, rttvar)
1653         __ADD(RTAX_SSTHRESH, ssthresh)
1654         __ADD(RTAX_CWND, cwnd)
1655         __ADD(RTAX_ADVMSS, advmss)
1656         __ADD(RTAX_REORDERING, reordering)
1657         __ADD(RTAX_HOPLIMIT, hoplimit)
1658         __ADD(RTAX_INITCWND, initcwnd)
1659         __ADD(RTAX_FEATURES, features)
1660 };
1661
1662 /**
1663  * Convert routing metric identifier to character string.
1664  * @arg metric          Routing metric identifier.
1665  * @arg buf             Destination buffer
1666  * @arg size            Size of destination buffer.
1667  *
1668  * Converts a routing metric identifier to a character string and stores
1669  * it in the specified destination buffer.
1670  *
1671  * @return The destination buffer or the metric encoded in hexidecimal
1672  *         form if the routing metric identifier is unknown.
1673  */
1674 char *rtnl_route_metric2str(int metric, char *buf, size_t size)
1675 {
1676         return __type2str(metric, buf, size, route_metrices,
1677                           ARRAY_SIZE(route_metrices));
1678 }
1679
1680 /**
1681  * Convert character string to routing metric identifier.
1682  * @arg name            Name of routing metric.
1683  *
1684  * Converts the provided character string specifying a routing metric
1685  * identifier to the corresponding numeric value.
1686  *
1687  * @return Routing metric dentifier or a negative value if no match was found.
1688  */
1689 int rtnl_route_str2metric(const char *name)
1690 {
1691         return __str2type(name, route_metrices, ARRAY_SIZE(route_metrices));
1692 }
1693
1694 /** @} */
1695
1696 /**
1697  * @name Nexthop Flags Translations
1698  * @{
1699  */
1700
1701 static struct trans_tbl nh_flags[] = {
1702         __ADD(RTNH_F_DEAD, dead)
1703         __ADD(RTNH_F_PERVASIVE, pervasive)
1704         __ADD(RTNH_F_ONLINK, onlink)
1705 };
1706
1707 /**
1708  * Convert nexthop flags to a character string.
1709  * @arg flags           Nexthop flags.
1710  * @arg buf             Destination buffer.
1711  * @arg len             Length of destination buffer.
1712  *
1713  * Converts nexthop flags to a character string separated by
1714  * commas and stores it in the specified destination buffer.
1715  *
1716  * \return The destination buffer
1717  */
1718 char * rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
1719 {
1720         return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
1721 }
1722
1723 /**
1724  * Convert a character string to a nexthop flag
1725  * @arg name            Name of nexthop flag.
1726  *
1727  * Converts the provided character string specifying a nexthop
1728  * flag to the corresponding numeric value.
1729  *
1730  * \return Nexthop flag or a negative value if none was found.
1731  */
1732 int rtnl_route_nh_str2flags(const char *name)
1733 {
1734         return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
1735 }
1736
1737 /** @} */
1738
1739 static struct nl_cache_ops rtnl_route_ops = {
1740         .co_name                = "route/route",
1741         .co_size                = sizeof(struct rtnl_route),
1742         .co_hdrsize             = sizeof(struct rtmsg),
1743         .co_msgtypes            = {
1744                                         { RTM_NEWROUTE, "new" },
1745                                         { RTM_DELROUTE, "delete" },
1746                                         { RTM_GETROUTE, "get" },
1747                                         { -1, NULL },
1748                                   },
1749         .co_protocol            = NETLINK_ROUTE,
1750         .co_request_update      = route_request_update,
1751         .co_msg_parser          = route_msg_parser,
1752         .co_constructor         = route_constructor,
1753         .co_free_data           = route_free_data,
1754         .co_dump[NL_DUMP_BRIEF] = route_dump_brief,
1755         .co_dump[NL_DUMP_FULL]  = route_dump_full,
1756         .co_dump[NL_DUMP_STATS] = route_dump_stats,
1757         .co_dump[NL_DUMP_XML]   = route_dump_xml,
1758         .co_dump[NL_DUMP_ENV]   = route_dump_env,
1759         .co_filter              = route_filter,
1760 };
1761
1762 static void __init route_init(void)
1763 {
1764         nl_cache_mngt_register(&rtnl_route_ops);
1765 }
1766
1767 static void __exit route_exit(void)
1768 {
1769         nl_cache_mngt_unregister(&rtnl_route_ops);
1770 }
1771
1772 /** @} */