00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <netlink-local.h>
00034 #include <netlink/netlink.h>
00035 #include <netlink/cache.h>
00036 #include <netlink/utils.h>
00037 #include <netlink/data.h>
00038 #include <netlink/route/rtnl.h>
00039 #include <netlink/route/route.h>
00040 #include <netlink/route/link.h>
00041 #include <netlink/route/nexthop.h>
00042
00043
00044 #define ROUTE_ATTR_FAMILY 0x000001
00045 #define ROUTE_ATTR_TOS 0x000002
00046 #define ROUTE_ATTR_TABLE 0x000004
00047 #define ROUTE_ATTR_PROTOCOL 0x000008
00048 #define ROUTE_ATTR_SCOPE 0x000010
00049 #define ROUTE_ATTR_TYPE 0x000020
00050 #define ROUTE_ATTR_FLAGS 0x000040
00051 #define ROUTE_ATTR_DST 0x000080
00052 #define ROUTE_ATTR_SRC 0x000100
00053 #define ROUTE_ATTR_IIF 0x000200
00054 #define ROUTE_ATTR_OIF 0x000400
00055 #define ROUTE_ATTR_GATEWAY 0x000800
00056 #define ROUTE_ATTR_PRIO 0x001000
00057 #define ROUTE_ATTR_PREF_SRC 0x002000
00058 #define ROUTE_ATTR_METRICS 0x004000
00059 #define ROUTE_ATTR_MULTIPATH 0x008000
00060 #define ROUTE_ATTR_REALMS 0x010000
00061 #define ROUTE_ATTR_CACHEINFO 0x020000
00062
00063
00064 static void route_constructor(struct nl_object *c)
00065 {
00066 struct rtnl_route *r = (struct rtnl_route *) c;
00067
00068 r->rt_family = AF_UNSPEC;
00069 r->rt_scope = RT_SCOPE_NOWHERE;
00070 r->rt_table = RT_TABLE_MAIN;
00071 r->rt_protocol = RTPROT_STATIC;
00072 r->rt_type = RTN_UNICAST;
00073
00074 nl_init_list_head(&r->rt_nexthops);
00075 }
00076
00077 static void route_free_data(struct nl_object *c)
00078 {
00079 struct rtnl_route *r = (struct rtnl_route *) c;
00080 struct rtnl_nexthop *nh, *tmp;
00081
00082 if (r == NULL)
00083 return;
00084
00085 nl_addr_put(r->rt_dst);
00086 nl_addr_put(r->rt_src);
00087 nl_addr_put(r->rt_pref_src);
00088
00089 nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
00090 rtnl_route_remove_nexthop(r, nh);
00091 rtnl_route_nh_free(nh);
00092 }
00093 }
00094
00095 static int route_clone(struct nl_object *_dst, struct nl_object *_src)
00096 {
00097 struct rtnl_route *dst = (struct rtnl_route *) _dst;
00098 struct rtnl_route *src = (struct rtnl_route *) _src;
00099 struct rtnl_nexthop *nh, *new;
00100
00101 if (src->rt_dst)
00102 if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
00103 return -NLE_NOMEM;
00104
00105 if (src->rt_src)
00106 if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
00107 return -NLE_NOMEM;
00108
00109 if (src->rt_pref_src)
00110 if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
00111 return -NLE_NOMEM;
00112
00113 nl_init_list_head(&dst->rt_nexthops);
00114 nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
00115 new = rtnl_route_nh_clone(nh);
00116 if (!new)
00117 return -NLE_NOMEM;
00118
00119 rtnl_route_add_nexthop(dst, new);
00120 }
00121
00122 return 0;
00123 }
00124
00125 static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
00126 {
00127 struct rtnl_route *r = (struct rtnl_route *) a;
00128 struct nl_cache *link_cache;
00129 int cache = 0, flags;
00130 char buf[64];
00131
00132 link_cache = nl_cache_mngt_require("route/link");
00133
00134 if (r->rt_flags & RTM_F_CLONED)
00135 cache = 1;
00136
00137 nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
00138
00139 if (cache)
00140 nl_dump(p, "cache ");
00141
00142 if (!(r->ce_mask & ROUTE_ATTR_DST) ||
00143 nl_addr_get_len(r->rt_dst) == 0)
00144 nl_dump(p, "default ");
00145 else
00146 nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
00147
00148 if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
00149 nl_dump(p, "table %s ",
00150 rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
00151
00152 if (r->ce_mask & ROUTE_ATTR_TYPE)
00153 nl_dump(p, "type %s ",
00154 nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
00155
00156 if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
00157 nl_dump(p, "tos %#x ", r->rt_tos);
00158
00159 if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
00160 struct rtnl_nexthop *nh;
00161
00162 nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
00163 p->dp_ivar = NH_DUMP_FROM_ONELINE;
00164 rtnl_route_nh_dump(nh, p);
00165 }
00166 }
00167
00168 flags = r->rt_flags & ~(RTM_F_CLONED);
00169 if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
00170
00171 nl_dump(p, "<");
00172
00173 #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
00174 flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
00175 PRINT_FLAG(DEAD);
00176 PRINT_FLAG(ONLINK);
00177 PRINT_FLAG(PERVASIVE);
00178 #undef PRINT_FLAG
00179
00180 #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
00181 flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
00182 PRINT_FLAG(NOTIFY);
00183 PRINT_FLAG(EQUALIZE);
00184 PRINT_FLAG(PREFIX);
00185 #undef PRINT_FLAG
00186
00187 #define PRINT_FLAG(f) if (flags & RTCF_##f) { \
00188 flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
00189 PRINT_FLAG(NOTIFY);
00190 PRINT_FLAG(REDIRECTED);
00191 PRINT_FLAG(DOREDIRECT);
00192 PRINT_FLAG(DIRECTSRC);
00193 PRINT_FLAG(DNAT);
00194 PRINT_FLAG(BROADCAST);
00195 PRINT_FLAG(MULTICAST);
00196 PRINT_FLAG(LOCAL);
00197 #undef PRINT_FLAG
00198
00199 nl_dump(p, ">");
00200 }
00201
00202 nl_dump(p, "\n");
00203 }
00204
00205 static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
00206 {
00207 struct rtnl_route *r = (struct rtnl_route *) a;
00208 struct nl_cache *link_cache;
00209 char buf[128];
00210 int i;
00211
00212 link_cache = nl_cache_mngt_require("route/link");
00213
00214 route_dump_line(a, p);
00215 nl_dump_line(p, " ");
00216
00217 if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
00218 nl_dump(p, "preferred-src %s ",
00219 nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
00220
00221 if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
00222 nl_dump(p, "scope %s ",
00223 rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
00224
00225 if (r->ce_mask & ROUTE_ATTR_PRIO)
00226 nl_dump(p, "priority %#x ", r->rt_prio);
00227
00228 if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
00229 nl_dump(p, "protocol %s ",
00230 rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
00231
00232 if (r->ce_mask & ROUTE_ATTR_IIF) {
00233 if (link_cache) {
00234 nl_dump(p, "iif %s ",
00235 rtnl_link_i2name(link_cache, r->rt_iif,
00236 buf, sizeof(buf)));
00237 } else
00238 nl_dump(p, "iif %d ", r->rt_iif);
00239 }
00240
00241 if (r->ce_mask & ROUTE_ATTR_SRC)
00242 nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
00243
00244 nl_dump(p, "\n");
00245
00246 if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
00247 struct rtnl_nexthop *nh;
00248
00249 nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
00250 nl_dump_line(p, " ");
00251 p->dp_ivar = NH_DUMP_FROM_DETAILS;
00252 rtnl_route_nh_dump(nh, p);
00253 nl_dump(p, "\n");
00254 }
00255 }
00256
00257 if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
00258 nl_dump_line(p, " cacheinfo error %d (%s)\n",
00259 r->rt_cacheinfo.rtci_error,
00260 strerror(-r->rt_cacheinfo.rtci_error));
00261 }
00262
00263 if (r->ce_mask & ROUTE_ATTR_METRICS) {
00264 nl_dump_line(p, " metrics [");
00265 for (i = 0; i < RTAX_MAX; i++)
00266 if (r->rt_metrics_mask & (1 << i))
00267 nl_dump(p, "%s %u ",
00268 rtnl_route_metric2str(i+1,
00269 buf, sizeof(buf)),
00270 r->rt_metrics[i]);
00271 nl_dump(p, "]\n");
00272 }
00273 }
00274
00275 static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00276 {
00277 struct rtnl_route *route = (struct rtnl_route *) obj;
00278
00279 route_dump_details(obj, p);
00280
00281 if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
00282 struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
00283
00284 nl_dump_line(p, " used %u refcnt %u last-use %us "
00285 "expires %us\n",
00286 ci->rtci_used, ci->rtci_clntref,
00287 ci->rtci_last_use / nl_get_user_hz(),
00288 ci->rtci_expires / nl_get_user_hz());
00289 }
00290 }
00291
00292 static int route_compare(struct nl_object *_a, struct nl_object *_b,
00293 uint32_t attrs, int flags)
00294 {
00295 struct rtnl_route *a = (struct rtnl_route *) _a;
00296 struct rtnl_route *b = (struct rtnl_route *) _b;
00297 struct rtnl_nexthop *nh_a, *nh_b;
00298 int i, diff = 0, found;
00299
00300 #define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
00301
00302 diff |= ROUTE_DIFF(FAMILY, a->rt_family != b->rt_family);
00303 diff |= ROUTE_DIFF(TOS, a->rt_tos != b->rt_tos);
00304 diff |= ROUTE_DIFF(TABLE, a->rt_table != b->rt_table);
00305 diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol);
00306 diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope);
00307 diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type);
00308 diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio);
00309 diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst));
00310 diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src));
00311 diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif);
00312 diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src,
00313 b->rt_pref_src));
00314
00315 if (flags & LOOSE_COMPARISON) {
00316 nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
00317 found = 0;
00318 nl_list_for_each_entry(nh_a, &a->rt_nexthops,
00319 rtnh_list) {
00320 if (!rtnl_route_nh_compare(nh_a, nh_b,
00321 nh_b->ce_mask, 1)) {
00322 found = 1;
00323 break;
00324 }
00325 }
00326
00327 if (!found)
00328 goto nh_mismatch;
00329 }
00330
00331 for (i = 0; i < RTAX_MAX - 1; i++) {
00332 if (a->rt_metrics_mask & (1 << i) &&
00333 (!(b->rt_metrics_mask & (1 << i)) ||
00334 a->rt_metrics[i] != b->rt_metrics[i]))
00335 ROUTE_DIFF(METRICS, 1);
00336 }
00337
00338 diff |= ROUTE_DIFF(FLAGS,
00339 (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
00340 } else {
00341 if (a->rt_nr_nh != a->rt_nr_nh)
00342 goto nh_mismatch;
00343
00344
00345 nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
00346 found = 0;
00347 nl_list_for_each_entry(nh_b, &b->rt_nexthops,
00348 rtnh_list) {
00349 if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0))
00350 found = 1;
00351 break;
00352 }
00353 if (!found)
00354 goto nh_mismatch;
00355 }
00356
00357
00358
00359 nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
00360 found = 0;
00361 nl_list_for_each_entry(nh_a, &a->rt_nexthops,
00362 rtnh_list) {
00363 if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0))
00364 found = 1;
00365 break;
00366 }
00367 if (!found)
00368 goto nh_mismatch;
00369 }
00370
00371 for (i = 0; i < RTAX_MAX - 1; i++) {
00372 if ((a->rt_metrics_mask & (1 << i)) ^
00373 (b->rt_metrics_mask & (1 << i)))
00374 diff |= ROUTE_DIFF(METRICS, 1);
00375 else
00376 diff |= ROUTE_DIFF(METRICS,
00377 a->rt_metrics[i] != b->rt_metrics[i]);
00378 }
00379
00380 diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
00381 }
00382
00383 out:
00384 return diff;
00385
00386 nh_mismatch:
00387 diff |= ROUTE_DIFF(MULTIPATH, 1);
00388 goto out;
00389
00390 #undef ROUTE_DIFF
00391 }
00392
00393 static const struct trans_tbl route_attrs[] = {
00394 __ADD(ROUTE_ATTR_FAMILY, family)
00395 __ADD(ROUTE_ATTR_TOS, tos)
00396 __ADD(ROUTE_ATTR_TABLE, table)
00397 __ADD(ROUTE_ATTR_PROTOCOL, protocol)
00398 __ADD(ROUTE_ATTR_SCOPE, scope)
00399 __ADD(ROUTE_ATTR_TYPE, type)
00400 __ADD(ROUTE_ATTR_FLAGS, flags)
00401 __ADD(ROUTE_ATTR_DST, dst)
00402 __ADD(ROUTE_ATTR_SRC, src)
00403 __ADD(ROUTE_ATTR_IIF, iif)
00404 __ADD(ROUTE_ATTR_OIF, oif)
00405 __ADD(ROUTE_ATTR_GATEWAY, gateway)
00406 __ADD(ROUTE_ATTR_PRIO, prio)
00407 __ADD(ROUTE_ATTR_PREF_SRC, pref_src)
00408 __ADD(ROUTE_ATTR_METRICS, metrics)
00409 __ADD(ROUTE_ATTR_MULTIPATH, multipath)
00410 __ADD(ROUTE_ATTR_REALMS, realms)
00411 __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
00412 };
00413
00414 static char *route_attrs2str(int attrs, char *buf, size_t len)
00415 {
00416 return __flags2str(attrs, buf, len, route_attrs,
00417 ARRAY_SIZE(route_attrs));
00418 }
00419
00420
00421
00422
00423
00424
00425 struct rtnl_route *rtnl_route_alloc(void)
00426 {
00427 return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
00428 }
00429
00430 void rtnl_route_get(struct rtnl_route *route)
00431 {
00432 nl_object_get((struct nl_object *) route);
00433 }
00434
00435 void rtnl_route_put(struct rtnl_route *route)
00436 {
00437 nl_object_put((struct nl_object *) route);
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447 void rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
00448 {
00449 route->rt_table = table;
00450 route->ce_mask |= ROUTE_ATTR_TABLE;
00451 }
00452
00453 uint32_t rtnl_route_get_table(struct rtnl_route *route)
00454 {
00455 return route->rt_table;
00456 }
00457
00458 void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
00459 {
00460 route->rt_scope = scope;
00461 route->ce_mask |= ROUTE_ATTR_SCOPE;
00462 }
00463
00464 uint8_t rtnl_route_get_scope(struct rtnl_route *route)
00465 {
00466 return route->rt_scope;
00467 }
00468
00469 void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
00470 {
00471 route->rt_tos = tos;
00472 route->ce_mask |= ROUTE_ATTR_TOS;
00473 }
00474
00475 uint8_t rtnl_route_get_tos(struct rtnl_route *route)
00476 {
00477 return route->rt_tos;
00478 }
00479
00480 void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
00481 {
00482 route->rt_protocol = protocol;
00483 route->ce_mask |= ROUTE_ATTR_PROTOCOL;
00484 }
00485
00486 uint8_t rtnl_route_get_protocol(struct rtnl_route *route)
00487 {
00488 return route->rt_protocol;
00489 }
00490
00491 void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
00492 {
00493 route->rt_prio = prio;
00494 route->ce_mask |= ROUTE_ATTR_PRIO;
00495 }
00496
00497 uint32_t rtnl_route_get_priority(struct rtnl_route *route)
00498 {
00499 return route->rt_prio;
00500 }
00501
00502 int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
00503 {
00504 if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
00505 return -NLE_AF_NOSUPPORT;
00506
00507 route->rt_family = family;
00508 route->ce_mask |= ROUTE_ATTR_FAMILY;
00509
00510 return 0;
00511 }
00512
00513 uint8_t rtnl_route_get_family(struct rtnl_route *route)
00514 {
00515 return route->rt_family;
00516 }
00517
00518 int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
00519 {
00520 if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00521 if (addr->a_family != route->rt_family)
00522 return -NLE_AF_MISMATCH;
00523 } else
00524 route->rt_family = addr->a_family;
00525
00526 if (route->rt_dst)
00527 nl_addr_put(route->rt_dst);
00528
00529 nl_addr_get(addr);
00530 route->rt_dst = addr;
00531
00532 route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
00533
00534 return 0;
00535 }
00536
00537 struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
00538 {
00539 return route->rt_dst;
00540 }
00541
00542 int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
00543 {
00544 if (addr->a_family == AF_INET)
00545 return -NLE_SRCRT_NOSUPPORT;
00546
00547 if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00548 if (addr->a_family != route->rt_family)
00549 return -NLE_AF_MISMATCH;
00550 } else
00551 route->rt_family = addr->a_family;
00552
00553 if (route->rt_src)
00554 nl_addr_put(route->rt_src);
00555
00556 nl_addr_get(addr);
00557 route->rt_src = addr;
00558 route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
00559
00560 return 0;
00561 }
00562
00563 struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
00564 {
00565 return route->rt_src;
00566 }
00567
00568 int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
00569 {
00570 if (type > RTN_MAX)
00571 return -NLE_RANGE;
00572
00573 route->rt_type = type;
00574 route->ce_mask |= ROUTE_ATTR_TYPE;
00575
00576 return 0;
00577 }
00578
00579 uint8_t rtnl_route_get_type(struct rtnl_route *route)
00580 {
00581 return route->rt_type;
00582 }
00583
00584 void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
00585 {
00586 route->rt_flag_mask |= flags;
00587 route->rt_flags |= flags;
00588 route->ce_mask |= ROUTE_ATTR_FLAGS;
00589 }
00590
00591 void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
00592 {
00593 route->rt_flag_mask |= flags;
00594 route->rt_flags &= ~flags;
00595 route->ce_mask |= ROUTE_ATTR_FLAGS;
00596 }
00597
00598 uint32_t rtnl_route_get_flags(struct rtnl_route *route)
00599 {
00600 return route->rt_flags;
00601 }
00602
00603 int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
00604 {
00605 if (metric > RTAX_MAX || metric < 1)
00606 return -NLE_RANGE;
00607
00608 route->rt_metrics[metric - 1] = value;
00609
00610 if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
00611 route->rt_nmetrics++;
00612 route->rt_metrics_mask |= (1 << (metric - 1));
00613 }
00614
00615 route->ce_mask |= ROUTE_ATTR_METRICS;
00616
00617 return 0;
00618 }
00619
00620 int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
00621 {
00622 if (metric > RTAX_MAX || metric < 1)
00623 return -NLE_RANGE;
00624
00625 if (route->rt_metrics_mask & (1 << (metric - 1))) {
00626 route->rt_nmetrics--;
00627 route->rt_metrics_mask &= ~(1 << (metric - 1));
00628 }
00629
00630 return 0;
00631 }
00632
00633 int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
00634 {
00635 if (metric > RTAX_MAX || metric < 1)
00636 return -NLE_RANGE;
00637
00638 if (!(route->rt_metrics_mask & (1 << (metric - 1))))
00639 return -NLE_OBJ_NOTFOUND;
00640
00641 if (value)
00642 *value = route->rt_metrics[metric - 1];
00643
00644 return 0;
00645 }
00646
00647 int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
00648 {
00649 if (route->ce_mask & ROUTE_ATTR_FAMILY) {
00650 if (addr->a_family != route->rt_family)
00651 return -NLE_AF_MISMATCH;
00652 } else
00653 route->rt_family = addr->a_family;
00654
00655 if (route->rt_pref_src)
00656 nl_addr_put(route->rt_pref_src);
00657
00658 nl_addr_get(addr);
00659 route->rt_pref_src = addr;
00660 route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
00661
00662 return 0;
00663 }
00664
00665 struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
00666 {
00667 return route->rt_pref_src;
00668 }
00669
00670 void rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
00671 {
00672 route->rt_iif = ifindex;
00673 route->ce_mask |= ROUTE_ATTR_IIF;
00674 }
00675
00676 int rtnl_route_get_iif(struct rtnl_route *route)
00677 {
00678 return route->rt_iif;
00679 }
00680
00681 void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
00682 {
00683 nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
00684 route->rt_nr_nh++;
00685 route->ce_mask |= ROUTE_ATTR_MULTIPATH;
00686 }
00687
00688 void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
00689 {
00690 route->rt_nr_nh--;
00691 nl_list_del(&nh->rtnh_list);
00692 }
00693
00694 struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
00695 {
00696 return &route->rt_nexthops;
00697 }
00698
00699 int rtnl_route_get_nnexthops(struct rtnl_route *route)
00700 {
00701 return route->rt_nr_nh;
00702 }
00703
00704 void rtnl_route_foreach_nexthop(struct rtnl_route *r,
00705 void (*cb)(struct rtnl_nexthop *, void *),
00706 void *arg)
00707 {
00708 struct rtnl_nexthop *nh;
00709
00710 if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
00711 nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
00712 cb(nh, arg);
00713 }
00714 }
00715 }
00716
00717 struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
00718 {
00719 struct rtnl_nexthop *nh;
00720 int i;
00721
00722 if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
00723 i = 0;
00724 nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
00725 if (i == n) return nh;
00726 i++;
00727 }
00728 }
00729 return NULL;
00730 }
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 int rtnl_route_guess_scope(struct rtnl_route *route)
00753 {
00754 if (route->rt_type == RTN_LOCAL)
00755 return RT_SCOPE_HOST;
00756
00757 if (!nl_list_empty(&route->rt_nexthops)) {
00758 struct rtnl_nexthop *nh;
00759
00760
00761
00762
00763
00764 nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
00765 if (nh->rtnh_gateway)
00766 return RT_SCOPE_UNIVERSE;
00767 }
00768 }
00769
00770 return RT_SCOPE_LINK;
00771 }
00772
00773
00774
00775 static struct nla_policy route_policy[RTA_MAX+1] = {
00776 [RTA_IIF] = { .type = NLA_U32 },
00777 [RTA_OIF] = { .type = NLA_U32 },
00778 [RTA_PRIORITY] = { .type = NLA_U32 },
00779 [RTA_FLOW] = { .type = NLA_U32 },
00780 [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
00781 [RTA_METRICS] = { .type = NLA_NESTED },
00782 [RTA_MULTIPATH] = { .type = NLA_NESTED },
00783 };
00784
00785 static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
00786 {
00787 struct rtnl_nexthop *nh = NULL;
00788 struct rtnexthop *rtnh = nla_data(attr);
00789 size_t tlen = nla_len(attr);
00790 int err;
00791
00792 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
00793 nh = rtnl_route_nh_alloc();
00794 if (!nh)
00795 return -NLE_NOMEM;
00796
00797 rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
00798 rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
00799 rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
00800
00801 if (rtnh->rtnh_len > sizeof(*rtnh)) {
00802 struct nlattr *ntb[RTA_MAX + 1];
00803
00804 err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
00805 RTNH_DATA(rtnh),
00806 rtnh->rtnh_len - sizeof(*rtnh),
00807 route_policy);
00808 if (err < 0)
00809 goto errout;
00810
00811 if (ntb[RTA_GATEWAY]) {
00812 struct nl_addr *addr;
00813
00814 addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
00815 route->rt_family);
00816 if (!addr) {
00817 err = -NLE_NOMEM;
00818 goto errout;
00819 }
00820
00821 rtnl_route_nh_set_gateway(nh, addr);
00822 nl_addr_put(addr);
00823 }
00824
00825 if (ntb[RTA_FLOW]) {
00826 uint32_t realms;
00827
00828 realms = nla_get_u32(ntb[RTA_FLOW]);
00829 rtnl_route_nh_set_realms(nh, realms);
00830 }
00831 }
00832
00833 rtnl_route_add_nexthop(route, nh);
00834 tlen -= RTNH_ALIGN(rtnh->rtnh_len);
00835 rtnh = RTNH_NEXT(rtnh);
00836 }
00837
00838 err = 0;
00839 errout:
00840 if (err && nh)
00841 rtnl_route_nh_free(nh);
00842
00843 return err;
00844 }
00845
00846 int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
00847 {
00848 struct rtmsg *rtm;
00849 struct rtnl_route *route;
00850 struct nlattr *tb[RTA_MAX + 1];
00851 struct nl_addr *src = NULL, *dst = NULL, *addr;
00852 struct rtnl_nexthop *old_nh = NULL;
00853 int err, family;
00854
00855 route = rtnl_route_alloc();
00856 if (!route) {
00857 err = -NLE_NOMEM;
00858 goto errout;
00859 }
00860
00861 route->ce_msgtype = nlh->nlmsg_type;
00862
00863 err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
00864 if (err < 0)
00865 goto errout;
00866
00867 rtm = nlmsg_data(nlh);
00868 route->rt_family = family = rtm->rtm_family;
00869 route->rt_tos = rtm->rtm_tos;
00870 route->rt_table = rtm->rtm_table;
00871 route->rt_type = rtm->rtm_type;
00872 route->rt_scope = rtm->rtm_scope;
00873 route->rt_protocol = rtm->rtm_protocol;
00874 route->rt_flags = rtm->rtm_flags;
00875
00876 route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
00877 ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
00878 ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
00879 ROUTE_ATTR_FLAGS;
00880
00881 if (tb[RTA_DST]) {
00882 if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
00883 goto errout_nomem;
00884 } else {
00885 if (!(dst = nl_addr_alloc(0)))
00886 goto errout_nomem;
00887 nl_addr_set_family(dst, rtm->rtm_family);
00888 }
00889
00890 nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
00891 err = rtnl_route_set_dst(route, dst);
00892 if (err < 0)
00893 goto errout;
00894
00895 nl_addr_put(dst);
00896
00897 if (tb[RTA_SRC]) {
00898 if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
00899 goto errout_nomem;
00900 } else if (rtm->rtm_src_len)
00901 if (!(src = nl_addr_alloc(0)))
00902 goto errout_nomem;
00903
00904 if (src) {
00905 nl_addr_set_prefixlen(src, rtm->rtm_src_len);
00906 rtnl_route_set_src(route, src);
00907 nl_addr_put(src);
00908 }
00909
00910 if (tb[RTA_IIF])
00911 rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
00912
00913 if (tb[RTA_PRIORITY])
00914 rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
00915
00916 if (tb[RTA_PREFSRC]) {
00917 if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
00918 goto errout_nomem;
00919 rtnl_route_set_pref_src(route, addr);
00920 nl_addr_put(addr);
00921 }
00922
00923 if (tb[RTA_METRICS]) {
00924 struct nlattr *mtb[RTAX_MAX + 1];
00925 int i;
00926
00927 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
00928 if (err < 0)
00929 goto errout;
00930
00931 for (i = 1; i <= RTAX_MAX; i++) {
00932 if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
00933 uint32_t m = nla_get_u32(mtb[i]);
00934 if (rtnl_route_set_metric(route, i, m) < 0)
00935 goto errout;
00936 }
00937 }
00938 }
00939
00940 if (tb[RTA_MULTIPATH])
00941 if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
00942 goto errout;
00943
00944 if (tb[RTA_CACHEINFO]) {
00945 nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
00946 sizeof(route->rt_cacheinfo));
00947 route->ce_mask |= ROUTE_ATTR_CACHEINFO;
00948 }
00949
00950 if (tb[RTA_OIF]) {
00951 if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
00952 goto errout;
00953
00954 rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
00955 }
00956
00957 if (tb[RTA_GATEWAY]) {
00958 if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
00959 goto errout;
00960
00961 if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
00962 goto errout_nomem;
00963
00964 rtnl_route_nh_set_gateway(old_nh, addr);
00965 nl_addr_put(addr);
00966 }
00967
00968 if (tb[RTA_FLOW]) {
00969 if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
00970 goto errout;
00971
00972 rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
00973 }
00974
00975 if (old_nh) {
00976 if (route->rt_nr_nh == 0) {
00977
00978
00979
00980 rtnl_route_add_nexthop(route, old_nh);
00981 } else {
00982
00983
00984 struct rtnl_nexthop *first;
00985
00986 first = nl_list_first_entry(&route->rt_nexthops,
00987 struct rtnl_nexthop,
00988 rtnh_list);
00989 if (!first)
00990 BUG();
00991
00992 if (rtnl_route_nh_compare(old_nh, first,
00993 old_nh->ce_mask, 0)) {
00994 err = -NLE_INVAL;
00995 goto errout;
00996 }
00997
00998 rtnl_route_nh_free(old_nh);
00999 }
01000 }
01001
01002 *result = route;
01003 return 0;
01004
01005 errout:
01006 rtnl_route_put(route);
01007 return err;
01008
01009 errout_nomem:
01010 err = -NLE_NOMEM;
01011 goto errout;
01012 }
01013
01014 int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
01015 {
01016 int i;
01017 struct nlattr *metrics;
01018 struct rtmsg rtmsg = {
01019 .rtm_family = route->rt_family,
01020 .rtm_tos = route->rt_tos,
01021 .rtm_table = route->rt_table,
01022 .rtm_protocol = route->rt_protocol,
01023 .rtm_scope = route->rt_scope,
01024 .rtm_type = route->rt_type,
01025 .rtm_flags = route->rt_flags,
01026 };
01027
01028 if (route->rt_dst == NULL)
01029 return -NLE_MISSING_ATTR;
01030
01031 rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
01032 if (route->rt_src)
01033 rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
01034
01035
01036 if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE)
01037 rtmsg.rtm_scope = rtnl_route_guess_scope(route);
01038
01039 if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
01040 goto nla_put_failure;
01041
01042
01043
01044 NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
01045
01046 if (nl_addr_get_len(route->rt_dst))
01047 NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
01048 NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
01049
01050 if (route->ce_mask & ROUTE_ATTR_SRC)
01051 NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
01052
01053 if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
01054 NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
01055
01056 if (route->ce_mask & ROUTE_ATTR_IIF)
01057 NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
01058
01059 if (route->rt_nmetrics > 0) {
01060 uint32_t val;
01061
01062 metrics = nla_nest_start(msg, RTA_METRICS);
01063 if (metrics == NULL)
01064 goto nla_put_failure;
01065
01066 for (i = 1; i <= RTAX_MAX; i++) {
01067 if (!rtnl_route_get_metric(route, i, &val))
01068 NLA_PUT_U32(msg, i, val);
01069 }
01070
01071 nla_nest_end(msg, metrics);
01072 }
01073
01074 if (rtnl_route_get_nnexthops(route) > 0) {
01075 struct nlattr *multipath;
01076 struct rtnl_nexthop *nh;
01077
01078 if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
01079 goto nla_put_failure;
01080
01081 nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
01082 struct rtnexthop *rtnh;
01083
01084 rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
01085 if (!rtnh)
01086 goto nla_put_failure;
01087
01088 rtnh->rtnh_flags = nh->rtnh_flags;
01089 rtnh->rtnh_hops = nh->rtnh_weight;
01090 rtnh->rtnh_ifindex = nh->rtnh_ifindex;
01091
01092 if (nh->rtnh_gateway)
01093 NLA_PUT_ADDR(msg, RTA_GATEWAY,
01094 nh->rtnh_gateway);
01095
01096 if (nh->rtnh_realms)
01097 NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
01098
01099 rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
01100 (void *) rtnh;
01101 }
01102
01103 nla_nest_end(msg, multipath);
01104 }
01105
01106 return 0;
01107
01108 nla_put_failure:
01109 return -NLE_MSGSIZE;
01110 }
01111
01112
01113 struct nl_object_ops route_obj_ops = {
01114 .oo_name = "route/route",
01115 .oo_size = sizeof(struct rtnl_route),
01116 .oo_constructor = route_constructor,
01117 .oo_free_data = route_free_data,
01118 .oo_clone = route_clone,
01119 .oo_dump = {
01120 [NL_DUMP_LINE] = route_dump_line,
01121 [NL_DUMP_DETAILS] = route_dump_details,
01122 [NL_DUMP_STATS] = route_dump_stats,
01123 },
01124 .oo_compare = route_compare,
01125 .oo_attrs2str = route_attrs2str,
01126 .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
01127 ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
01128 };
01129
01130
01131