summaryrefslogtreecommitdiffstats
path: root/lib/route/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route/route.c')
-rw-r--r--lib/route/route.c354
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);
}
/** @} */