libnl 2.0
|
00001 /* 00002 * lib/route/route_obj.c Route Object 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup route 00014 * @defgroup route_obj Route Object 00015 * 00016 * @par Attributes 00017 * @code 00018 * Name Default 00019 * ------------------------------------------------------------- 00020 * routing table RT_TABLE_MAIN 00021 * scope RT_SCOPE_NOWHERE 00022 * tos 0 00023 * protocol RTPROT_STATIC 00024 * prio 0 00025 * family AF_UNSPEC 00026 * type RTN_UNICAST 00027 * iif NULL 00028 * @endcode 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 /** @cond SKIP */ 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 /** @endcond */ 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 /* search for a dup in each nh of a */ 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 /* search for a dup in each nh of b, covers case where a has 00423 * dupes itself */ 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 * @name Allocation/Freeing 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 * @name Attributes 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 * @name Utilities 00801 * @{ 00802 */ 00803 00804 /** 00805 * Guess scope of a route object. 00806 * @arg route Route object. 00807 * 00808 * Guesses the scope of a route object, based on the following rules: 00809 * @code 00810 * 1) Local route -> local scope 00811 * 2) At least one nexthop not directly connected -> universe scope 00812 * 3) All others -> link scope 00813 * @endcode 00814 * 00815 * @return Scope value. 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 * Use scope uiniverse if there is at least one nexthop which 00827 * is not directly connected 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 /* If no nexthops have been provided via RTA_MULTIPATH 01043 * we add it as regular nexthop to maintain backwards 01044 * compatibility */ 01045 rtnl_route_add_nexthop(route, old_nh); 01046 } else { 01047 /* Kernel supports new style nexthop configuration, 01048 * verify that it is a duplicate and discard nexthop. */ 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 /* Additional table attribute replacing the 8bit in the header, was 01108 * required to allow more than 256 tables. */ 01109 NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); 01110 01111 if (nl_addr_get_len(route->rt_dst)) 01112 NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst); 01113 NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); 01114 01115 if (route->ce_mask & ROUTE_ATTR_SRC) 01116 NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src); 01117 01118 if (route->ce_mask & ROUTE_ATTR_PREF_SRC) 01119 NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src); 01120 01121 if (route->ce_mask & ROUTE_ATTR_IIF) 01122 NLA_PUT_U32(msg, RTA_IIF, route->rt_iif); 01123 01124 if (route->rt_nmetrics > 0) { 01125 uint32_t val; 01126 01127 metrics = nla_nest_start(msg, RTA_METRICS); 01128 if (metrics == NULL) 01129 goto nla_put_failure; 01130 01131 for (i = 1; i <= RTAX_MAX; i++) { 01132 if (!rtnl_route_get_metric(route, i, &val)) 01133 NLA_PUT_U32(msg, i, val); 01134 } 01135 01136 nla_nest_end(msg, metrics); 01137 } 01138 01139 if (rtnl_route_get_nnexthops(route) > 0) { 01140 struct nlattr *multipath; 01141 struct rtnl_nexthop *nh; 01142 01143 if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH))) 01144 goto nla_put_failure; 01145 01146 nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { 01147 struct rtnexthop *rtnh; 01148 01149 rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO); 01150 if (!rtnh) 01151 goto nla_put_failure; 01152 01153 rtnh->rtnh_flags = nh->rtnh_flags; 01154 rtnh->rtnh_hops = nh->rtnh_weight; 01155 rtnh->rtnh_ifindex = nh->rtnh_ifindex; 01156 01157 if (nh->rtnh_gateway) 01158 NLA_PUT_ADDR(msg, RTA_GATEWAY, 01159 nh->rtnh_gateway); 01160 01161 if (nh->rtnh_realms) 01162 NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); 01163 01164 rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) - 01165 (void *) rtnh; 01166 } 01167 01168 nla_nest_end(msg, multipath); 01169 } 01170 01171 return 0; 01172 01173 nla_put_failure: 01174 return -NLE_MSGSIZE; 01175 } 01176 01177 /** @cond SKIP */ 01178 struct nl_object_ops route_obj_ops = { 01179 .oo_name = "route/route", 01180 .oo_size = sizeof(struct rtnl_route), 01181 .oo_constructor = route_constructor, 01182 .oo_free_data = route_free_data, 01183 .oo_clone = route_clone, 01184 .oo_dump = { 01185 [NL_DUMP_LINE] = route_dump_line, 01186 [NL_DUMP_DETAILS] = route_dump_details, 01187 [NL_DUMP_STATS] = route_dump_stats, 01188 [NL_DUMP_ENV] = route_dump_env, 01189 }, 01190 .oo_compare = route_compare, 01191 .oo_attrs2str = route_attrs2str, 01192 .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | 01193 ROUTE_ATTR_TABLE | ROUTE_ATTR_DST), 01194 }; 01195 /** @endcond */ 01196 01197 /** @} */