diff options
Diffstat (limited to 'lib/route/route.c')
-rw-r--r-- | lib/route/route.c | 354 |
1 files changed, 54 insertions, 300 deletions
diff --git a/lib/route/route.c b/lib/route/route.c index 0644bd7..c85c225 100644 --- a/lib/route/route.c +++ b/lib/route/route.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -27,199 +27,31 @@ static struct nl_cache_ops rtnl_route_ops; -static struct nla_policy route_policy[RTA_MAX+1] = { - [RTA_IIF] = { .type = NLA_STRING, - .maxlen = IFNAMSIZ, }, - [RTA_OIF] = { .type = NLA_U32 }, - [RTA_PRIORITY] = { .type = NLA_U32 }, - [RTA_FLOW] = { .type = NLA_U32 }, - [RTA_MP_ALGO] = { .type = NLA_U32 }, - [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, - [RTA_METRICS] = { .type = NLA_NESTED }, - [RTA_MULTIPATH] = { .type = NLA_NESTED }, -}; - -static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, - struct rtnl_route *route) -{ - struct rtnl_rtcacheinfo nci = { - .rtci_clntref = ci->rta_clntref, - .rtci_last_use = ci->rta_lastuse, - .rtci_expires = ci->rta_expires, - .rtci_error = ci->rta_error, - .rtci_used = ci->rta_used, - .rtci_id = ci->rta_id, - .rtci_ts = ci->rta_ts, - .rtci_tsage = ci->rta_tsage, - }; - - rtnl_route_set_cacheinfo(route, &nci); -} - static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *nlh, struct nl_parser_param *pp) { - struct rtmsg *rtm; struct rtnl_route *route; - struct nlattr *tb[RTA_MAX + 1]; - struct nl_addr *src = NULL, *dst = NULL, *addr; int err; - route = rtnl_route_alloc(); - if (!route) { - err = nl_errno(ENOMEM); - goto errout; - } - - route->ce_msgtype = nlh->nlmsg_type; - - err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, - route_policy); - if (err < 0) - goto errout; - - rtm = nlmsg_data(nlh); - rtnl_route_set_family(route, rtm->rtm_family); - rtnl_route_set_tos(route, rtm->rtm_tos); - rtnl_route_set_table(route, rtm->rtm_table); - rtnl_route_set_type(route, rtm->rtm_type); - rtnl_route_set_scope(route, rtm->rtm_scope); - rtnl_route_set_protocol(route, rtm->rtm_protocol); - rtnl_route_set_flags(route, rtm->rtm_flags); - - if (tb[RTA_DST]) { - dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); - if (dst == NULL) - goto errout_errno; - } else { - dst = nl_addr_alloc(0); - nl_addr_set_family(dst, rtm->rtm_family); - } - - nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); - err = rtnl_route_set_dst(route, dst); - if (err < 0) - goto errout; - - nl_addr_put(dst); - - if (tb[RTA_SRC]) { - src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); - if (src == NULL) - goto errout_errno; - } else if (rtm->rtm_src_len) - src = nl_addr_alloc(0); - - if (src) { - nl_addr_set_prefixlen(src, rtm->rtm_src_len); - rtnl_route_set_src(route, src); - nl_addr_put(src); - } - - if (tb[RTA_IIF]) - rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); - - if (tb[RTA_OIF]) - rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); - - if (tb[RTA_GATEWAY]) { - addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); - if (addr == NULL) - goto errout_errno; - rtnl_route_set_gateway(route, addr); - nl_addr_put(addr); - } - - if (tb[RTA_PRIORITY]) - rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); - - if (tb[RTA_PREFSRC]) { - addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); - if (addr == NULL) - goto errout_errno; - rtnl_route_set_pref_src(route, addr); - nl_addr_put(addr); - } - - if (tb[RTA_METRICS]) { - struct nlattr *mtb[RTAX_MAX + 1]; - int i; - - err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); - if (err < 0) - goto errout; - - for (i = 1; i <= RTAX_MAX; i++) { - if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { - uint32_t m = nla_get_u32(mtb[i]); - if (rtnl_route_set_metric(route, i, m) < 0) - goto errout_errno; - } - } - } - - if (tb[RTA_MULTIPATH]) { - struct rtnl_nexthop *nh; - struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); - size_t tlen = nla_len(tb[RTA_MULTIPATH]); - - while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { - nh = rtnl_route_nh_alloc(); - if (!nh) - goto errout; - - rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); - rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); - rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); - - if (rtnh->rtnh_len > sizeof(*rtnh)) { - struct nlattr *ntb[RTA_MAX + 1]; - nla_parse(ntb, RTA_MAX, (struct nlattr *) - RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof(*rtnh), - route_policy); - - if (ntb[RTA_GATEWAY]) { - nh->rtnh_gateway = nla_get_addr( - ntb[RTA_GATEWAY], - route->rt_family); - nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; - } - } - - rtnl_route_add_nexthop(route, nh); - tlen -= RTNH_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); - } - } - - if (tb[RTA_FLOW]) - rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); - - if (tb[RTA_CACHEINFO]) - copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); - - if (tb[RTA_MP_ALGO]) - rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); + if ((err = rtnl_route_parse(nlh, &route)) < 0) + return err; err = pp->pp_cb((struct nl_object *) route, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; -errout: rtnl_route_put(route); return err; - -errout_errno: - err = nl_get_errno(); - goto errout; } -static int route_request_update(struct nl_cache *c, struct nl_handle *h) +static int route_request_update(struct nl_cache *c, struct nl_sock *h) { - return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); + struct rtmsg rhdr = { + .rtm_family = c->c_iarg1, + }; + + if (c->c_iarg2 & ROUTE_CACHE_CONTENT) + rhdr.rtm_flags |= RTM_F_CLONED; + + return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr)); } /** @@ -229,7 +61,9 @@ static int route_request_update(struct nl_cache *c, struct nl_handle *h) /** * Build a route cache holding all routes currently configured in the kernel - * @arg handle netlink handle + * @arg sk Netlink socket. + * @arg family Address family of routes to cover or AF_UNSPEC + * @arg flags Flags * * Allocates a new cache, initializes it properly and updates it to * contain all routes currently configured in the kernel. @@ -238,20 +72,25 @@ static int route_request_update(struct nl_cache *c, struct nl_handle *h) * cache after using it. * @return The cache or NULL if an error has occured. */ -struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) +int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags, + struct nl_cache **result) { struct nl_cache *cache; + int err; - cache = nl_cache_alloc(&rtnl_route_ops); - if (!cache) - return NULL; + if (!(cache = nl_cache_alloc(&rtnl_route_ops))) + return -NLE_NOMEM; - if (handle && nl_cache_refill(handle, cache) < 0) { + cache->c_iarg1 = family; + cache->c_iarg2 = flags; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { free(cache); - return NULL; + return err; } - return cache; + *result = cache; + return 0; } /** @} */ @@ -261,152 +100,67 @@ struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) * @{ */ -static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, - int flags) +static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags, + struct nl_msg **result) { struct nl_msg *msg; - struct nl_addr *addr; - int scope, i, oif, nmetrics = 0; - struct nlattr *metrics; - struct rtmsg rtmsg = { - .rtm_family = rtnl_route_get_family(tmpl), - .rtm_dst_len = rtnl_route_get_dst_len(tmpl), - .rtm_src_len = rtnl_route_get_src_len(tmpl), - .rtm_tos = rtnl_route_get_tos(tmpl), - .rtm_table = rtnl_route_get_table(tmpl), - .rtm_type = rtnl_route_get_type(tmpl), - .rtm_protocol = rtnl_route_get_protocol(tmpl), - .rtm_flags = rtnl_route_get_flags(tmpl), - }; - - if (rtmsg.rtm_family == AF_UNSPEC) { - nl_error(EINVAL, "Cannot build route message, address " \ - "family is unknown."); - return NULL; - } - - scope = rtnl_route_get_scope(tmpl); - if (scope == RT_SCOPE_NOWHERE) { - if (rtmsg.rtm_type == RTN_LOCAL) - scope = RT_SCOPE_HOST; - else { - /* XXX Change to UNIVERSE if gw || nexthops */ - scope = RT_SCOPE_LINK; - } - } - - rtmsg.rtm_scope = scope; - - msg = nlmsg_alloc_simple(cmd, flags); - if (msg == NULL) - return NULL; - - if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) - goto nla_put_failure; - - addr = rtnl_route_get_dst(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_DST, addr); - - addr = rtnl_route_get_src(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_SRC, addr); - - addr = rtnl_route_get_gateway(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); - - addr = rtnl_route_get_pref_src(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); - - NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); - - oif = rtnl_route_get_oif(tmpl); - if (oif != RTNL_LINK_NOT_FOUND) - NLA_PUT_U32(msg, RTA_OIF, oif); - - for (i = 1; i <= RTAX_MAX; i++) - if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) - nmetrics++; - - if (nmetrics > 0) { - unsigned int val; - - metrics = nla_nest_start(msg, RTA_METRICS); - if (metrics == NULL) - goto nla_put_failure; + int err; - for (i = 1; i <= RTAX_MAX; i++) { - val = rtnl_route_get_metric(tmpl, i); - if (val != UINT_MAX) - NLA_PUT_U32(msg, i, val); - } + if (!(msg = nlmsg_alloc_simple(cmd, flags))) + return -NLE_NOMEM; - nla_nest_end(msg, metrics); + if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) { + nlmsg_free(msg); + return err; } -#if 0 - RTA_IIF, - RTA_MULTIPATH, - RTA_PROTOINFO, - RTA_FLOW, - RTA_CACHEINFO, - RTA_SESSION, - RTA_MP_ALGO, -#endif - - return msg; - -nla_put_failure: - nlmsg_free(msg); - return NULL; + *result = msg; + return 0; } -struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) +int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags, + struct nl_msg **result) { - return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); + return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags, + result); } -int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, - int flags) +int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; - msg = rtnl_route_build_add_request(route, flags); - if (!msg) - return nl_get_errno(); + if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } -struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) +int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags, + struct nl_msg **result) { - return build_route_msg(tmpl, RTM_DELROUTE, flags); + return build_route_msg(tmpl, RTM_DELROUTE, flags, result); } -int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, - int flags) +int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; - msg = rtnl_route_build_del_request(route, flags); - if (!msg) - return nl_get_errno(); + if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ |