route.c revision 3040a1d6254465bed9e44e4d1bf279c2c50cd16a
1/* 2 * lib/route/route.c Routes 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup rtnl 14 * @defgroup route Routing 15 * @brief 16 * @{ 17 */ 18 19#include <netlink-local.h> 20#include <netlink/netlink.h> 21#include <netlink/cache.h> 22#include <netlink/utils.h> 23#include <netlink/data.h> 24#include <netlink/route/rtnl.h> 25#include <netlink/route/route.h> 26#include <netlink/route/link.h> 27 28static struct nl_cache_ops rtnl_route_ops; 29 30static struct nla_policy route_policy[RTA_MAX+1] = { 31 [RTA_IIF] = { .type = NLA_STRING, 32 .maxlen = IFNAMSIZ, }, 33 [RTA_OIF] = { .type = NLA_U32 }, 34 [RTA_PRIORITY] = { .type = NLA_U32 }, 35 [RTA_FLOW] = { .type = NLA_U32 }, 36 [RTA_MP_ALGO] = { .type = NLA_U32 }, 37 [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, 38 [RTA_METRICS] = { .type = NLA_NESTED }, 39 [RTA_MULTIPATH] = { .type = NLA_NESTED }, 40}; 41 42static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, 43 struct rtnl_route *route) 44{ 45 struct rtnl_rtcacheinfo nci = { 46 .rtci_clntref = ci->rta_clntref, 47 .rtci_last_use = ci->rta_lastuse, 48 .rtci_expires = ci->rta_expires, 49 .rtci_error = ci->rta_error, 50 .rtci_used = ci->rta_used, 51 .rtci_id = ci->rta_id, 52 .rtci_ts = ci->rta_ts, 53 .rtci_tsage = ci->rta_tsage, 54 }; 55 56 rtnl_route_set_cacheinfo(route, &nci); 57} 58 59static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 60 struct nlmsghdr *nlh, struct nl_parser_param *pp) 61{ 62 struct rtmsg *rtm; 63 struct rtnl_route *route; 64 struct nlattr *tb[RTA_MAX + 1]; 65 struct nl_addr *src = NULL, *dst = NULL, *addr; 66 int err; 67 68 route = rtnl_route_alloc(); 69 if (!route) { 70 err = nl_errno(ENOMEM); 71 goto errout; 72 } 73 74 route->ce_msgtype = nlh->nlmsg_type; 75 76 err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, 77 route_policy); 78 if (err < 0) 79 goto errout; 80 81 rtm = nlmsg_data(nlh); 82 rtnl_route_set_family(route, rtm->rtm_family); 83 rtnl_route_set_tos(route, rtm->rtm_tos); 84 rtnl_route_set_table(route, rtm->rtm_table); 85 rtnl_route_set_type(route, rtm->rtm_type); 86 rtnl_route_set_scope(route, rtm->rtm_scope); 87 rtnl_route_set_protocol(route, rtm->rtm_protocol); 88 rtnl_route_set_flags(route, rtm->rtm_flags); 89 90 if (tb[RTA_DST]) { 91 dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); 92 if (dst == NULL) 93 goto errout_errno; 94 } else if (rtm->rtm_dst_len) 95 dst = nl_addr_alloc(0); 96 97 if (dst) { 98 nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); 99 rtnl_route_set_dst(route, dst); 100 nl_addr_put(dst); 101 } 102 103 if (tb[RTA_SRC]) { 104 src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); 105 if (src == NULL) 106 goto errout_errno; 107 } else if (rtm->rtm_src_len) 108 src = nl_addr_alloc(0); 109 110 if (src) { 111 nl_addr_set_prefixlen(src, rtm->rtm_src_len); 112 rtnl_route_set_src(route, src); 113 nl_addr_put(src); 114 } 115 116 if (tb[RTA_IIF]) 117 rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); 118 119 if (tb[RTA_OIF]) 120 rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); 121 122 if (tb[RTA_GATEWAY]) { 123 addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); 124 if (addr == NULL) 125 goto errout_errno; 126 rtnl_route_set_gateway(route, addr); 127 nl_addr_put(addr); 128 } 129 130 if (tb[RTA_PRIORITY]) 131 rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); 132 133 if (tb[RTA_PREFSRC]) { 134 addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); 135 if (addr == NULL) 136 goto errout_errno; 137 rtnl_route_set_pref_src(route, addr); 138 nl_addr_put(addr); 139 } 140 141 if (tb[RTA_METRICS]) { 142 struct nlattr *mtb[RTAX_MAX + 1]; 143 int i; 144 145 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); 146 if (err < 0) 147 goto errout; 148 149 for (i = 1; i <= RTAX_MAX; i++) { 150 if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { 151 uint32_t m = nla_get_u32(mtb[i]); 152 if (rtnl_route_set_metric(route, i, m) < 0) 153 goto errout_errno; 154 } 155 } 156 } 157 158 if (tb[RTA_MULTIPATH]) { 159 struct rtnl_nexthop *nh; 160 struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); 161 size_t tlen = nla_len(tb[RTA_MULTIPATH]); 162 163 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { 164 nh = rtnl_route_nh_alloc(); 165 if (!nh) 166 goto errout; 167 168 rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); 169 rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); 170 rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); 171 172 if (rtnh->rtnh_len > sizeof(*rtnh)) { 173 struct nlattr *ntb[RTA_MAX + 1]; 174 nla_parse(ntb, RTA_MAX, (struct nlattr *) 175 RTNH_DATA(rtnh), 176 rtnh->rtnh_len - sizeof(*rtnh), 177 route_policy); 178 179 if (ntb[RTA_GATEWAY]) { 180 nh->rtnh_gateway = nla_get_addr( 181 ntb[RTA_GATEWAY], 182 route->rt_family); 183 nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; 184 } 185 } 186 187 rtnl_route_add_nexthop(route, nh); 188 tlen -= RTNH_ALIGN(rtnh->rtnh_len); 189 rtnh = RTNH_NEXT(rtnh); 190 } 191 } 192 193 if (tb[RTA_FLOW]) 194 rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); 195 196 if (tb[RTA_CACHEINFO]) 197 copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); 198 199 if (tb[RTA_MP_ALGO]) 200 rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); 201 202 err = pp->pp_cb((struct nl_object *) route, pp); 203 if (err < 0) 204 goto errout; 205 206 return P_ACCEPT; 207 208errout_errno: 209 err = nl_get_errno(); 210errout: 211 rtnl_route_put(route); 212 return err; 213 214} 215 216static int route_request_update(struct nl_cache *c, struct nl_handle *h) 217{ 218 return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); 219} 220 221/** 222 * @name Cache Management 223 * @{ 224 */ 225 226/** 227 * Build a route cache holding all routes currently configured in the kernel 228 * @arg handle netlink handle 229 * 230 * Allocates a new cache, initializes it properly and updates it to 231 * contain all routes currently configured in the kernel. 232 * 233 * @note The caller is responsible for destroying and freeing the 234 * cache after using it. 235 * @return The cache or NULL if an error has occured. 236 */ 237struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) 238{ 239 struct nl_cache *cache; 240 241 cache = nl_cache_alloc(&rtnl_route_ops); 242 if (!cache) 243 return NULL; 244 245 if (handle && nl_cache_refill(handle, cache) < 0) { 246 free(cache); 247 return NULL; 248 } 249 250 return cache; 251} 252 253/** @} */ 254 255/** 256 * @name Route Addition 257 * @{ 258 */ 259 260static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, 261 int flags) 262{ 263 struct nl_msg *msg; 264 struct nl_addr *addr; 265 int scope, i, oif, nmetrics = 0; 266 struct nlattr *metrics; 267 struct rtmsg rtmsg = { 268 .rtm_family = rtnl_route_get_family(tmpl), 269 .rtm_dst_len = rtnl_route_get_dst_len(tmpl), 270 .rtm_src_len = rtnl_route_get_src_len(tmpl), 271 .rtm_tos = rtnl_route_get_tos(tmpl), 272 .rtm_table = rtnl_route_get_table(tmpl), 273 .rtm_type = rtnl_route_get_type(tmpl), 274 .rtm_protocol = rtnl_route_get_protocol(tmpl), 275 .rtm_flags = rtnl_route_get_flags(tmpl), 276 }; 277 278 if (rtmsg.rtm_family == AF_UNSPEC) { 279 nl_error(EINVAL, "Cannot build route message, address " \ 280 "family is unknown."); 281 return NULL; 282 } 283 284 scope = rtnl_route_get_scope(tmpl); 285 if (scope == RT_SCOPE_NOWHERE) { 286 if (rtmsg.rtm_type == RTN_LOCAL) 287 scope = RT_SCOPE_HOST; 288 else { 289 /* XXX Change to UNIVERSE if gw || nexthops */ 290 scope = RT_SCOPE_LINK; 291 } 292 } 293 294 rtmsg.rtm_scope = scope; 295 296 msg = nlmsg_alloc_simple(cmd, flags); 297 if (msg == NULL) 298 return NULL; 299 300 if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) 301 goto nla_put_failure; 302 303 addr = rtnl_route_get_dst(tmpl); 304 if (addr) 305 NLA_PUT_ADDR(msg, RTA_DST, addr); 306 307 addr = rtnl_route_get_src(tmpl); 308 if (addr) 309 NLA_PUT_ADDR(msg, RTA_SRC, addr); 310 311 addr = rtnl_route_get_gateway(tmpl); 312 if (addr) 313 NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); 314 315 addr = rtnl_route_get_pref_src(tmpl); 316 if (addr) 317 NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); 318 319 NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); 320 321 oif = rtnl_route_get_oif(tmpl); 322 if (oif != RTNL_LINK_NOT_FOUND) 323 NLA_PUT_U32(msg, RTA_OIF, oif); 324 325 for (i = 1; i <= RTAX_MAX; i++) 326 if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) 327 nmetrics++; 328 329 if (nmetrics > 0) { 330 unsigned int val; 331 332 metrics = nla_nest_start(msg, RTA_METRICS); 333 if (metrics == NULL) 334 goto nla_put_failure; 335 336 for (i = 1; i <= RTAX_MAX; i++) { 337 val = rtnl_route_get_metric(tmpl, i); 338 if (val != UINT_MAX) 339 NLA_PUT_U32(msg, i, val); 340 } 341 342 nla_nest_end(msg, metrics); 343 } 344 345#if 0 346 RTA_IIF, 347 RTA_MULTIPATH, 348 RTA_PROTOINFO, 349 RTA_FLOW, 350 RTA_CACHEINFO, 351 RTA_SESSION, 352 RTA_MP_ALGO, 353#endif 354 355 return msg; 356 357nla_put_failure: 358 nlmsg_free(msg); 359 return NULL; 360} 361 362struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) 363{ 364 return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); 365} 366 367int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, 368 int flags) 369{ 370 struct nl_msg *msg; 371 int err; 372 373 msg = rtnl_route_build_add_request(route, flags); 374 if (!msg) 375 return nl_get_errno(); 376 377 err = nl_send_auto_complete(handle, msg); 378 nlmsg_free(msg); 379 if (err < 0) 380 return err; 381 382 return nl_wait_for_ack(handle); 383} 384 385struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) 386{ 387 return build_route_msg(tmpl, RTM_DELROUTE, flags); 388} 389 390int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, 391 int flags) 392{ 393 struct nl_msg *msg; 394 int err; 395 396 msg = rtnl_route_build_del_request(route, flags); 397 if (!msg) 398 return nl_get_errno(); 399 400 err = nl_send_auto_complete(handle, msg); 401 nlmsg_free(msg); 402 if (err < 0) 403 return err; 404 405 return nl_wait_for_ack(handle); 406} 407 408/** @} */ 409 410static struct nl_af_group route_groups[] = { 411 { AF_INET, RTNLGRP_IPV4_ROUTE }, 412 { AF_INET6, RTNLGRP_IPV6_ROUTE }, 413 { AF_DECnet, RTNLGRP_DECnet_ROUTE }, 414 { END_OF_GROUP_LIST }, 415}; 416 417static struct nl_cache_ops rtnl_route_ops = { 418 .co_name = "route/route", 419 .co_hdrsize = sizeof(struct rtmsg), 420 .co_msgtypes = { 421 { RTM_NEWROUTE, NL_ACT_NEW, "new" }, 422 { RTM_DELROUTE, NL_ACT_DEL, "del" }, 423 { RTM_GETROUTE, NL_ACT_GET, "get" }, 424 END_OF_MSGTYPES_LIST, 425 }, 426 .co_protocol = NETLINK_ROUTE, 427 .co_groups = route_groups, 428 .co_request_update = route_request_update, 429 .co_msg_parser = route_msg_parser, 430 .co_obj_ops = &route_obj_ops, 431}; 432 433static void __init route_init(void) 434{ 435 nl_cache_mngt_register(&rtnl_route_ops); 436} 437 438static void __exit route_exit(void) 439{ 440 nl_cache_mngt_unregister(&rtnl_route_ops); 441} 442 443/** @} */ 444