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