diff options
author | Thomas Graf <tgr@lsx.localdomain> | 2008-04-29 21:31:30 (GMT) |
---|---|---|
committer | Thomas Graf <tgr@lsx.localdomain> | 2008-04-29 21:31:30 (GMT) |
commit | 535e83162249ed6274ba46bc72d8cc683ba20e17 (patch) | |
tree | fa3b60b4116668b86d23c11b695ff371d771b997 /lib/route | |
parent | 8ac78f1552fa6b6340776513c8a7c36f7b72e498 (diff) | |
download | libnl-535e83162249ed6274ba46bc72d8cc683ba20e17.zip libnl-535e83162249ed6274ba46bc72d8cc683ba20e17.tar.gz libnl-535e83162249ed6274ba46bc72d8cc683ba20e17.tar.bz2 |
Big routing code rework (API/ABI BREAK!)
Adds all missing routing attributes and brings the routing
related code to a working state. In the process the API
was broken several times with the justification that nobody
is using this code yet.
The changes include new example code which is also a prototype
for how plain CLI tools could look like to control routes.
Diffstat (limited to 'lib/route')
-rw-r--r-- | lib/route/addr.c | 2 | ||||
-rw-r--r-- | lib/route/link.c | 2 | ||||
-rw-r--r-- | lib/route/neigh.c | 2 | ||||
-rw-r--r-- | lib/route/nexthop.c | 235 | ||||
-rw-r--r-- | lib/route/route.c | 274 | ||||
-rw-r--r-- | lib/route/route_obj.c | 974 | ||||
-rw-r--r-- | lib/route/route_utils.c | 23 | ||||
-rw-r--r-- | lib/route/rule.c | 4 |
8 files changed, 821 insertions, 695 deletions
diff --git a/lib/route/addr.c b/lib/route/addr.c index b8ec56c..a4a9acf 100644 --- a/lib/route/addr.c +++ b/lib/route/addr.c @@ -585,7 +585,7 @@ static int addr_compare(struct nl_object *_a, struct nl_object *_b, b->a_multicast)); diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast)); - if (flags & LOOSE_FLAG_COMPARISON) + if (flags & LOOSE_COMPARISON) diff |= ADDR_DIFF(FLAGS, (a->a_flags ^ b->a_flags) & b->a_flag_mask); else diff --git a/lib/route/link.c b/lib/route/link.c index 75031d4..13d3e93 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -795,7 +795,7 @@ static int link_compare(struct nl_object *_a, struct nl_object *_b, diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); - if (flags & LOOSE_FLAG_COMPARISON) + if (flags & LOOSE_COMPARISON) diff |= LINK_DIFF(FLAGS, (a->l_flags ^ b->l_flags) & b->l_flag_mask); else diff --git a/lib/route/neigh.c b/lib/route/neigh.c index 6f2f0d3..fa1dc59 100644 --- a/lib/route/neigh.c +++ b/lib/route/neigh.c @@ -213,7 +213,7 @@ static int neigh_compare(struct nl_object *_a, struct nl_object *_b, diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr)); diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst)); - if (flags & LOOSE_FLAG_COMPARISON) { + if (flags & LOOSE_COMPARISON) { diff |= NEIGH_DIFF(STATE, (a->n_state ^ b->n_state) & b->n_state_mask); diff |= NEIGH_DIFF(FLAGS, diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c index 7486769..2db6d90 100644 --- a/lib/route/nexthop.c +++ b/lib/route/nexthop.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> */ /** @@ -21,6 +21,14 @@ #include <netlink/route/rtnl.h> #include <netlink/route/route.h> +/** @cond SKIP */ +#define NH_ATTR_FLAGS 0x000001 +#define NH_ATTR_WEIGHT 0x000002 +#define NH_ATTR_IFINDEX 0x000004 +#define NH_ATTR_GATEWAY 0x000008 +#define NH_ATTR_REALMS 0x000010 +/** @endcond */ + /** * @name Allocation/Freeing * @{ @@ -53,7 +61,7 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src) nh->rtnh_flag_mask = src->rtnh_flag_mask; nh->rtnh_weight = src->rtnh_weight; nh->rtnh_ifindex = src->rtnh_ifindex; - nh->rtnh_mask = src->rtnh_mask; + nh->ce_mask = src->ce_mask; if (src->rtnh_gateway) { nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway); @@ -74,78 +82,251 @@ void rtnl_route_nh_free(struct rtnl_nexthop *nh) /** @} */ +int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, + uint32_t attrs, int loose) +{ + int diff = 0; + +#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR) + + diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex); + diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight); + diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms); + diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway, + b->rtnh_gateway)); + + if (loose) + diff |= NH_DIFF(FLAGS, + (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask); + else + diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags); + +#undef NH_DIFF + + return diff; +} + +static void nh_dump_oneline(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump(dp, "via"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway, + buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump(dp, " dev %s", + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump(dp, " dev %d", nh->rtnh_ifindex); + } + + nl_dump(dp, " "); +} + +static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump(dp, "nexthop"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, + buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump(dp, " dev %s", + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump(dp, " dev %d", nh->rtnh_ifindex); + } + + if (nh->ce_mask & NH_ATTR_WEIGHT) + nl_dump(dp, " weight %u", nh->rtnh_weight); + + if (nh->ce_mask & NH_ATTR_REALMS) + nl_dump(dp, " realm %04x:%04x", + RTNL_REALM_FROM(nh->rtnh_realms), + RTNL_REALM_TO(nh->rtnh_realms)); + + if (nh->ce_mask & NH_ATTR_FLAGS) + nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags, + buf, sizeof(buf))); +} + +static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar, + nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar, + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar, + nh->rtnh_ifindex); + } + + if (nh->ce_mask & NH_ATTR_WEIGHT) + nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar, + nh->rtnh_weight); + + if (nh->ce_mask & NH_ATTR_REALMS) + nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar, + RTNL_REALM_FROM(nh->rtnh_realms), + RTNL_REALM_TO(nh->rtnh_realms)); + + if (nh->ce_mask & NH_ATTR_FLAGS) + nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar, + rtnl_route_nh_flags2str(nh->rtnh_flags, + buf, sizeof(buf))); +} +void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + switch (dp->dp_type) { + case NL_DUMP_ONELINE: + nh_dump_oneline(nh, dp); + break; + + case NL_DUMP_DETAILS: + case NL_DUMP_STATS: + if (dp->dp_ivar == NH_DUMP_FROM_DETAILS) + nh_dump_details(nh, dp); + break; + + case NL_DUMP_ENV: + nh_dump_env(nh, dp); + break; + + default: + break; + } +} + /** * @name Attributes + * @{ */ -void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, int weight) +void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight) { nh->rtnh_weight = weight; - nh->rtnh_mask |= NEXTHOP_HAS_WEIGHT; + nh->ce_mask |= NH_ATTR_WEIGHT; } -int rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) +uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_WEIGHT) - return nh->rtnh_weight; - else - return 0; + return nh->rtnh_weight; } void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex) { nh->rtnh_ifindex = ifindex; - nh->rtnh_mask |= NEXTHOP_HAS_IFINDEX; + nh->ce_mask |= NH_ATTR_IFINDEX; } int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_IFINDEX) - return nh->rtnh_ifindex; - else - return -1; + return nh->rtnh_ifindex; } void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr) { struct nl_addr *old = nh->rtnh_gateway; - nh->rtnh_gateway = nl_addr_get(addr); + if (addr) { + nh->rtnh_gateway = nl_addr_get(addr); + nh->ce_mask |= NH_ATTR_GATEWAY; + } else { + nh->ce_mask &= ~NH_ATTR_GATEWAY; + nh->rtnh_gateway = NULL; + } + if (old) nl_addr_put(old); - - nh->rtnh_mask |= NEXTHOP_HAS_GATEWAY; } struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY) - return nh->rtnh_gateway; - else - return NULL; + return nh->rtnh_gateway; } void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags) { nh->rtnh_flag_mask |= flags; nh->rtnh_flags |= flags; - nh->rtnh_mask |= NEXTHOP_HAS_FLAGS; + nh->ce_mask |= NH_ATTR_FLAGS; } void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags) { nh->rtnh_flag_mask |= flags; nh->rtnh_flags &= ~flags; - nh->rtnh_mask |= NEXTHOP_HAS_FLAGS; + nh->ce_mask |= NH_ATTR_FLAGS; } unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_FLAGS) - return nh->rtnh_flags; - else - return 0; + return nh->rtnh_flags; +} + +void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms) +{ + nh->rtnh_realms = realms; + nh->ce_mask |= NH_ATTR_REALMS; +} + +uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh) +{ + return nh->rtnh_realms; +} + +/** @} */ + +/** + * @name Nexthop Flags Translations + * @{ + */ + +static struct trans_tbl nh_flags[] = { + __ADD(RTNH_F_DEAD, dead) + __ADD(RTNH_F_PERVASIVE, pervasive) + __ADD(RTNH_F_ONLINK, onlink) +}; + +char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); +} + +int rtnl_route_nh_str2flags(const char *name) +{ + return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); } /** @} */ + /** @} */ diff --git a/lib/route/route.c b/lib/route/route.c index 0644bd7..9edaddc 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,183 +27,16 @@ 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; + if (!(route = rtnl_route_parse(nlh))) + return -EINVAL; - 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])); - - err = pp->pp_cb((struct nl_object *) route, pp); - if (err < 0) + if ((err = pp->pp_cb((struct nl_object *) route, pp)) < 0) goto errout; err = P_ACCEPT; @@ -211,10 +44,6 @@ static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 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) @@ -265,102 +94,17 @@ static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, int flags) { 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; - - for (i = 1; i <= RTAX_MAX; i++) { - val = rtnl_route_get_metric(tmpl, i); - if (val != UINT_MAX) - NLA_PUT_U32(msg, i, val); - } - - nla_nest_end(msg, metrics); + if (rtnl_route_build_msg(msg, tmpl) < 0) { + nlmsg_free(msg); + return NULL; } -#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; } struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) @@ -391,8 +135,8 @@ struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) return build_route_msg(tmpl, RTM_DELROUTE, flags); } -int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, - int flags) +int rtnl_route_delete(struct nl_handle *handle, struct rtnl_route *route, + int flags) { struct nl_msg *msg; int err; diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c index 78e7712..8792c10 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.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> */ /** @@ -20,14 +20,11 @@ * routing table RT_TABLE_MAIN * scope RT_SCOPE_NOWHERE * tos 0 - * realms 0 * protocol RTPROT_STATIC * prio 0 * family AF_UNSPEC * type RTN_UNICAST - * oif RTNL_LINK_NOT_FOUND * iif NULL - * mpalgo IP_MP_ALG_NONE * @endcode * * @{ @@ -41,6 +38,7 @@ #include <netlink/route/rtnl.h> #include <netlink/route/route.h> #include <netlink/route/link.h> +#include <netlink/route/nexthop.h> /** @cond SKIP */ #define ROUTE_ATTR_FAMILY 0x000001 @@ -61,15 +59,18 @@ #define ROUTE_ATTR_MULTIPATH 0x008000 #define ROUTE_ATTR_REALMS 0x010000 #define ROUTE_ATTR_CACHEINFO 0x020000 -#define ROUTE_ATTR_MP_ALGO 0x040000 /** @endcond */ -static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p); - static void route_constructor(struct nl_object *c) { struct rtnl_route *r = (struct rtnl_route *) c; + r->rt_family = AF_UNSPEC; + r->rt_scope = RT_SCOPE_NOWHERE; + r->rt_table = RT_TABLE_MAIN; + r->rt_protocol = RTPROT_STATIC; + r->rt_type = RTN_UNICAST; + nl_init_list_head(&r->rt_nexthops); } @@ -83,11 +84,10 @@ static void route_free_data(struct nl_object *c) nl_addr_put(r->rt_dst); nl_addr_put(r->rt_src); - nl_addr_put(r->rt_gateway); nl_addr_put(r->rt_pref_src); nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) { - rtnl_route_remove_nexthop(nh); + rtnl_route_remove_nexthop(r, nh); rtnl_route_nh_free(nh); } } @@ -106,10 +106,6 @@ static int route_clone(struct nl_object *_dst, struct nl_object *_src) if (!(dst->rt_src = nl_addr_clone(src->rt_src))) goto errout; - if (src->rt_gateway) - if (!(dst->rt_gateway = nl_addr_clone(src->rt_gateway))) - goto errout; - if (src->rt_pref_src) if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src))) goto errout; @@ -128,7 +124,7 @@ errout: return nl_get_errno(); } -static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p) +static int route_dump_oneline(struct nl_object *a, struct nl_dump_params *p) { struct rtnl_route *r = (struct rtnl_route *) a; struct nl_cache *link_cache; @@ -136,330 +132,203 @@ static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p) link_cache = nl_cache_mngt_require("route/link"); + nl_dump(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf))); + if (!(r->ce_mask & ROUTE_ATTR_DST) || nl_addr_get_len(r->rt_dst) == 0) - dp_dump(p, "default "); + nl_dump(p, "default "); else - dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf))); - - if (r->ce_mask & ROUTE_ATTR_OIF) { - if (link_cache) - dp_dump(p, "dev %s ", - rtnl_link_i2name(link_cache, r->rt_oif, - buf, sizeof(buf))); - else - dp_dump(p, "dev %d ", r->rt_oif); - } + nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf, - sizeof(buf))); - else if (r->ce_mask & ROUTE_ATTR_MULTIPATH) - dp_dump(p, "via nexthops "); + if (r->ce_mask & ROUTE_ATTR_TABLE) + nl_dump(p, "table %s ", + rtnl_route_table2str(r->rt_table, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump(p, "scope %s ", - rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); + if (r->ce_mask & ROUTE_ATTR_TYPE) + nl_dump(p, "type %s ", + nl_rtntype2str(r->rt_type, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0) + nl_dump(p, "tos %#x ", r->rt_tos); + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + p->dp_ivar = NH_DUMP_FROM_ONELINE; + rtnl_route_nh_dump(nh, p); + } + } if (r->ce_mask & ROUTE_ATTR_FLAGS && r->rt_flags) { int flags = r->rt_flags; - dp_dump(p, "<"); + nl_dump(p, "<"); #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \ - flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); } + flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } PRINT_FLAG(DEAD); PRINT_FLAG(ONLINK); PRINT_FLAG(PERVASIVE); #undef PRINT_FLAG #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \ - flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); } + flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } PRINT_FLAG(NOTIFY); PRINT_FLAG(CLONED); PRINT_FLAG(EQUALIZE); PRINT_FLAG(PREFIX); #undef PRINT_FLAG - dp_dump(p, ">"); + nl_dump(p, ">"); } - dp_dump(p, "\n"); + nl_dump(p, "\n"); return 1; } -static int route_dump_full(struct nl_object *a, struct nl_dump_params *p) +static int route_dump_details(struct nl_object *a, struct nl_dump_params *p) { struct rtnl_route *r = (struct rtnl_route *) a; struct nl_cache *link_cache; char buf[128]; - int i, line; + int i; link_cache = nl_cache_mngt_require("route/link"); - line = route_dump_brief(a, p); - if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { - struct rtnl_nexthop *nh; - - nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { - dp_dump_line(p, line++, " via "); - - if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY) - dp_dump(p, "%s ", - nl_addr2str(nh->rtnh_gateway, - buf, sizeof(buf))); - if (link_cache) { - dp_dump(p, "dev %s ", - rtnl_link_i2name(link_cache, - nh->rtnh_ifindex, - buf, sizeof(buf))); - } else - dp_dump(p, "dev %d ", nh->rtnh_ifindex); - - dp_dump(p, "weight %u <%s>\n", nh->rtnh_weight, - rtnl_route_nh_flags2str(nh->rtnh_flags, - buf, sizeof(buf))); - } - } - - dp_dump_line(p, line++, " "); + route_dump_oneline(a, p); + nl_dump_line(p, " "); if (r->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump(p, "preferred-src %s ", + nl_dump(p, "preferred-src %s ", nl_addr2str(r->rt_pref_src, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_TABLE) - dp_dump(p, "table %s ", - rtnl_route_table2str(r->rt_table, buf, sizeof(buf))); - - if (r->ce_mask & ROUTE_ATTR_TYPE) - dp_dump(p, "type %s ", - nl_rtntype2str(r->rt_type, buf, sizeof(buf))); + if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE) + nl_dump(p, "scope %s ", + rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); if (r->ce_mask & ROUTE_ATTR_PRIO) - dp_dump(p, "metric %#x ", r->rt_prio); - - if (r->ce_mask & ROUTE_ATTR_FAMILY) - dp_dump(p, "family %s ", - nl_af2str(r->rt_family, buf, sizeof(buf))); + nl_dump(p, "priority %#x ", r->rt_prio); if (r->ce_mask & ROUTE_ATTR_PROTOCOL) - dp_dump(p, "protocol %s ", + nl_dump(p, "protocol %s ", rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf))); - dp_dump(p, "\n"); - - if ((r->ce_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS | - ROUTE_ATTR_REALMS)) || - ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && - r->rt_cacheinfo.rtci_error)) { - dp_dump_line(p, line++, " "); + if (r->ce_mask & ROUTE_ATTR_IIF) + nl_dump(p, "iif %s ", r->rt_iif); - if (r->ce_mask & ROUTE_ATTR_IIF) - dp_dump(p, "iif %s ", r->rt_iif); + if (r->ce_mask & ROUTE_ATTR_SRC) + nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_SRC) - dp_dump(p, "src %s ", - nl_addr2str(r->rt_src, buf, sizeof(buf))); + nl_dump(p, "\n"); - if (r->ce_mask & ROUTE_ATTR_TOS) - dp_dump(p, "tos %#x ", r->rt_tos); - - if (r->ce_mask & ROUTE_ATTR_REALMS) - dp_dump(p, "realm %04x:%04x ", - RTNL_REALM_FROM(r->rt_realms), - RTNL_REALM_TO(r->rt_realms)); + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; - if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && - r->rt_cacheinfo.rtci_error) - dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error, - strerror(-r->rt_cacheinfo.rtci_error)); + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + nl_dump_line(p, " "); + p->dp_ivar = NH_DUMP_FROM_DETAILS; + rtnl_route_nh_dump(nh, p); + nl_dump(p, "\n"); + } + } - dp_dump(p, "\n"); + if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) { + nl_dump_line(p, " cacheinfo error %d (%s)\n", + r->rt_cacheinfo.rtci_error, + strerror(-r->rt_cacheinfo.rtci_error)); } if (r->ce_mask & ROUTE_ATTR_METRICS) { - dp_dump_line(p, line++, " "); + nl_dump_line(p, " metrics ["); for (i = 0; i < RTAX_MAX; i++) if (r->rt_metrics_mask & (1 << i)) - dp_dump(p, "%s %u ", + nl_dump(p, "%s %u ", rtnl_route_metric2str(i+1, buf, sizeof(buf)), r->rt_metrics[i]); - dp_dump(p, "\n"); + nl_dump(p, "]\n"); } - return line; + return 0; } static int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_route *route = (struct rtnl_route *) obj; - int line; - line = route_dump_full(obj, p); + route_dump_details(obj, p); if (route->ce_mask & ROUTE_ATTR_CACHEINFO) { struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo; - dp_dump_line(p, line++, " used %u refcnt %u ", - ci->rtci_used, ci->rtci_clntref); - dp_dump_line(p, line++, "last-use %us expires %us\n", + + nl_dump_line(p, " used %u refcnt %u last-use %us " + "expires %us\n", + ci->rtci_used, ci->rtci_clntref, ci->rtci_last_use / nl_get_hz(), ci->rtci_expires / nl_get_hz()); } - return line; + return 0; } -static int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p) +static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_route *route = (struct rtnl_route *) obj; char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "<route>\n"); - dp_dump_line(p, line++, " <family>%s</family>\n", + + nl_dump(p, "ROUTE_FAMILY=%s\n", nl_af2str(route->rt_family, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_DST) - dp_dump_line(p, line++, " <dst>%s</dst>\n", + nl_dump_line(p, "ROUTE_DST=%s\n", nl_addr2str(route->rt_dst, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_SRC) - dp_dump_line(p, line++, " <src>%s</src>\n", + nl_dump_line(p, "ROUTE_SRC=%s\n", nl_addr2str(route->rt_src, buf, sizeof(buf))); - if (route->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump_line(p, line++, " <gateway>%s</gateway>\n", - nl_addr2str(route->rt_gateway, buf, sizeof(buf))); - if (route->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump_line(p, line++, " <prefsrc>%s</prefsrc>\n", + nl_dump_line(p, "ROUTE_PREFSRC=%s\n", nl_addr2str(route->rt_pref_src, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_IIF) - dp_dump_line(p, line++, " <iif>%s</iif>\n", route->rt_iif); - - if (route->ce_mask & ROUTE_ATTR_REALMS) - dp_dump_line(p, line++, " <realms>%u</realms>\n", - route->rt_realms); + nl_dump_line(p, "ROUTE_IIF=%s\n", route->rt_iif); if (route->ce_mask & ROUTE_ATTR_TOS) - dp_dump_line(p, line++, " <tos>%u</tos>\n", route->rt_tos); + nl_dump_line(p, "ROUTE_TOS=%u\n", route->rt_tos); if (route->ce_mask & ROUTE_ATTR_TABLE) - dp_dump_line(p, line++, " <table>%u</table>\n", + nl_dump_line(p, "ROUTE_TABLE=%u\n", route->rt_table); if (route->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump_line(p, line++, " <scope>%s</scope>\n", + nl_dump_line(p, "ROUTE_SCOPE=%s\n", rtnl_scope2str(route->rt_scope, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_PRIO) - dp_dump_line(p, line++, " <metric>%u</metric>\n", + nl_dump_line(p, "ROUTE_PRIORITY=%u\n", route->rt_prio); - if (route->ce_mask & ROUTE_ATTR_OIF) { - struct nl_cache *link_cache; - - link_cache = nl_cache_mngt_require("route/link"); - if (link_cache) - dp_dump_line(p, line++, " <oif>%s</oif>\n", - rtnl_link_i2name(link_cache, - route->rt_oif, - buf, sizeof(buf))); - else - dp_dump_line(p, line++, " <oif>%u</oif>\n", - route->rt_oif); - } - if (route->ce_mask & ROUTE_ATTR_TYPE) - dp_dump_line(p, line++, " <type>%s</type>\n", + nl_dump_line(p, "ROUTE_TYPE=%s\n", nl_rtntype2str(route->rt_type, buf, sizeof(buf))); - dp_dump_line(p, line++, "</route>\n"); - -#if 0 - uint8_t rt_protocol; - uint32_t rt_flags; - uint32_t rt_metrics[RTAX_MAX]; - uint32_t rt_metrics_mask; - struct rtnl_nexthop * rt_nexthops; - struct rtnl_rtcacheinfo rt_cacheinfo; - uint32_t rt_mp_algo; - -#endif - - return line; -} - -static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_route *route = (struct rtnl_route *) obj; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n", - nl_af2str(route->rt_family, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_DST) - dp_dump_line(p, line++, "ROUTE_DST=%s\n", - nl_addr2str(route->rt_dst, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_SRC) - dp_dump_line(p, line++, "ROUTE_SRC=%s\n", - nl_addr2str(route->rt_src, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n", - nl_addr2str(route->rt_gateway, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n", - nl_addr2str(route->rt_pref_src, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_IIF) - dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif); - - if (route->ce_mask & ROUTE_ATTR_REALMS) - dp_dump_line(p, line++, "ROUTE_REALM=%u\n", - route->rt_realms); - - if (route->ce_mask & ROUTE_ATTR_TOS) - dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos); - - if (route->ce_mask & ROUTE_ATTR_TABLE) - dp_dump_line(p, line++, "ROUTE_TABLE=%u\n", - route->rt_table); - - if (route->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n", - rtnl_scope2str(route->rt_scope, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_PRIO) - dp_dump_line(p, line++, "ROUTE_METRIC=%u\n", - route->rt_prio); - - if (route->ce_mask & ROUTE_ATTR_OIF) { - struct nl_cache *link_cache; + if (route->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + int index = 1; - dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n", - route->rt_oif); + if (route->rt_nr_nh > 0) + nl_dump_line(p, "ROUTE_NR_NH=%u\n", route->rt_nr_nh); - link_cache = nl_cache_mngt_require("route/link"); - if (link_cache) - dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n", - rtnl_link_i2name(link_cache, - route->rt_oif, - buf, sizeof(buf))); + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + p->dp_ivar = index++; + rtnl_route_nh_dump(nh, p); + } } - if (route->ce_mask & ROUTE_ATTR_TYPE) - dp_dump_line(p, line++, "ROUTE_TYPE=%s\n", - nl_rtntype2str(route->rt_type, buf, sizeof(buf))); - - return line; + return 0; } static int route_compare(struct nl_object *_a, struct nl_object *_b, @@ -467,7 +336,8 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b, { struct rtnl_route *a = (struct rtnl_route *) _a; struct rtnl_route *b = (struct rtnl_route *) _b; - int diff = 0; + struct rtnl_nexthop *nh_a, *nh_b; + int i, diff = 0, found; #define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR) @@ -477,29 +347,96 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b, diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol); diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope); diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type); - diff |= ROUTE_DIFF(OIF, a->rt_oif != b->rt_oif); diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio); - diff |= ROUTE_DIFF(REALMS, a->rt_realms != b->rt_realms); - diff |= ROUTE_DIFF(MP_ALGO, a->rt_mp_algo != b->rt_mp_algo); diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst)); diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src)); - diff |= ROUTE_DIFF(IIF, strcmp(a->rt_iif, b->rt_iif)); + diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif); diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src, b->rt_pref_src)); - diff |= ROUTE_DIFF(GATEWAY, nl_addr_cmp(a->rt_gateway, - b->rt_gateway)); - /* FIXME: Compare metrics, multipath config */ + if (flags & LOOSE_COMPARISON) { + nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_a, &a->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, + nh_b->ce_mask, 1)) { + found = 1; + break; + } + } + + if (!found) + goto nh_mismatch; + } + + for (i = 1; i < RTAX_MAX; i++) { + uint32_t val_a, val_b; + + if (!rtnl_route_get_metric(a, i, &val_a)) { + if (rtnl_route_get_metric(b, i, &val_b) != 0 || + val_a != val_b) + ROUTE_DIFF(METRICS, 1); + } + } - if (flags & LOOSE_FLAG_COMPARISON) diff |= ROUTE_DIFF(FLAGS, (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask); - else + } else { + if (a->rt_nr_nh != a->rt_nr_nh) + goto nh_mismatch; + + /* search for a dup in each nh of a */ + nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_b, &b->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) + found = 1; + break; + } + if (!found) + goto nh_mismatch; + } + + /* search for a dup in each nh of b, covers case where a has + * dupes itself */ + nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_a, &a->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) + found = 1; + break; + } + if (!found) + goto nh_mismatch; + } + + for (i = 1; i < RTAX_MAX; i++) { + int avail_a, avail_b; + uint32_t val_a, val_b; + + avail_a = rtnl_route_get_metric(a, i, &val_a); + avail_b = rtnl_route_get_metric(b, i, &val_b); + + if (avail_a ^ avail_b) + diff |= ROUTE_DIFF(METRICS, 1); + else + diff |= ROUTE_DIFF(METRICS, val_a != val_b); + } + diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags); - -#undef ROUTE_DIFF + } +out: return diff; + +nh_mismatch: + diff |= ROUTE_DIFF(MULTIPATH, 1); + goto out; + +#undef ROUTE_DIFF } static struct trans_tbl route_attrs[] = { @@ -521,7 +458,6 @@ static struct trans_tbl route_attrs[] = { __ADD(ROUTE_ATTR_MULTIPATH, multipath) __ADD(ROUTE_ATTR_REALMS, realms) __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo) - __ADD(ROUTE_ATTR_MP_ALGO, mp_algo) }; static char *route_attrs2str(int attrs, char *buf, size_t len) @@ -557,93 +493,76 @@ void rtnl_route_put(struct rtnl_route *route) * @{ */ -void rtnl_route_set_table(struct rtnl_route *route, int table) +void rtnl_route_set_table(struct rtnl_route *route, uint32_t table) { route->rt_table = table; route->ce_mask |= ROUTE_ATTR_TABLE; } -int rtnl_route_get_table(struct rtnl_route *route) +uint32_t rtnl_route_get_table(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_TABLE) - return route->rt_table; - else - return RT_TABLE_MAIN; + return route->rt_table; } -void rtnl_route_set_scope(struct rtnl_route *route, int scope) +void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope) { route->rt_scope = scope; route->ce_mask |= ROUTE_ATTR_SCOPE; } -int rtnl_route_get_scope(struct rtnl_route *route) +uint8_t rtnl_route_get_scope(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_SCOPE) - return route->rt_scope; - else - return RT_SCOPE_NOWHERE; + return route->rt_scope; } -void rtnl_route_set_tos(struct rtnl_route *route, int tos) +void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos) { route->rt_tos = tos; route->ce_mask |= ROUTE_ATTR_TOS; } -int rtnl_route_get_tos(struct rtnl_route *route) +uint8_t rtnl_route_get_tos(struct rtnl_route *route) { return route->rt_tos; } -void rtnl_route_set_realms(struct rtnl_route *route, realm_t realms) +void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol) { - route->rt_realms = realms; - route->ce_mask |= ROUTE_ATTR_REALMS; -} - -realm_t rtnl_route_get_realms(struct rtnl_route *route) -{ - return route->rt_realms; -} - -void rtnl_route_set_protocol(struct rtnl_route *route, int proto) -{ - route->rt_protocol = proto; + route->rt_protocol = protocol; route->ce_mask |= ROUTE_ATTR_PROTOCOL; } -int rtnl_route_get_protocol(struct rtnl_route *route) +uint8_t rtnl_route_get_protocol(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_PROTOCOL) - return route->rt_protocol; - else - return RTPROT_STATIC; + return route->rt_protocol; } -void rtnl_route_set_prio(struct rtnl_route *route, int prio) +void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio) { route->rt_prio = prio; route->ce_mask |= ROUTE_ATTR_PRIO; } -int rtnl_route_get_prio(struct rtnl_route *route) +uint32_t rtnl_route_get_priority(struct rtnl_route *route) { return route->rt_prio; } -void rtnl_route_set_family(struct rtnl_route *route, int family) +int rtnl_route_set_family(struct rtnl_route *route, uint8_t family) { + if (family != AF_INET && family != AF_INET6 && family != AF_DECnet) + return nl_error(EINVAL, "Unsupported address family, " + "supported: { INET | INET6 | DECnet }"); + route->rt_family = family; route->ce_mask |= ROUTE_ATTR_FAMILY; + + return 0; } -int rtnl_route_get_family(struct rtnl_route *route) +uint8_t rtnl_route_get_family(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_FAMILY) - return route->rt_family; - else - return AF_UNSPEC; + return route->rt_family; } int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr) @@ -670,16 +589,12 @@ struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route) return route->rt_dst; } -int rtnl_route_get_dst_len(struct rtnl_route *route) -{ - if (route->ce_mask & ROUTE_ATTR_DST) - return nl_addr_get_prefixlen(route->rt_dst); - else - return 0; -} - int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr) { + if (addr->a_family == AF_INET) + return nl_error(EINVAL, "IPv4 does not support source based " + "routing."); + if (route->ce_mask & ROUTE_ATTR_FAMILY) { if (addr->a_family != route->rt_family) return nl_error(EINVAL, "Address family mismatch"); @@ -701,66 +616,37 @@ struct nl_addr *rtnl_route_get_src(struct rtnl_route *route) return route->rt_src; } -int rtnl_route_get_src_len(struct rtnl_route *route) -{ - if (route->ce_mask & ROUTE_ATTR_SRC) - return nl_addr_get_prefixlen(route->rt_src); - else - return 0; -} - -int rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr) -{ - if (route->ce_mask & ROUTE_ATTR_FAMILY) { - if (addr->a_family != route->rt_family) - return nl_error(EINVAL, "Address family mismatch"); - } else - route->rt_family = addr->a_family; - - if (route->rt_gateway) - nl_addr_put(route->rt_gateway); - - nl_addr_get(addr); - route->rt_gateway = addr; - route->ce_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY); - - return 0; -} - -struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route) -{ - return route->rt_gateway; -} - -void rtnl_route_set_type(struct rtnl_route *route, int type) +int rtnl_route_set_type(struct rtnl_route *route, uint8_t type) { + if (type > RTN_MAX) + return nl_error(ERANGE, "Invalid route type %d, valid range " + "is 0..%d", type, RTN_MAX); route->rt_type = type; route->ce_mask |= ROUTE_ATTR_TYPE; + + return 0; } -int rtnl_route_get_type(struct rtnl_route *route) +uint8_t rtnl_route_get_type(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_TYPE) - return route->rt_type; - else - return RTN_UNICAST; + return route->rt_type; } -void rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags) +void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags) { route->rt_flag_mask |= flags; route->rt_flags |= flags; route->ce_mask |= ROUTE_ATTR_FLAGS; } -void rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags) +void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags) { route->rt_flag_mask |= flags; route->rt_flags &= ~flags; route->ce_mask |= ROUTE_ATTR_FLAGS; } -unsigned int rtnl_route_get_flags(struct rtnl_route *route) +uint32_t rtnl_route_get_flags(struct rtnl_route *route) { return route->rt_flags; } @@ -772,7 +658,13 @@ int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value) RTAX_MAX); route->rt_metrics[metric - 1] = value; - route->rt_metrics_mask |= (1 << (metric - 1)); + + if (!(route->rt_metrics_mask & (1 << (metric - 1)))) { + route->rt_nmetrics++; + route->rt_metrics_mask |= (1 << (metric - 1)); + } + + route->ce_mask |= ROUTE_ATTR_METRICS; return 0; } @@ -783,20 +675,27 @@ int rtnl_route_unset_metric(struct rtnl_route *route, int metric) return nl_error(EINVAL, "Metric out of range (1..%d)", RTAX_MAX); - route->rt_metrics_mask &= ~(1 << (metric - 1)); + if (route->rt_metrics_mask & (1 << (metric - 1))) { + route->rt_nmetrics--; + route->rt_metrics_mask &= ~(1 << (metric - 1)); + } return 0; } -unsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric) +int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value) { if (metric > RTAX_MAX || metric < 1) - return UINT_MAX; + return nl_error(EINVAL, "Metric out of range (1..%d)", + RTAX_MAX); if (!(route->rt_metrics_mask & (1 << (metric - 1)))) - return UINT_MAX; + return nl_error(ENOENT, "Metric not available"); + + if (value) + *value = route->rt_metrics[metric - 1]; - return route->rt_metrics[metric - 1]; + return 0; } int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr) @@ -822,42 +721,27 @@ struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route) return route->rt_pref_src; } -void rtnl_route_set_oif(struct rtnl_route *route, int ifindex) -{ - route->rt_oif = ifindex; - route->ce_mask |= ROUTE_ATTR_OIF; -} - -int rtnl_route_get_oif(struct rtnl_route *route) +void rtnl_route_set_iif(struct rtnl_route *route, int ifindex) { - if (route->ce_mask & ROUTE_ATTR_OIF) - return route->rt_oif; - else - return RTNL_LINK_NOT_FOUND; -} - -void rtnl_route_set_iif(struct rtnl_route *route, const char *name) -{ - strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1); + route->rt_iif = ifindex; route->ce_mask |= ROUTE_ATTR_IIF; } -char *rtnl_route_get_iif(struct rtnl_route *route) +int rtnl_route_get_iif(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_IIF) - return route->rt_iif; - else - return NULL; + return route->rt_iif; } void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) { nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops); + route->rt_nr_nh++; route->ce_mask |= ROUTE_ATTR_MULTIPATH; } -void rtnl_route_remove_nexthop(struct rtnl_nexthop *nh) +void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) { + route->rt_nr_nh--; nl_list_del(&nh->rtnh_list); } @@ -866,44 +750,384 @@ struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route) return &route->rt_nexthops; } -void rtnl_route_set_cacheinfo(struct rtnl_route *route, - struct rtnl_rtcacheinfo *ci) +int rtnl_route_get_nnexthops(struct rtnl_route *route) { - memcpy(&route->rt_cacheinfo, ci, sizeof(*ci)); - route->ce_mask |= ROUTE_ATTR_CACHEINFO; + return route->rt_nr_nh; } -uint32_t rtnl_route_get_mp_algo(struct rtnl_route *route) +/** @} */ + +/** + * @name Utilities + * @{ + */ + +/** + * Guess scope of a route object. + * @arg route Route object. + * + * Guesses the scope of a route object, based on the following rules: + * @code + * 1) Local route -> local scope + * 2) At least one nexthop not directly connected -> universe scope + * 3) All others -> link scope + * @endcode + * + * @return Scope value. + */ +int rtnl_route_guess_scope(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_MP_ALGO) - return route->rt_mp_algo; - else - return IP_MP_ALG_NONE; + if (route->rt_type == RTN_LOCAL) + return RT_SCOPE_HOST; + + if (!nl_list_empty(&route->rt_nexthops)) { + struct rtnl_nexthop *nh; + + /* + * Use scope uiniverse if there is at least one nexthop which + * is not directly connected + */ + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + if (nh->rtnh_gateway) + return RT_SCOPE_UNIVERSE; + } + } + + return RT_SCOPE_LINK; } -void rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo) +/** @} */ + +static struct nla_policy route_policy[RTA_MAX+1] = { + [RTA_IIF] = { .type = NLA_U32 }, + [RTA_OIF] = { .type = NLA_U32 }, + [RTA_PRIORITY] = { .type = NLA_U32 }, + [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, + [RTA_METRICS] = { .type = NLA_NESTED }, + [RTA_MULTIPATH] = { .type = NLA_NESTED }, +}; + +struct rtnl_route *rtnl_route_parse(struct nlmsghdr *nlh) { - route->rt_mp_algo = algo; - route->ce_mask |= ROUTE_ATTR_MP_ALGO; + struct rtmsg *rtm; + struct rtnl_route *route; + struct nlattr *tb[RTA_MAX + 1]; + struct nl_addr *src = NULL, *dst = NULL, *addr; + struct rtnl_nexthop *old_nh = NULL; + 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); + route->rt_family = rtm->rtm_family; + route->rt_tos = rtm->rtm_tos; + route->rt_table = rtm->rtm_table; + route->rt_type = rtm->rtm_type; + route->rt_scope = rtm->rtm_scope; + route->rt_protocol = rtm->rtm_protocol; + route->rt_flags = rtm->rtm_flags; + + route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | + ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE | + ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL | + ROUTE_ATTR_FLAGS; + + if (tb[RTA_DST]) { + dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); + if (dst == NULL) + goto errout; + } 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; + } 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_u32(tb[RTA_IIF])); + + if (tb[RTA_PRIORITY]) + rtnl_route_set_priority(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; + 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; + } + } + } + + 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]) { + struct nl_addr *addr; + + addr = nla_get_addr(ntb[RTA_GATEWAY], + route->rt_family); + rtnl_route_nh_set_gateway(nh, addr); + nl_addr_put(addr); + } + + if (ntb[RTA_FLOW]) { + uint32_t realms; + + realms = nla_get_u32(ntb[RTA_FLOW]); + rtnl_route_nh_set_realms(nh, realms); + } + } + + rtnl_route_add_nexthop(route, nh); + tlen -= RTNH_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + } + + if (tb[RTA_CACHEINFO]) { + nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO], + sizeof(route->rt_cacheinfo)); + route->ce_mask |= ROUTE_ATTR_CACHEINFO; + } + + if (tb[RTA_OIF]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF])); + } + + if (tb[RTA_GATEWAY]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); + if (addr == NULL) + goto errout; + + rtnl_route_nh_set_gateway(old_nh, addr); + nl_addr_put(addr); + } + + if (tb[RTA_FLOW]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW])); + } + + if (old_nh) { + if (route->rt_nr_nh == 0) { + /* If no nexthops have been provided via RTA_MULTIPATH + * we add it as regular nexthop to maintain backwards + * compatibility */ + rtnl_route_add_nexthop(route, old_nh); + } else { + /* Kernel supports new style nexthop configuration, + * verify that it is a duplicate and discard nexthop. */ + struct rtnl_nexthop *first; + + first = nl_list_first_entry(&route->rt_nexthops, + struct rtnl_nexthop, + rtnh_list); + if (!first) + BUG(); + + if (rtnl_route_nh_compare(old_nh, first, + old_nh->ce_mask, 0)) { + nl_error(EINVAL, "Mismatch of multipath " + "configuration."); + goto errout; + } + + rtnl_route_nh_free(old_nh); + } + } + + return route; + +errout: + rtnl_route_put(route); + return NULL; } -/** @} */ +int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) +{ + int i; + struct nlattr *metrics; + struct rtmsg rtmsg = { + .rtm_family = route->rt_family, + .rtm_tos = route->rt_tos, + .rtm_table = route->rt_table, + .rtm_protocol = route->rt_protocol, + .rtm_scope = route->rt_scope, + .rtm_type = route->rt_type, + .rtm_flags = route->rt_flags, + }; + + if (route->rt_dst == NULL) + return nl_error(EINVAL, "Cannot build route message, please " + "specify route destination."); + + rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst); + if (route->rt_src) + rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src); + + if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE) + rtmsg.rtm_scope = rtnl_route_guess_scope(route); + + if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + /* Additional table attribute replacing the 8bit in the header, was + * required to allow more than 256 tables. */ + NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); + + NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst); + NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); + + if (route->ce_mask & ROUTE_ATTR_SRC) + NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src); + + if (route->ce_mask & ROUTE_ATTR_PREF_SRC) + NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src); + + if (route->ce_mask & ROUTE_ATTR_IIF) + NLA_PUT_U32(msg, RTA_IIF, route->rt_iif); + + if (route->rt_nmetrics > 0) { + uint32_t val; + + metrics = nla_nest_start(msg, RTA_METRICS); + if (metrics == NULL) + goto nla_put_failure; + + for (i = 1; i <= RTAX_MAX; i++) { + if (!rtnl_route_get_metric(route, i, &val)) + NLA_PUT_U32(msg, i, val); + } + + nla_nest_end(msg, metrics); + } + + if (rtnl_route_get_nnexthops(route) > 0) { + struct nlattr *multipath; + struct rtnl_nexthop *nh; + + if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH))) + goto nla_put_failure; + + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + struct rtnexthop *rtnh; + + rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO); + if (!rtnh) + goto nla_put_failure; + + rtnh->rtnh_flags = nh->rtnh_flags; + rtnh->rtnh_hops = nh->rtnh_weight; + rtnh->rtnh_ifindex = nh->rtnh_ifindex; + + if (nh->rtnh_gateway) + NLA_PUT_ADDR(msg, RTA_GATEWAY, + nh->rtnh_gateway); + + if (nh->rtnh_realms) + NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); + + rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) - + (void *) rtnh; + } + + nla_nest_end(msg, multipath); + } + + return 0; + +nla_put_failure: + return -ENOBUFS; +} + +/** @cond SKIP */ struct nl_object_ops route_obj_ops = { .oo_name = "route/route", .oo_size = sizeof(struct rtnl_route), .oo_constructor = route_constructor, .oo_free_data = route_free_data, .oo_clone = route_clone, - .oo_dump[NL_DUMP_BRIEF] = route_dump_brief, - .oo_dump[NL_DUMP_FULL] = route_dump_full, - .oo_dump[NL_DUMP_STATS] = route_dump_stats, - .oo_dump[NL_DUMP_XML] = route_dump_xml, - .oo_dump[NL_DUMP_ENV] = route_dump_env, + .oo_dump[NL_DUMP_ONELINE] = route_dump_oneline, + .oo_dump[NL_DUMP_DETAILS] = route_dump_details, + .oo_dump[NL_DUMP_STATS] = route_dump_stats, + .oo_dump[NL_DUMP_ENV] = route_dump_env, .oo_compare = route_compare, .oo_attrs2str = route_attrs2str, .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | ROUTE_ATTR_TABLE | ROUTE_ATTR_DST), }; +/** @endcond */ /** @} */ diff --git a/lib/route/route_utils.c b/lib/route/route_utils.c index 1386cda..41ae65c 100644 --- a/lib/route/route_utils.c +++ b/lib/route/route_utils.c @@ -167,27 +167,4 @@ int rtnl_route_str2metric(const char *name) /** @} */ -/** - * @name Nexthop Flags Translations - * @{ - */ - -static struct trans_tbl nh_flags[] = { - __ADD(RTNH_F_DEAD, dead) - __ADD(RTNH_F_PERVASIVE, pervasive) - __ADD(RTNH_F_ONLINK, onlink) -}; - -char * rtnl_route_nh_flags2str(int flags, char *buf, size_t len) -{ - return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); -} - -int rtnl_route_nh_str2flags(const char *name) -{ - return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); -} - -/** @} */ - /** @} */ diff --git a/lib/route/rule.c b/lib/route/rule.c index 60defd7..38944d3 100644 --- a/lib/route/rule.c +++ b/lib/route/rule.c @@ -840,13 +840,13 @@ int rtnl_rule_get_action(struct rtnl_rule *rule) return nl_errno(ENOENT); } -void rtnl_rule_set_realms(struct rtnl_rule *rule, realm_t realms) +void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms) { rule->r_realms = realms; rule->ce_mask |= RULE_ATTR_REALMS; } -realm_t rtnl_rule_get_realms(struct rtnl_rule *rule) +uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule) { if (rule->ce_mask & RULE_ATTR_REALMS) return rule->r_realms; |