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