From 535e83162249ed6274ba46bc72d8cc683ba20e17 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 29 Apr 2008 23:31:30 +0200 Subject: [PATCH] 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. --- include/netlink-types.h | 23 +- include/netlink/list.h | 3 + include/netlink/route/nexthop.h | 32 +- include/netlink/route/route.h | 73 +-- include/netlink/route/rtnl.h | 2 - include/netlink/route/rule.h | 4 +- lib/netfilter/ct_obj.c | 4 +- lib/object.c | 2 +- lib/route/addr.c | 2 +- lib/route/link.c | 2 +- lib/route/neigh.c | 2 +- lib/route/nexthop.c | 245 +++++++- lib/route/route.c | 274 +-------- lib/route/route_obj.c | 1006 +++++++++++++++++++------------ lib/route/route_utils.c | 23 - lib/route/rule.c | 4 +- src/.gitignore | 4 +- src/Makefile | 13 +- src/f_route.c | 81 --- src/nl-route-add.c | 116 ++-- src/nl-route-del.c | 76 --- src/nl-route-delete.c | 113 ++++ src/nl-route-dump.c | 81 --- src/nl-route-list.c | 118 ++++ src/route-utils.c | 237 ++++++++ src/route-utils.h | 30 + src/utils.c | 70 ++- src/utils.h | 2 + 28 files changed, 1555 insertions(+), 1087 deletions(-) delete mode 100644 src/f_route.c delete mode 100644 src/nl-route-del.c create mode 100644 src/nl-route-delete.c delete mode 100644 src/nl-route-dump.c create mode 100644 src/nl-route-list.c create mode 100644 src/route-utils.c create mode 100644 src/route-utils.h diff --git a/include/netlink-types.h b/include/netlink-types.h index a690cb2..3678a87 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2008 Thomas Graf */ #ifndef NETLINK_LOCAL_TYPES_H_ @@ -104,7 +104,7 @@ struct genl_info struct nlattr ** attrs; }; -#define LOOSE_FLAG_COMPARISON 1 +#define LOOSE_COMPARISON 1 #define NL_OBJ_MARK 1 @@ -244,11 +244,6 @@ struct rtnl_addr uint32_t a_flag_mask; }; -#define NEXTHOP_HAS_FLAGS 0x000001 -#define NEXTHOP_HAS_WEIGHT 0x000002 -#define NEXTHOP_HAS_IFINDEX 0x000004 -#define NEXTHOP_HAS_GATEWAY 0x000008 - struct rtnl_nexthop { uint8_t rtnh_flags; @@ -257,9 +252,9 @@ struct rtnl_nexthop /* 1 byte spare */ uint32_t rtnh_ifindex; struct nl_addr * rtnh_gateway; - uint32_t rtnh_mask; - + uint32_t ce_mask; /* HACK to support attr macros */ struct nl_list_head rtnh_list; + uint32_t rtnh_realms; }; struct rtnl_route @@ -270,24 +265,22 @@ struct rtnl_route uint8_t rt_dst_len; uint8_t rt_src_len; uint8_t rt_tos; - uint8_t rt_table; uint8_t rt_protocol; uint8_t rt_scope; uint8_t rt_type; + uint8_t rt_nmetrics; uint32_t rt_flags; struct nl_addr * rt_dst; struct nl_addr * rt_src; - char rt_iif[IFNAMSIZ]; - uint32_t rt_oif; - struct nl_addr * rt_gateway; + uint32_t rt_table; + uint32_t rt_iif; uint32_t rt_prio; uint32_t rt_metrics[RTAX_MAX]; uint32_t rt_metrics_mask; + uint32_t rt_nr_nh; struct nl_addr * rt_pref_src; struct nl_list_head rt_nexthops; - realm_t rt_realms; struct rtnl_rtcacheinfo rt_cacheinfo; - uint32_t rt_mp_algo; uint32_t rt_flag_mask; }; diff --git a/include/netlink/list.h b/include/netlink/list.h index e7a2646..c6876a7 100644 --- a/include/netlink/list.h +++ b/include/netlink/list.h @@ -68,6 +68,9 @@ static inline int nl_list_empty(struct nl_list_head *head) #define NL_LIST_HEAD(name) \ struct nl_list_head name = { &(name), &(name) } +#define nl_list_first_entry(head, type, member) \ + nl_list_entry((head)->next, type, member) + #define nl_list_for_each_entry(pos, head, member) \ for (pos = nl_list_entry((head)->next, typeof(*pos), member); \ &(pos)->member != (head); \ diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h index 984f4b5..2aa44dc 100644 --- a/include/netlink/route/nexthop.h +++ b/include/netlink/route/nexthop.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2008 Thomas Graf */ #ifndef NETLINK_ROUTE_NEXTHOP_H_ @@ -21,18 +21,42 @@ extern "C" { struct rtnl_nexthop; -extern struct rtnl_nexthop * rtnl_route_nh_alloc(void); -extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *); +enum { + NH_DUMP_FROM_ONELINE = -2, + NH_DUMP_FROM_DETAILS = -1, + NH_DUMP_FROM_ENV = 0, + /* > 0 reserved for nexthop index */ +}; + +extern struct rtnl_nexthop * rtnl_route_nh_alloc(void); +extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *); extern void rtnl_route_nh_free(struct rtnl_nexthop *); -extern void rtnl_route_nh_set_weight(struct rtnl_nexthop *, int); + +extern int rtnl_route_nh_compare(struct rtnl_nexthop *, + struct rtnl_nexthop *, + uint32_t, int); + +extern void rtnl_route_nh_dump(struct rtnl_nexthop *, + struct nl_dump_params *); + +extern void rtnl_route_nh_set_weight(struct rtnl_nexthop *, uint8_t); +extern uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *); extern void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *, int); +extern int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *); extern void rtnl_route_nh_set_gateway(struct rtnl_nexthop *, struct nl_addr *); +extern struct nl_addr * rtnl_route_nh_get_gateway(struct rtnl_nexthop *); extern void rtnl_route_nh_set_flags(struct rtnl_nexthop *, unsigned int); extern void rtnl_route_nh_unset_flags(struct rtnl_nexthop *, unsigned int); extern unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *); +extern void rtnl_route_nh_set_realms(struct rtnl_nexthop *, + uint32_t); +extern uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *); + +extern char * rtnl_route_nh_flags2str(int, char *, size_t); +extern int rtnl_route_nh_str2flags(const char *); #ifdef __cplusplus } diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h index f59f36b..53f47be 100644 --- a/include/netlink/route/route.h +++ b/include/netlink/route/route.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2008 Thomas Graf */ #ifndef NETLINK_ROUTE_H_ @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -46,63 +47,58 @@ extern struct nl_cache * rtnl_route_alloc_cache(struct nl_handle *); extern void rtnl_route_get(struct rtnl_route *); extern void rtnl_route_put(struct rtnl_route *); +extern struct rtnl_route *rtnl_route_parse(struct nlmsghdr *); +extern int rtnl_route_build_msg(struct nl_msg *, + struct rtnl_route *); + extern struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *, int); extern int rtnl_route_add(struct nl_handle *, struct rtnl_route *, int); extern struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *, int); -extern int rtnl_route_del(struct nl_handle *, struct rtnl_route *, int); +extern int rtnl_route_delete(struct nl_handle *, struct rtnl_route *, int); -extern void rtnl_route_set_table(struct rtnl_route *, int); -extern int rtnl_route_get_table(struct rtnl_route *); -extern void rtnl_route_set_scope(struct rtnl_route *, int); -extern int rtnl_route_get_scope(struct rtnl_route *); -extern void rtnl_route_set_tos(struct rtnl_route *, int); -extern int rtnl_route_get_tos(struct rtnl_route *); -extern void rtnl_route_set_realms(struct rtnl_route *, realm_t); -extern realm_t rtnl_route_get_realms(struct rtnl_route *); -extern void rtnl_route_set_protocol(struct rtnl_route *, int); -extern int rtnl_route_get_protocol(struct rtnl_route *); -extern void rtnl_route_set_prio(struct rtnl_route *, int); -extern int rtnl_route_get_prio(struct rtnl_route *); -extern void rtnl_route_set_family(struct rtnl_route *, int); -extern int rtnl_route_get_family(struct rtnl_route *); -extern void rtnl_route_set_type(struct rtnl_route *, int); -extern int rtnl_route_get_type(struct rtnl_route *); -extern void rtnl_route_set_flags(struct rtnl_route *, - unsigned int); -extern void rtnl_route_unset_flags(struct rtnl_route *, - unsigned int); -extern unsigned int rtnl_route_get_flags(struct rtnl_route *); +extern void rtnl_route_set_table(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_table(struct rtnl_route *); +extern void rtnl_route_set_scope(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_scope(struct rtnl_route *); +extern void rtnl_route_set_tos(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_tos(struct rtnl_route *); +extern void rtnl_route_set_protocol(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_protocol(struct rtnl_route *); +extern void rtnl_route_set_priority(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_priority(struct rtnl_route *); +extern int rtnl_route_set_family(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_family(struct rtnl_route *); +extern int rtnl_route_set_type(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_type(struct rtnl_route *); +extern void rtnl_route_set_flags(struct rtnl_route *, uint32_t); +extern void rtnl_route_unset_flags(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_flags(struct rtnl_route *); extern int rtnl_route_set_metric(struct rtnl_route *, int, unsigned int); extern int rtnl_route_unset_metric(struct rtnl_route *, int); -extern unsigned int rtnl_route_get_metric(struct rtnl_route *, int); +extern int rtnl_route_get_metric(struct rtnl_route *, int, + uint32_t *); extern int rtnl_route_set_dst(struct rtnl_route *, struct nl_addr *); extern struct nl_addr * rtnl_route_get_dst(struct rtnl_route *); extern int rtnl_route_set_src(struct rtnl_route *, struct nl_addr *); extern struct nl_addr * rtnl_route_get_src(struct rtnl_route *); -extern int rtnl_route_set_gateway(struct rtnl_route *, - struct nl_addr *); -extern struct nl_addr * rtnl_route_get_gateway(struct rtnl_route *); extern int rtnl_route_set_pref_src(struct rtnl_route *, struct nl_addr *); extern struct nl_addr * rtnl_route_get_pref_src(struct rtnl_route *); -extern void rtnl_route_set_oif(struct rtnl_route *, int); -extern int rtnl_route_get_oif(struct rtnl_route *); -extern void rtnl_route_set_iif(struct rtnl_route *, const char *); -extern char * rtnl_route_get_iif(struct rtnl_route *); -extern int rtnl_route_get_dst_len(struct rtnl_route *); +extern void rtnl_route_set_iif(struct rtnl_route *, int); +extern int rtnl_route_get_iif(struct rtnl_route *); extern int rtnl_route_get_src_len(struct rtnl_route *); extern void rtnl_route_add_nexthop(struct rtnl_route *, struct rtnl_nexthop *); -extern void rtnl_route_remove_nexthop(struct rtnl_nexthop *); +extern void rtnl_route_remove_nexthop(struct rtnl_route *, + struct rtnl_nexthop *); extern struct nl_list_head * rtnl_route_get_nexthops(struct rtnl_route *); -extern void rtnl_route_set_cacheinfo(struct rtnl_route *, - struct rtnl_rtcacheinfo *); -extern uint32_t rtnl_route_get_mp_algo(struct rtnl_route *); -extern void rtnl_route_set_mp_algo(struct rtnl_route *, uint32_t); +extern int rtnl_route_get_nnexthops(struct rtnl_route *); + +extern int rtnl_route_guess_scope(struct rtnl_route *); extern char * rtnl_route_table2str(int, char *, size_t); extern int rtnl_route_str2table(const char *); @@ -115,9 +111,6 @@ extern int rtnl_route_read_protocol_names(const char *); extern char * rtnl_route_metric2str(int, char *, size_t); extern int rtnl_route_str2metric(const char *); -extern char * rtnl_route_nh_flags2str(int, char *, size_t); -extern int rtnl_route_nh_str2flags(const char *); - #ifdef __cplusplus } #endif diff --git a/include/netlink/route/rtnl.h b/include/netlink/route/rtnl.h index 9d116cd..b12479a 100644 --- a/include/netlink/route/rtnl.h +++ b/include/netlink/route/rtnl.h @@ -23,8 +23,6 @@ extern "C" { * @{ */ -typedef uint32_t realm_t; - /** * Mask specying the size of each realm part * @ingroup rtnl diff --git a/include/netlink/route/rule.h b/include/netlink/route/rule.h index d295b0d..e57ef53 100644 --- a/include/netlink/route/rule.h +++ b/include/netlink/route/rule.h @@ -69,8 +69,8 @@ extern char * rtnl_rule_get_iif(struct rtnl_rule *); extern void rtnl_rule_set_classid(struct rtnl_rule *, uint32_t); extern uint32_t rtnl_rule_get_classid(struct rtnl_rule *); -extern void rtnl_rule_set_realms(struct rtnl_rule *, realm_t); -extern realm_t rtnl_rule_get_realms(struct rtnl_rule *); +extern void rtnl_rule_set_realms(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_realms(struct rtnl_rule *); #ifdef __cplusplus } diff --git a/lib/netfilter/ct_obj.c b/lib/netfilter/ct_obj.c index 0f5a79e..96e5db6 100644 --- a/lib/netfilter/ct_obj.c +++ b/lib/netfilter/ct_obj.c @@ -197,7 +197,7 @@ static int ct_compare(struct nl_object *_a, struct nl_object *_b, #define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR) #define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD) #define CT_DIFF_ADDR(ATTR, FIELD) \ - ((flags & LOOSE_FLAG_COMPARISON) \ + ((flags & LOOSE_COMPARISON) \ ? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \ : CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD))) @@ -227,7 +227,7 @@ static int ct_compare(struct nl_object *_a, struct nl_object *_b, diff |= CT_DIFF_VAL(REPL_PACKETS, ct_repl.packets); diff |= CT_DIFF_VAL(REPL_BYTES, ct_repl.bytes); - if (flags & LOOSE_FLAG_COMPARISON) + if (flags & LOOSE_COMPARISON) diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) & b->ct_status_mask); else diff --git a/lib/object.c b/lib/object.c index 74f6e2d..72e4ba4 100644 --- a/lib/object.c +++ b/lib/object.c @@ -318,7 +318,7 @@ int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter) return 0; return !(ops->oo_compare(obj, filter, filter->ce_mask, - LOOSE_FLAG_COMPARISON)); + LOOSE_COMPARISON)); } /** 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 + * Copyright (c) 2003-2008 Thomas Graf */ /** @@ -21,6 +21,14 @@ #include #include +/** @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) /** @} */ -/** - * @name Attributes - */ - -void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, int weight) +int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, + uint32_t attrs, int loose) { - nh->rtnh_weight = weight; - nh->rtnh_mask |= NEXTHOP_HAS_WEIGHT; + 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; } -int rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) +static void nh_dump_oneline(struct rtnl_nexthop *nh, struct nl_dump_params *dp) { - if (nh->rtnh_mask & NEXTHOP_HAS_WEIGHT) - return nh->rtnh_weight; - else - return 0; + 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, uint8_t weight) +{ + nh->rtnh_weight = weight; + nh->ce_mask |= NH_ATTR_WEIGHT; +} + +uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) +{ + 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 + * Copyright (c) 2003-2008 Thomas Graf */ /** @@ -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; - } + if (!(route = rtnl_route_parse(nlh))) + return -EINVAL; - 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])); - - 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 + * Copyright (c) 2003-2008 Thomas Graf */ /** @@ -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 #include #include +#include /** @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))); + nl_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); + 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_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_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_SCOPE) - dp_dump(p, "scope %s ", - rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); - 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); + + route_dump_oneline(a, p); + nl_dump_line(p, " "); + + if (r->ce_mask & ROUTE_ATTR_PREF_SRC) + nl_dump(p, "preferred-src %s ", + nl_addr2str(r->rt_pref_src, 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) + nl_dump(p, "priority %#x ", r->rt_prio); + + if (r->ce_mask & ROUTE_ATTR_PROTOCOL) + nl_dump(p, "protocol %s ", + rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf))); + + if (r->ce_mask & ROUTE_ATTR_IIF) + nl_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))); + + nl_dump(p, "\n"); 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))); + nl_dump_line(p, " "); + p->dp_ivar = NH_DUMP_FROM_DETAILS; + rtnl_route_nh_dump(nh, p); + nl_dump(p, "\n"); } } - dp_dump_line(p, line++, " "); - - if (r->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_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_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))); - - if (r->ce_mask & ROUTE_ATTR_PROTOCOL) - dp_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) - dp_dump(p, "iif %s ", r->rt_iif); - - if (r->ce_mask & ROUTE_ATTR_SRC) - dp_dump(p, "src %s ", - nl_addr2str(r->rt_src, buf, sizeof(buf))); - - 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_CACHEINFO) && - r->rt_cacheinfo.rtci_error) - dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error, - strerror(-r->rt_cacheinfo.rtci_error)); - - 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; -} - -static int route_dump_xml(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++, "\n"); - dp_dump_line(p, line++, " %s\n", - nl_af2str(route->rt_family, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_DST) - dp_dump_line(p, line++, " %s\n", - nl_addr2str(route->rt_dst, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_SRC) - dp_dump_line(p, line++, " %s\n", - nl_addr2str(route->rt_src, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump_line(p, line++, " %s\n", - nl_addr2str(route->rt_gateway, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump_line(p, line++, " %s\n", - nl_addr2str(route->rt_pref_src, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_IIF) - dp_dump_line(p, line++, " %s\n", route->rt_iif); - - if (route->ce_mask & ROUTE_ATTR_REALMS) - dp_dump_line(p, line++, " %u\n", - route->rt_realms); - - if (route->ce_mask & ROUTE_ATTR_TOS) - dp_dump_line(p, line++, " %u\n", route->rt_tos); - - if (route->ce_mask & ROUTE_ATTR_TABLE) - dp_dump_line(p, line++, " %u
\n", - route->rt_table); - - if (route->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump_line(p, line++, " %s\n", - rtnl_scope2str(route->rt_scope, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_PRIO) - dp_dump_line(p, line++, " %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++, " %s\n", - rtnl_link_i2name(link_cache, - route->rt_oif, - buf, sizeof(buf))); - else - dp_dump_line(p, line++, " %u\n", - route->rt_oif); - } - - if (route->ce_mask & ROUTE_ATTR_TYPE) - dp_dump_line(p, line++, " %s\n", - nl_rtntype2str(route->rt_type, buf, sizeof(buf))); - - dp_dump_line(p, line++, "
\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; + return 0; } 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_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++, "ROUTE_DST=%s\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++, "ROUTE_SRC=%s\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++, "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_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++, "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); + nl_dump_line(p, "ROUTE_IIF=%s\n", route->rt_iif); if (route->ce_mask & ROUTE_ATTR_TOS) - dp_dump_line(p, line++, "ROUTE_TOS=%u\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++, "ROUTE_TABLE=%u\n", + nl_dump_line(p, "ROUTE_TABLE=%u\n", route->rt_table); if (route->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump_line(p, line++, "ROUTE_SCOPE=%s\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++, "ROUTE_METRIC=%u\n", + nl_dump_line(p, "ROUTE_PRIORITY=%u\n", route->rt_prio); - if (route->ce_mask & ROUTE_ATTR_OIF) { - struct nl_cache *link_cache; - - dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n", - route->rt_oif); - - 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))); - } - if (route->ce_mask & ROUTE_ATTR_TYPE) - dp_dump_line(p, line++, "ROUTE_TYPE=%s\n", + nl_dump_line(p, "ROUTE_TYPE=%s\n", nl_rtntype2str(route->rt_type, buf, sizeof(buf))); - return line; + if (route->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + int index = 1; + + if (route->rt_nr_nh > 0) + nl_dump_line(p, "ROUTE_NR_NH=%u\n", route->rt_nr_nh); + + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + p->dp_ivar = index++; + rtnl_route_nh_dump(nh, p); + } + } + + 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 - diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags); - -#undef ROUTE_DIFF + } 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); + } + +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) +int rtnl_route_set_type(struct rtnl_route *route, uint8_t type) { - 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); + 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; } -struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route) +uint8_t rtnl_route_get_type(struct rtnl_route *route) { - return route->rt_gateway; + return route->rt_type; } -void rtnl_route_set_type(struct rtnl_route *route, int type) -{ - route->rt_type = type; - route->ce_mask |= ROUTE_ATTR_TYPE; -} - -int rtnl_route_get_type(struct rtnl_route *route) -{ - if (route->ce_mask & ROUTE_ATTR_TYPE) - return route->rt_type; - else - return RTN_UNICAST; -} - -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"); - return route->rt_metrics[metric - 1]; + if (value) + *value = 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) +void rtnl_route_set_iif(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) -{ - 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; -} - -uint32_t rtnl_route_get_mp_algo(struct rtnl_route *route) -{ - if (route->ce_mask & ROUTE_ATTR_MP_ALGO) - return route->rt_mp_algo; - else - return IP_MP_ALG_NONE; -} - -void rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo) -{ - route->rt_mp_algo = algo; - route->ce_mask |= ROUTE_ATTR_MP_ALGO; + return route->rt_nr_nh; } /** @} */ +/** + * @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->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; +} + +/** @} */ + +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) +{ + 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; diff --git a/src/.gitignore b/src/.gitignore index 11fe5ab..8d71209 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -23,8 +23,8 @@ nl-qdisc-add nl-qdisc-delete nl-qdisc-dump nl-route-add -nl-route-del -nl-route-dump +nl-route-delete +nl-route-list nl-route-get nl-rule-dump nl-tctree-dump diff --git a/src/Makefile b/src/Makefile index ddbe29a..0f1e14e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,36 +6,37 @@ # License as published by the Free Software Foundation version 2.1 # of the License. # -# Copyright (c) 2003-2006 Thomas Graf +# Copyright (c) 2003-2008 Thomas Graf # ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),) include ../Makefile.opts endif -LDFLAGS += -L../lib -lnl utils.o +LDFLAGS += -L../lib -lnl CIN := $(wildcard nl-*.c) $(wildcard genl-*.c) $(wildcard nf-*.c) TOOLS := $(CIN:%.c=%) all: $(TOOLS) $(TOOLS): utils.o +nl-route-add nl-route-delete nl-route-list: route-utils.o nl-%: nl-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) genl-%: genl-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) nf-%: nf-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) clean: @echo " CLEAN src"; \ - rm -f $(TOOLS) utils.o + rm -f $(TOOLS) *.o distclean: clean diff --git a/src/f_route.c b/src/f_route.c deleted file mode 100644 index 581ff65..0000000 --- a/src/f_route.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * src/f_route.c Routes Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -static void get_filter(struct rtnl_route *r, int ac, char **av, int idx, - struct nl_cache *cache, struct nl_cache *link_cache) -{ - while (ac > idx) { - if (!strcasecmp(av[idx], "src")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_pref_src(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "dst")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_dst(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "via")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_gateway(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "from")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_src(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "tos")) { - if (ac > ++idx) - rtnl_route_set_tos(r, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "prio")) { - if (ac > ++idx) - rtnl_route_set_prio(r, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "scope")) { - if (ac > ++idx) - rtnl_route_set_scope(r, rtnl_str2scope(av[idx++])); - } else if (!strcasecmp(av[idx], "dev")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(link_cache, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_route_set_oif(r, ifindex); - } - } else if (!strcasecmp(av[idx], "table")) { - if (ac > ++idx) - rtnl_route_set_table(r, strtoul(av[idx++], NULL, 0)); - } else { - fprintf(stderr, "What is '%s'?\n", av[idx]); - exit(1); - } - } - - return; - -err_notfound: - fprintf(stderr, "Unable to find device \"%s\"\n", av[idx-1]); - exit(1); -err: - fprintf(stderr, "%s\n", nl_geterror()); - exit(1); -} diff --git a/src/nl-route-add.c b/src/nl-route-add.c index 2686397..eb63a22 100644 --- a/src/nl-route-add.c +++ b/src/nl-route-add.c @@ -1,76 +1,124 @@ /* - * src/nl-route-dump.c Dump route attributes + * src/nl-route-add.c Route addition utility * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2008 Thomas Graf */ -#include "utils.h" +#include "route-utils.h" + +static struct nl_cache *link_cache, *route_cache; static void print_usage(void) { printf( - "Usage: nl-route-add []\n"); + "Usage: nl-route-add [OPTION]... --dst=ADDR --nh=NEXTHOP [--nh=...]\n" + " nl-route-add [OPTION]... ADDR NEXTHOP\n" + "\n" + "Required Options\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nh=NEXTHOP nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + "\n" + " e.g. dev=eth0,via=192.168.1.12\n" + "\n" + "Options\n" + " -s, --src=ADDR source prefix\n" + " -i, --iif=DEV incomming interface\n" + " -P, --pref-src=ADDR preferred source address\n" + " -t, --table=TABLE routing table\n" + " -m, --metric=OPTS metrics\n" + " -p, --prio=NUM priotity\n" + " -S, --scope=SCOPE scope\n" + " -x, --proto=PROTO protocol\n" + " -T, --type=TYPE routing type\n" + " -h, --help show this help\n"); exit(1); } -#include "f_route.c" - int main(int argc, char *argv[]) { struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; struct rtnl_route *route; int err = 1; - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; + nltool_connect(nlh, NETLINK_ROUTE); + link_cache = nltool_alloc_link_cache(nlh); + route_cache = nltool_alloc_route_cache(nlh); route = rtnl_route_alloc(); if (!route) goto errout; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "dst", 1, 0, 'd' }, + { "src", 1, 0, 's' }, + { "iif", 1, 0, 'i' }, + { "nh", 1, 0, 'n' }, + { "pref-src", 1, 0, 'P' }, + { "table", 1, 0, 't' }, + { "metric", 1, 0, 'm' }, + { "prio", 1, 0, 'p' }, + { "scope", 1, 0, 'S' }, + { "proto", 1, 0, 'x' }, + { "type", 1, 0, 'T' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; + c = getopt_long(argc, argv, "d:s:i:n:P:t:m:p:S:x:T:h", long_opts, &optidx); + if (c == -1) + break; - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; + switch (c) { + case 'd': parse_dst(route, optarg); break; + case 's': parse_src(route, optarg); break; + case 'i': parse_iif(route, optarg, link_cache); break; + case 'n': parse_nexthop(route, optarg, link_cache); break; + case 'P': parse_pref_src(route, optarg); break; + case 't': parse_table(route, optarg); break; + case 'm': parse_metric(route, optarg); break; + case 'p': parse_prio(route, optarg); break; + case 'S': parse_scope(route, optarg); break; + case 'x': parse_protocol(route, optarg); break; + case 'T': parse_type(route, optarg); break; + case 'h': print_usage(); break; + } + } - get_filter(route, argc, argv, 1, route_cache, link_cache); + while (optind < argc) { + if (!rtnl_route_get_dst(route)) { + parse_dst(route, argv[optind++]); + continue; + } + + /* This must all be nexthop configuration */ + } if (rtnl_route_add(nlh, route, 0) < 0) { - fprintf(stderr, "rtnl_route_add failed: %s\n", - nl_geterror()); - goto errout_route_cache; + fprintf(stderr, "rtnl_route_add failed: %s\n", nl_geterror()); + goto errout_free; } err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); errout_free: rtnl_route_put(route); errout: + nl_cache_free(route_cache); + nl_cache_free(link_cache); + nl_close(nlh); nl_handle_destroy(nlh); + return err; } diff --git a/src/nl-route-del.c b/src/nl-route-del.c deleted file mode 100644 index 9d912e1..0000000 --- a/src/nl-route-del.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * src/nl-route-del.c Delete Routes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-route-del []\n"); - exit(1); -} - -#include "f_route.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; - struct rtnl_route *route; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - route = rtnl_route_alloc(); - if (!route) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; - - get_filter(route, argc, argv, 1, route_cache, link_cache); - - if (rtnl_route_del(nlh, route, 0) < 0) { - fprintf(stderr, "rtnl_route_del failed: %s\n", - nl_geterror()); - goto errout_route_cache; - } - - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-route-delete.c b/src/nl-route-delete.c new file mode 100644 index 0000000..1c97817 --- /dev/null +++ b/src/nl-route-delete.c @@ -0,0 +1,113 @@ +/* + * src/nl-route-delete.c Delete Routes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#include "route-utils.h" + +static void print_usage(void) +{ + printf( + "Usage: nl-route-delete [OPTION]...\n" + "\n" + "Options\n" + " -f, --family=FAMILY address family\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nh=NEXTHOP nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -s, --src=ADDR source prefix\n" + " -i, --iif=DEV incomming interface\n" + " -P, --pref-src=ADDR preferred source address\n" + " -t, --table=TABLE routing table\n" + " -m, --metric=OPTS metrics\n" + " -p, --prio=NUM priotity\n" + " -S, --scope=SCOPE scope\n" + " -x, --proto=PROTO protocol\n" + " -T, --type=TYPE routing type\n" + " -D, --dumptype=TYPE { brief | detailed | stats | env }\n" + " -h, --help show this help\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct nl_handle *nlh; + struct nl_cache *link_cache, *route_cache; + struct rtnl_route *route; + int err = 1; + + nlh = nltool_alloc_handle(); + nltool_connect(nlh, NETLINK_ROUTE); + link_cache = nltool_alloc_link_cache(nlh); + route_cache = nltool_alloc_route_cache(nlh); + + route = rtnl_route_alloc(); + if (!route) + goto errout; + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "family", 1, 0, 'f' }, + { "dst", 1, 0, 'd' }, + { "src", 1, 0, 's' }, + { "iif", 1, 0, 'i' }, + { "nh", 1, 0, 'n' }, + { "pref-src", 1, 0, 'P' }, + { "table", 1, 0, 't' }, + { "metric", 1, 0, 'm' }, + { "prio", 1, 0, 'p' }, + { "scope", 1, 0, 'S' }, + { "proto", 1, 0, 'x' }, + { "type", 1, 0, 'T' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:d:s:i:n:P:t:m:p:S:x:T:h", + long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': parse_family(route, optarg); break; + case 'd': parse_dst(route, optarg); break; + case 's': parse_src(route, optarg); break; + case 'i': parse_iif(route, optarg, link_cache); break; + case 'n': parse_nexthop(route, optarg, link_cache); break; + case 'P': parse_pref_src(route, optarg); break; + case 't': parse_table(route, optarg); break; + case 'm': parse_metric(route, optarg); break; + case 'p': parse_prio(route, optarg); break; + case 'S': parse_scope(route, optarg); break; + case 'x': parse_protocol(route, optarg); break; + case 'T': parse_type(route, optarg); break; + case 'h': print_usage(); break; + } + } + + if ((err = rtnl_route_delete(nlh, route, 0)) < 0) + fatal(err, "rtnl_route_del failed: %s\n", nl_geterror()); + + err = 0; + + rtnl_route_put(route); +errout: + nl_cache_free(route_cache); + nl_cache_free(link_cache); + nl_close(nlh); + nl_handle_destroy(nlh); + + return err; +} diff --git a/src/nl-route-dump.c b/src/nl-route-dump.c deleted file mode 100644 index aed9bd2..0000000 --- a/src/nl-route-dump.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * src/nl-route-dump.c Dump route attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-route-dump []\n" - " mode := { brief | detailed | stats | xml }\n"); - exit(1); -} - -#include "f_route.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; - struct rtnl_route *route; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - route = rtnl_route_alloc(); - if (!route) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_route_cache; - - get_filter(route, argc, argv, 2, route_cache, link_cache); - - nl_cache_dump_filter(route_cache, ¶ms, (struct nl_object *) route); - - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-route-list.c b/src/nl-route-list.c new file mode 100644 index 0000000..4f70ff7 --- /dev/null +++ b/src/nl-route-list.c @@ -0,0 +1,118 @@ +/* + * src/nl-route-list.c List route attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf + */ + +#include "route-utils.h" + +static void print_usage(void) +{ + printf( + "Usage: nl-route-list [OPTION]...\n" + "\n" + "Options\n" + " -f, --family=FAMILY address family\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nh=NEXTHOP nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -s, --src=ADDR source prefix\n" + " -i, --iif=DEV incomming interface\n" + " -P, --pref-src=ADDR preferred source address\n" + " -t, --table=TABLE routing table\n" + " -m, --metric=OPTS metrics\n" + " -p, --prio=NUM priotity\n" + " -S, --scope=SCOPE scope\n" + " -x, --proto=PROTO protocol\n" + " -T, --type=TYPE routing type\n" + " -D, --dumptype=TYPE { brief | detailed | stats | env }\n" + " -h, --help show this help\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + struct nl_handle *nlh; + struct nl_cache *link_cache, *route_cache; + struct rtnl_route *route; + struct nl_dump_params params = { + .dp_fd = stdout, + .dp_type = NL_DUMP_BRIEF + }; + int err = 1; + + nlh = nltool_alloc_handle(); + nltool_connect(nlh, NETLINK_ROUTE); + link_cache = nltool_alloc_link_cache(nlh); + route_cache = nltool_alloc_route_cache(nlh); + + route = rtnl_route_alloc(); + if (!route) + goto errout; + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "family", 1, 0, 'f' }, + { "dst", 1, 0, 'd' }, + { "src", 1, 0, 's' }, + { "iif", 1, 0, 'i' }, + { "nh", 1, 0, 'n' }, + { "pref-src", 1, 0, 'P' }, + { "table", 1, 0, 't' }, + { "metric", 1, 0, 'm' }, + { "prio", 1, 0, 'p' }, + { "scope", 1, 0, 'S' }, + { "proto", 1, 0, 'x' }, + { "type", 1, 0, 'T' }, + { "dumptype", 1, 0, 'D' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:d:s:i:n:P:t:m:p:S:x:T:D:h", + long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': parse_family(route, optarg); break; + case 'd': parse_dst(route, optarg); break; + case 's': parse_src(route, optarg); break; + case 'i': parse_iif(route, optarg, link_cache); break; + case 'n': parse_nexthop(route, optarg, link_cache); break; + case 'P': parse_pref_src(route, optarg); break; + case 't': parse_table(route, optarg); break; + case 'm': parse_metric(route, optarg); break; + case 'p': parse_prio(route, optarg); break; + case 'S': parse_scope(route, optarg); break; + case 'x': parse_protocol(route, optarg); break; + case 'T': parse_type(route, optarg); break; + case 'D': params.dp_type = nltool_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + } + } + + nl_cache_dump_filter(route_cache, ¶ms, OBJ_CAST(route)); + + err = 0; + + rtnl_route_put(route); +errout: + nl_cache_free(route_cache); + nl_cache_free(link_cache); + nl_close(nlh); + nl_handle_destroy(nlh); + + return err; +} diff --git a/src/route-utils.c b/src/route-utils.c new file mode 100644 index 0000000..61bc9cd --- /dev/null +++ b/src/route-utils.c @@ -0,0 +1,237 @@ +/* + * src/route-utils.c Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf + */ + +#include "route-utils.h" + +void parse_family(struct rtnl_route *route, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) != AF_UNSPEC) + rtnl_route_set_family(route, family); +} + +void parse_dst(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + if ((err = rtnl_route_set_dst(route, addr)) < 0) + fatal(err, nl_geterror()); + + nl_addr_put(addr); +} + +void parse_src(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + if ((err = rtnl_route_set_src(route, addr)) < 0) + fatal(err, nl_geterror()); + + nl_addr_put(addr); +} + +void parse_pref_src(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + if ((err = rtnl_route_set_pref_src(route, addr)) < 0) + fatal(err, nl_geterror()); + + nl_addr_put(addr); +} + +void parse_metric(struct rtnl_route *route, char *subopts) +{ + /* strict equal order to RTAX_* */ + static char *const tokens[] = { + "unspec", + "lock", + "mtu", + "window", + "rtt", + "rttvar", + "sstresh", + "cwnd", + "advmss", + "reordering", + "hoplimit", + "initcwnd", + "features", + NULL, + }; + unsigned long lval; + char *arg, *endptr; + + while (*subopts != '\0') { + int ret = getsubopt(&subopts, tokens, &arg); + if (ret == -1) + fatal(EINVAL, "Unknown metric token \"%s\"", arg); + + if (ret == 0) + fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]); + + if (arg == NULL) + fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]); + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]); + + if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0) + fatal(ret, nl_geterror()); + } +} + +void parse_nexthop(struct rtnl_route *route, char *subopts, + struct nl_cache *link_cache) +{ + enum { + NH_DEV, + NH_VIA, + NH_WEIGHT, + }; + static char *const tokens[] = { + "dev", + "via", + "weight", + NULL, + }; + struct rtnl_nexthop *nh; + unsigned long lval; + struct nl_addr *addr; + int ival; + char *arg, *endptr; + + if (!(nh = rtnl_route_nh_alloc())) + fatal(ENOMEM, "Out of memory"); + + while (*subopts != '\0') { + int ret = getsubopt(&subopts, tokens, &arg); + if (ret == -1) + fatal(EINVAL, "Unknown nexthop token \"%s\"", arg); + + switch (ret) { + case NH_DEV: + ival = rtnl_link_name2i(link_cache, arg); + if (ival == RTNL_LINK_NOT_FOUND) + fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_route_nh_set_ifindex(nh, ival); + break; + + case NH_VIA: + addr = nl_addr_parse(arg, rtnl_route_get_family(route)); + if (addr == NULL) + fatal(nl_get_errno(), nl_geterror()); + + rtnl_route_nh_set_gateway(nh, addr); + nl_addr_put(addr); + break; + + case NH_WEIGHT: + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + fatal(EINVAL, "Invalid weight \"%s\", not numeric", arg); + rtnl_route_nh_set_weight(nh, lval); + break; + } + } + + rtnl_route_add_nexthop(route, nh); +} + +void parse_table(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) { + if ((lval = rtnl_route_str2table(arg)) < 0) + fatal(EINVAL, "Unknown table name \"%s\"", arg); + } + + rtnl_route_set_table(route, lval); +} + +void parse_prio(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + fatal(EINVAL, "Invalid priority value, not numeric"); + rtnl_route_set_priority(route, lval); +} + +void parse_scope(struct rtnl_route *route, char *arg) +{ + int ival; + + if ((ival = rtnl_str2scope(arg)) < 0) + fatal(EINVAL, "Unknown routing scope \"%s\"", arg); + + rtnl_route_set_scope(route, ival); +} + +void parse_protocol(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) { + if ((lval = rtnl_route_str2proto(arg)) < 0) + fatal(EINVAL, "Unknown routing protocol name \"%s\"", + arg); + } + + rtnl_route_set_protocol(route, lval); +} + +void parse_type(struct rtnl_route *route, char *arg) +{ + int ival; + + if ((ival = nl_str2rtntype(arg)) < 0) + fatal(EINVAL, "Unknown routing type \"%s\"", arg); + + if ((ival = rtnl_route_set_type(route, ival)) < 0) + fatal(ival, nl_geterror()); +} + +void parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache) +{ + int ival; + + ival = rtnl_link_name2i(link_cache, arg); + if (ival == RTNL_LINK_NOT_FOUND) + fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_route_set_iif(route, ival); +} diff --git a/src/route-utils.h b/src/route-utils.h new file mode 100644 index 0000000..873835c --- /dev/null +++ b/src/route-utils.h @@ -0,0 +1,30 @@ +/* + * src/route-utils.h Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf + */ + +#ifndef __ROUTE_UTILS_H_ +#define __ROUTE_UTILS_H_ + +#include "utils.h" + +extern void parse_family(struct rtnl_route *, char *); +extern void parse_dst(struct rtnl_route *, char *); +extern void parse_src(struct rtnl_route *, char *); +extern void parse_pref_src(struct rtnl_route *, char *); +extern void parse_metric(struct rtnl_route *, char *); +extern void parse_nexthop(struct rtnl_route *, char *, struct nl_cache *); +extern void parse_table(struct rtnl_route *, char *); +extern void parse_prio(struct rtnl_route *, char *); +extern void parse_scope(struct rtnl_route *, char *); +extern void parse_protocol(struct rtnl_route *, char *); +extern void parse_type(struct rtnl_route *, char *); +extern void parse_iif(struct rtnl_route *, char *, struct nl_cache *); + +#endif diff --git a/src/utils.c b/src/utils.c index b43758a..4695760 100644 --- a/src/utils.c +++ b/src/utils.c @@ -13,6 +13,21 @@ #include +void fatal(int err, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "Error: "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + exit(err); +} + int nltool_init(int argc, char *argv[]) { return 0; @@ -24,7 +39,7 @@ int nltool_connect(struct nl_handle *nlh, int protocol) err = nl_connect(nlh, protocol); if (err < 0) - fprintf(stderr, "Unable to connect netlink socket%s\n", + fatal(err, "Unable to connect netlink socket: %s", nl_geterror()); return err; @@ -32,7 +47,12 @@ int nltool_connect(struct nl_handle *nlh, int protocol) struct nl_handle *nltool_alloc_handle(void) { - return nl_handle_alloc(); + struct nl_handle *sock; + + if (!(sock = nl_handle_alloc())) + fatal(ENOBUFS, "Unable to allocate netlink socket"); + + return sock; } struct nl_addr *nltool_addr_parse(const char *str) @@ -71,10 +91,10 @@ struct nl_cache *nltool_alloc_link_cache(struct nl_handle *nlh) cache = rtnl_link_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve link cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve link cache: %s", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -85,10 +105,10 @@ struct nl_cache *nltool_alloc_addr_cache(struct nl_handle *nlh) cache = rtnl_addr_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve address cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve address cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -99,10 +119,10 @@ struct nl_cache *nltool_alloc_neigh_cache(struct nl_handle *nlh) cache = rtnl_neigh_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve neighbour cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve neighbour cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -113,8 +133,8 @@ struct nl_cache *nltool_alloc_neightbl_cache(struct nl_handle *nlh) cache = rtnl_neightbl_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve neighbour table " - "cache: %s\n", nl_geterror()); + fatal(nl_get_errno(), "Unable to retrieve neighbour table " + "cache: %s", nl_geterror()); else nl_cache_mngt_provide(cache); @@ -127,10 +147,10 @@ struct nl_cache *nltool_alloc_route_cache(struct nl_handle *nlh) cache = rtnl_route_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve route cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve route cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -141,10 +161,10 @@ struct nl_cache *nltool_alloc_rule_cache(struct nl_handle *nlh) cache = rtnl_rule_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve rule cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve rule cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -155,10 +175,10 @@ struct nl_cache *nltool_alloc_qdisc_cache(struct nl_handle *nlh) cache = rtnl_qdisc_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve qdisc cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve qdisc cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } @@ -169,10 +189,10 @@ struct nl_cache *nltool_alloc_genl_family_cache(struct nl_handle *nlh) cache = genl_ctrl_alloc_cache(nlh); if (!cache) - fprintf(stderr, "Unable to retrieve genl family cache: %s\n", + fatal(nl_get_errno(), "Unable to retrieve genl family cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); + + nl_cache_mngt_provide(cache); return cache; } diff --git a/src/utils.h b/src/utils.h index d738ce7..7d85e15 100644 --- a/src/utils.h +++ b/src/utils.h @@ -43,6 +43,8 @@ #include #include +extern void fatal(int err, const char *fmt, ...); + extern int nltool_init(int argc, char *argv[]); extern int nltool_connect(struct nl_handle *nlh, int protocol); extern struct nl_addr *nltool_addr_parse(const char *str);