libnl 1.1
|
00001 /* 00002 * lib/route/route.c Routes 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-2006 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup rtnl 00014 * @defgroup route Routing 00015 * @brief 00016 * @{ 00017 */ 00018 00019 #include <netlink-local.h> 00020 #include <netlink/netlink.h> 00021 #include <netlink/cache.h> 00022 #include <netlink/utils.h> 00023 #include <netlink/data.h> 00024 #include <netlink/route/rtnl.h> 00025 #include <netlink/route/route.h> 00026 #include <netlink/route/link.h> 00027 00028 static struct nl_cache_ops rtnl_route_ops; 00029 00030 static struct nla_policy route_policy[RTA_MAX+1] = { 00031 [RTA_IIF] = { .type = NLA_STRING, 00032 .maxlen = IFNAMSIZ, }, 00033 [RTA_OIF] = { .type = NLA_U32 }, 00034 [RTA_PRIORITY] = { .type = NLA_U32 }, 00035 [RTA_FLOW] = { .type = NLA_U32 }, 00036 [RTA_MP_ALGO] = { .type = NLA_U32 }, 00037 [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, 00038 [RTA_METRICS] = { .type = NLA_NESTED }, 00039 [RTA_MULTIPATH] = { .type = NLA_NESTED }, 00040 }; 00041 00042 static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, 00043 struct rtnl_route *route) 00044 { 00045 struct rtnl_rtcacheinfo nci = { 00046 .rtci_clntref = ci->rta_clntref, 00047 .rtci_last_use = ci->rta_lastuse, 00048 .rtci_expires = ci->rta_expires, 00049 .rtci_error = ci->rta_error, 00050 .rtci_used = ci->rta_used, 00051 .rtci_id = ci->rta_id, 00052 .rtci_ts = ci->rta_ts, 00053 .rtci_tsage = ci->rta_tsage, 00054 }; 00055 00056 rtnl_route_set_cacheinfo(route, &nci); 00057 } 00058 00059 static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00060 struct nlmsghdr *nlh, struct nl_parser_param *pp) 00061 { 00062 struct rtmsg *rtm; 00063 struct rtnl_route *route; 00064 struct nlattr *tb[RTA_MAX + 1]; 00065 struct nl_addr *src = NULL, *dst = NULL, *addr; 00066 int err; 00067 00068 route = rtnl_route_alloc(); 00069 if (!route) { 00070 err = nl_errno(ENOMEM); 00071 goto errout; 00072 } 00073 00074 route->ce_msgtype = nlh->nlmsg_type; 00075 00076 err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, 00077 route_policy); 00078 if (err < 0) 00079 goto errout; 00080 00081 rtm = nlmsg_data(nlh); 00082 rtnl_route_set_family(route, rtm->rtm_family); 00083 rtnl_route_set_tos(route, rtm->rtm_tos); 00084 rtnl_route_set_table(route, rtm->rtm_table); 00085 rtnl_route_set_type(route, rtm->rtm_type); 00086 rtnl_route_set_scope(route, rtm->rtm_scope); 00087 rtnl_route_set_protocol(route, rtm->rtm_protocol); 00088 rtnl_route_set_flags(route, rtm->rtm_flags); 00089 00090 if (tb[RTA_DST]) { 00091 dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); 00092 if (dst == NULL) 00093 goto errout_errno; 00094 } else { 00095 dst = nl_addr_alloc(0); 00096 nl_addr_set_family(dst, rtm->rtm_family); 00097 } 00098 00099 nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); 00100 err = rtnl_route_set_dst(route, dst); 00101 if (err < 0) 00102 goto errout; 00103 00104 nl_addr_put(dst); 00105 00106 if (tb[RTA_SRC]) { 00107 src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); 00108 if (src == NULL) 00109 goto errout_errno; 00110 } else if (rtm->rtm_src_len) 00111 src = nl_addr_alloc(0); 00112 00113 if (src) { 00114 nl_addr_set_prefixlen(src, rtm->rtm_src_len); 00115 rtnl_route_set_src(route, src); 00116 nl_addr_put(src); 00117 } 00118 00119 if (tb[RTA_IIF]) 00120 rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); 00121 00122 if (tb[RTA_OIF]) 00123 rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); 00124 00125 if (tb[RTA_GATEWAY]) { 00126 addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); 00127 if (addr == NULL) 00128 goto errout_errno; 00129 rtnl_route_set_gateway(route, addr); 00130 nl_addr_put(addr); 00131 } 00132 00133 if (tb[RTA_PRIORITY]) 00134 rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); 00135 00136 if (tb[RTA_PREFSRC]) { 00137 addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); 00138 if (addr == NULL) 00139 goto errout_errno; 00140 rtnl_route_set_pref_src(route, addr); 00141 nl_addr_put(addr); 00142 } 00143 00144 if (tb[RTA_METRICS]) { 00145 struct nlattr *mtb[RTAX_MAX + 1]; 00146 int i; 00147 00148 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); 00149 if (err < 0) 00150 goto errout; 00151 00152 for (i = 1; i <= RTAX_MAX; i++) { 00153 if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { 00154 uint32_t m = nla_get_u32(mtb[i]); 00155 if (rtnl_route_set_metric(route, i, m) < 0) 00156 goto errout_errno; 00157 } 00158 } 00159 } 00160 00161 if (tb[RTA_MULTIPATH]) { 00162 struct rtnl_nexthop *nh; 00163 struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); 00164 size_t tlen = nla_len(tb[RTA_MULTIPATH]); 00165 00166 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { 00167 nh = rtnl_route_nh_alloc(); 00168 if (!nh) 00169 goto errout; 00170 00171 rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); 00172 rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); 00173 rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); 00174 00175 if (rtnh->rtnh_len > sizeof(*rtnh)) { 00176 struct nlattr *ntb[RTA_MAX + 1]; 00177 nla_parse(ntb, RTA_MAX, (struct nlattr *) 00178 RTNH_DATA(rtnh), 00179 rtnh->rtnh_len - sizeof(*rtnh), 00180 route_policy); 00181 00182 if (ntb[RTA_GATEWAY]) { 00183 nh->rtnh_gateway = nla_get_addr( 00184 ntb[RTA_GATEWAY], 00185 route->rt_family); 00186 nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; 00187 } 00188 } 00189 00190 rtnl_route_add_nexthop(route, nh); 00191 tlen -= RTNH_ALIGN(rtnh->rtnh_len); 00192 rtnh = RTNH_NEXT(rtnh); 00193 } 00194 } 00195 00196 if (tb[RTA_FLOW]) 00197 rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); 00198 00199 if (tb[RTA_CACHEINFO]) 00200 copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); 00201 00202 if (tb[RTA_MP_ALGO]) 00203 rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); 00204 00205 err = pp->pp_cb((struct nl_object *) route, pp); 00206 if (err < 0) 00207 goto errout; 00208 00209 err = P_ACCEPT; 00210 00211 errout: 00212 rtnl_route_put(route); 00213 return err; 00214 00215 errout_errno: 00216 err = nl_get_errno(); 00217 goto errout; 00218 } 00219 00220 static int route_request_update(struct nl_cache *c, struct nl_handle *h) 00221 { 00222 return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); 00223 } 00224 00225 /** 00226 * @name Cache Management 00227 * @{ 00228 */ 00229 00230 /** 00231 * Build a route cache holding all routes currently configured in the kernel 00232 * @arg handle netlink handle 00233 * 00234 * Allocates a new cache, initializes it properly and updates it to 00235 * contain all routes currently configured in the kernel. 00236 * 00237 * @note The caller is responsible for destroying and freeing the 00238 * cache after using it. 00239 * @return The cache or NULL if an error has occured. 00240 */ 00241 struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) 00242 { 00243 struct nl_cache *cache; 00244 00245 cache = nl_cache_alloc(&rtnl_route_ops); 00246 if (!cache) 00247 return NULL; 00248 00249 if (handle && nl_cache_refill(handle, cache) < 0) { 00250 free(cache); 00251 return NULL; 00252 } 00253 00254 return cache; 00255 } 00256 00257 /** @} */ 00258 00259 /** 00260 * @name Route Addition 00261 * @{ 00262 */ 00263 00264 static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, 00265 int flags) 00266 { 00267 struct nl_msg *msg; 00268 struct nl_addr *addr; 00269 int scope, i, oif, nmetrics = 0; 00270 struct nlattr *metrics; 00271 struct rtmsg rtmsg = { 00272 .rtm_family = rtnl_route_get_family(tmpl), 00273 .rtm_dst_len = rtnl_route_get_dst_len(tmpl), 00274 .rtm_src_len = rtnl_route_get_src_len(tmpl), 00275 .rtm_tos = rtnl_route_get_tos(tmpl), 00276 .rtm_table = rtnl_route_get_table(tmpl), 00277 .rtm_type = rtnl_route_get_type(tmpl), 00278 .rtm_protocol = rtnl_route_get_protocol(tmpl), 00279 .rtm_flags = rtnl_route_get_flags(tmpl), 00280 }; 00281 00282 if (rtmsg.rtm_family == AF_UNSPEC) { 00283 nl_error(EINVAL, "Cannot build route message, address " \ 00284 "family is unknown."); 00285 return NULL; 00286 } 00287 00288 scope = rtnl_route_get_scope(tmpl); 00289 if (scope == RT_SCOPE_NOWHERE) { 00290 if (rtmsg.rtm_type == RTN_LOCAL) 00291 scope = RT_SCOPE_HOST; 00292 else { 00293 /* XXX Change to UNIVERSE if gw || nexthops */ 00294 scope = RT_SCOPE_LINK; 00295 } 00296 } 00297 00298 rtmsg.rtm_scope = scope; 00299 00300 msg = nlmsg_alloc_simple(cmd, flags); 00301 if (msg == NULL) 00302 return NULL; 00303 00304 if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) 00305 goto nla_put_failure; 00306 00307 addr = rtnl_route_get_dst(tmpl); 00308 if (addr) 00309 NLA_PUT_ADDR(msg, RTA_DST, addr); 00310 00311 addr = rtnl_route_get_src(tmpl); 00312 if (addr) 00313 NLA_PUT_ADDR(msg, RTA_SRC, addr); 00314 00315 addr = rtnl_route_get_gateway(tmpl); 00316 if (addr) 00317 NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); 00318 00319 addr = rtnl_route_get_pref_src(tmpl); 00320 if (addr) 00321 NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); 00322 00323 NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); 00324 00325 oif = rtnl_route_get_oif(tmpl); 00326 if (oif != RTNL_LINK_NOT_FOUND) 00327 NLA_PUT_U32(msg, RTA_OIF, oif); 00328 00329 for (i = 1; i <= RTAX_MAX; i++) 00330 if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) 00331 nmetrics++; 00332 00333 if (nmetrics > 0) { 00334 unsigned int val; 00335 00336 metrics = nla_nest_start(msg, RTA_METRICS); 00337 if (metrics == NULL) 00338 goto nla_put_failure; 00339 00340 for (i = 1; i <= RTAX_MAX; i++) { 00341 val = rtnl_route_get_metric(tmpl, i); 00342 if (val != UINT_MAX) 00343 NLA_PUT_U32(msg, i, val); 00344 } 00345 00346 nla_nest_end(msg, metrics); 00347 } 00348 00349 #if 0 00350 RTA_IIF, 00351 RTA_MULTIPATH, 00352 RTA_PROTOINFO, 00353 RTA_FLOW, 00354 RTA_CACHEINFO, 00355 RTA_SESSION, 00356 RTA_MP_ALGO, 00357 #endif 00358 00359 return msg; 00360 00361 nla_put_failure: 00362 nlmsg_free(msg); 00363 return NULL; 00364 } 00365 00366 struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) 00367 { 00368 return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); 00369 } 00370 00371 int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, 00372 int flags) 00373 { 00374 struct nl_msg *msg; 00375 int err; 00376 00377 msg = rtnl_route_build_add_request(route, flags); 00378 if (!msg) 00379 return nl_get_errno(); 00380 00381 err = nl_send_auto_complete(handle, msg); 00382 nlmsg_free(msg); 00383 if (err < 0) 00384 return err; 00385 00386 return nl_wait_for_ack(handle); 00387 } 00388 00389 struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) 00390 { 00391 return build_route_msg(tmpl, RTM_DELROUTE, flags); 00392 } 00393 00394 int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, 00395 int flags) 00396 { 00397 struct nl_msg *msg; 00398 int err; 00399 00400 msg = rtnl_route_build_del_request(route, flags); 00401 if (!msg) 00402 return nl_get_errno(); 00403 00404 err = nl_send_auto_complete(handle, msg); 00405 nlmsg_free(msg); 00406 if (err < 0) 00407 return err; 00408 00409 return nl_wait_for_ack(handle); 00410 } 00411 00412 /** @} */ 00413 00414 static struct nl_af_group route_groups[] = { 00415 { AF_INET, RTNLGRP_IPV4_ROUTE }, 00416 { AF_INET6, RTNLGRP_IPV6_ROUTE }, 00417 { AF_DECnet, RTNLGRP_DECnet_ROUTE }, 00418 { END_OF_GROUP_LIST }, 00419 }; 00420 00421 static struct nl_cache_ops rtnl_route_ops = { 00422 .co_name = "route/route", 00423 .co_hdrsize = sizeof(struct rtmsg), 00424 .co_msgtypes = { 00425 { RTM_NEWROUTE, NL_ACT_NEW, "new" }, 00426 { RTM_DELROUTE, NL_ACT_DEL, "del" }, 00427 { RTM_GETROUTE, NL_ACT_GET, "get" }, 00428 END_OF_MSGTYPES_LIST, 00429 }, 00430 .co_protocol = NETLINK_ROUTE, 00431 .co_groups = route_groups, 00432 .co_request_update = route_request_update, 00433 .co_msg_parser = route_msg_parser, 00434 .co_obj_ops = &route_obj_ops, 00435 }; 00436 00437 static void __init route_init(void) 00438 { 00439 nl_cache_mngt_register(&rtnl_route_ops); 00440 } 00441 00442 static void __exit route_exit(void) 00443 { 00444 nl_cache_mngt_unregister(&rtnl_route_ops); 00445 } 00446 00447 /** @} */