libnl 1.1

lib/route/route.c

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 /** @} */