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.
This commit is contained in:
parent
8ac78f1552
commit
535e831622
|
@ -6,7 +6,7 @@
|
||||||
* License as published by the Free Software Foundation version 2.1
|
* License as published by the Free Software Foundation version 2.1
|
||||||
* of the License.
|
* of the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NETLINK_LOCAL_TYPES_H_
|
#ifndef NETLINK_LOCAL_TYPES_H_
|
||||||
|
@ -104,7 +104,7 @@ struct genl_info
|
||||||
struct nlattr ** attrs;
|
struct nlattr ** attrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LOOSE_FLAG_COMPARISON 1
|
#define LOOSE_COMPARISON 1
|
||||||
|
|
||||||
#define NL_OBJ_MARK 1
|
#define NL_OBJ_MARK 1
|
||||||
|
|
||||||
|
@ -244,11 +244,6 @@ struct rtnl_addr
|
||||||
uint32_t a_flag_mask;
|
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
|
struct rtnl_nexthop
|
||||||
{
|
{
|
||||||
uint8_t rtnh_flags;
|
uint8_t rtnh_flags;
|
||||||
|
@ -257,9 +252,9 @@ struct rtnl_nexthop
|
||||||
/* 1 byte spare */
|
/* 1 byte spare */
|
||||||
uint32_t rtnh_ifindex;
|
uint32_t rtnh_ifindex;
|
||||||
struct nl_addr * rtnh_gateway;
|
struct nl_addr * rtnh_gateway;
|
||||||
uint32_t rtnh_mask;
|
uint32_t ce_mask; /* HACK to support attr macros */
|
||||||
|
|
||||||
struct nl_list_head rtnh_list;
|
struct nl_list_head rtnh_list;
|
||||||
|
uint32_t rtnh_realms;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rtnl_route
|
struct rtnl_route
|
||||||
|
@ -270,24 +265,22 @@ struct rtnl_route
|
||||||
uint8_t rt_dst_len;
|
uint8_t rt_dst_len;
|
||||||
uint8_t rt_src_len;
|
uint8_t rt_src_len;
|
||||||
uint8_t rt_tos;
|
uint8_t rt_tos;
|
||||||
uint8_t rt_table;
|
|
||||||
uint8_t rt_protocol;
|
uint8_t rt_protocol;
|
||||||
uint8_t rt_scope;
|
uint8_t rt_scope;
|
||||||
uint8_t rt_type;
|
uint8_t rt_type;
|
||||||
|
uint8_t rt_nmetrics;
|
||||||
uint32_t rt_flags;
|
uint32_t rt_flags;
|
||||||
struct nl_addr * rt_dst;
|
struct nl_addr * rt_dst;
|
||||||
struct nl_addr * rt_src;
|
struct nl_addr * rt_src;
|
||||||
char rt_iif[IFNAMSIZ];
|
uint32_t rt_table;
|
||||||
uint32_t rt_oif;
|
uint32_t rt_iif;
|
||||||
struct nl_addr * rt_gateway;
|
|
||||||
uint32_t rt_prio;
|
uint32_t rt_prio;
|
||||||
uint32_t rt_metrics[RTAX_MAX];
|
uint32_t rt_metrics[RTAX_MAX];
|
||||||
uint32_t rt_metrics_mask;
|
uint32_t rt_metrics_mask;
|
||||||
|
uint32_t rt_nr_nh;
|
||||||
struct nl_addr * rt_pref_src;
|
struct nl_addr * rt_pref_src;
|
||||||
struct nl_list_head rt_nexthops;
|
struct nl_list_head rt_nexthops;
|
||||||
realm_t rt_realms;
|
|
||||||
struct rtnl_rtcacheinfo rt_cacheinfo;
|
struct rtnl_rtcacheinfo rt_cacheinfo;
|
||||||
uint32_t rt_mp_algo;
|
|
||||||
uint32_t rt_flag_mask;
|
uint32_t rt_flag_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,9 @@ static inline int nl_list_empty(struct nl_list_head *head)
|
||||||
#define NL_LIST_HEAD(name) \
|
#define NL_LIST_HEAD(name) \
|
||||||
struct nl_list_head name = { &(name), &(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) \
|
#define nl_list_for_each_entry(pos, head, member) \
|
||||||
for (pos = nl_list_entry((head)->next, typeof(*pos), member); \
|
for (pos = nl_list_entry((head)->next, typeof(*pos), member); \
|
||||||
&(pos)->member != (head); \
|
&(pos)->member != (head); \
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* License as published by the Free Software Foundation version 2.1
|
* License as published by the Free Software Foundation version 2.1
|
||||||
* of the License.
|
* of the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NETLINK_ROUTE_NEXTHOP_H_
|
#ifndef NETLINK_ROUTE_NEXTHOP_H_
|
||||||
|
@ -21,18 +21,42 @@ extern "C" {
|
||||||
|
|
||||||
struct rtnl_nexthop;
|
struct rtnl_nexthop;
|
||||||
|
|
||||||
extern struct rtnl_nexthop * rtnl_route_nh_alloc(void);
|
enum {
|
||||||
extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *);
|
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_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 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 *,
|
extern void rtnl_route_nh_set_gateway(struct rtnl_nexthop *,
|
||||||
struct nl_addr *);
|
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 *,
|
extern void rtnl_route_nh_set_flags(struct rtnl_nexthop *,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
extern void rtnl_route_nh_unset_flags(struct rtnl_nexthop *,
|
extern void rtnl_route_nh_unset_flags(struct rtnl_nexthop *,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
extern unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* License as published by the Free Software Foundation version 2.1
|
* License as published by the Free Software Foundation version 2.1
|
||||||
* of the License.
|
* of the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NETLINK_ROUTE_H_
|
#ifndef NETLINK_ROUTE_H_
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
#include <netlink/addr.h>
|
#include <netlink/addr.h>
|
||||||
#include <netlink/data.h>
|
#include <netlink/data.h>
|
||||||
#include <netlink/route/nexthop.h>
|
#include <netlink/route/nexthop.h>
|
||||||
|
#include <netlink/route/rtnl.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
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_get(struct rtnl_route *);
|
||||||
extern void rtnl_route_put(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 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 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 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 void rtnl_route_set_table(struct rtnl_route *, uint32_t);
|
||||||
extern int rtnl_route_get_table(struct rtnl_route *);
|
extern uint32_t rtnl_route_get_table(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_scope(struct rtnl_route *, int);
|
extern void rtnl_route_set_scope(struct rtnl_route *, uint8_t);
|
||||||
extern int rtnl_route_get_scope(struct rtnl_route *);
|
extern uint8_t rtnl_route_get_scope(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_tos(struct rtnl_route *, int);
|
extern void rtnl_route_set_tos(struct rtnl_route *, uint8_t);
|
||||||
extern int rtnl_route_get_tos(struct rtnl_route *);
|
extern uint8_t rtnl_route_get_tos(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_realms(struct rtnl_route *, realm_t);
|
extern void rtnl_route_set_protocol(struct rtnl_route *, uint8_t);
|
||||||
extern realm_t rtnl_route_get_realms(struct rtnl_route *);
|
extern uint8_t rtnl_route_get_protocol(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_protocol(struct rtnl_route *, int);
|
extern void rtnl_route_set_priority(struct rtnl_route *, uint32_t);
|
||||||
extern int rtnl_route_get_protocol(struct rtnl_route *);
|
extern uint32_t rtnl_route_get_priority(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_prio(struct rtnl_route *, int);
|
extern int rtnl_route_set_family(struct rtnl_route *, uint8_t);
|
||||||
extern int rtnl_route_get_prio(struct rtnl_route *);
|
extern uint8_t rtnl_route_get_family(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_family(struct rtnl_route *, int);
|
extern int rtnl_route_set_type(struct rtnl_route *, uint8_t);
|
||||||
extern int rtnl_route_get_family(struct rtnl_route *);
|
extern uint8_t rtnl_route_get_type(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_type(struct rtnl_route *, int);
|
extern void rtnl_route_set_flags(struct rtnl_route *, uint32_t);
|
||||||
extern int rtnl_route_get_type(struct rtnl_route *);
|
extern void rtnl_route_unset_flags(struct rtnl_route *, uint32_t);
|
||||||
extern void rtnl_route_set_flags(struct rtnl_route *,
|
extern uint32_t rtnl_route_get_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 int rtnl_route_set_metric(struct rtnl_route *, int,
|
extern int rtnl_route_set_metric(struct rtnl_route *, int,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
extern int rtnl_route_unset_metric(struct rtnl_route *, 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 *,
|
extern int rtnl_route_set_dst(struct rtnl_route *,
|
||||||
struct nl_addr *);
|
struct nl_addr *);
|
||||||
extern struct nl_addr * rtnl_route_get_dst(struct rtnl_route *);
|
extern struct nl_addr * rtnl_route_get_dst(struct rtnl_route *);
|
||||||
extern int rtnl_route_set_src(struct rtnl_route *,
|
extern int rtnl_route_set_src(struct rtnl_route *,
|
||||||
struct nl_addr *);
|
struct nl_addr *);
|
||||||
extern struct nl_addr * rtnl_route_get_src(struct rtnl_route *);
|
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 *,
|
extern int rtnl_route_set_pref_src(struct rtnl_route *,
|
||||||
struct nl_addr *);
|
struct nl_addr *);
|
||||||
extern struct nl_addr * rtnl_route_get_pref_src(struct rtnl_route *);
|
extern struct nl_addr * rtnl_route_get_pref_src(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_oif(struct rtnl_route *, int);
|
extern void rtnl_route_set_iif(struct rtnl_route *, int);
|
||||||
extern int rtnl_route_get_oif(struct rtnl_route *);
|
extern int rtnl_route_get_iif(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 int rtnl_route_get_src_len(struct rtnl_route *);
|
extern int rtnl_route_get_src_len(struct rtnl_route *);
|
||||||
|
|
||||||
extern void rtnl_route_add_nexthop(struct rtnl_route *,
|
extern void rtnl_route_add_nexthop(struct rtnl_route *,
|
||||||
struct rtnl_nexthop *);
|
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 struct nl_list_head * rtnl_route_get_nexthops(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_cacheinfo(struct rtnl_route *,
|
extern int rtnl_route_get_nnexthops(struct rtnl_route *);
|
||||||
struct rtnl_rtcacheinfo *);
|
|
||||||
extern uint32_t rtnl_route_get_mp_algo(struct rtnl_route *);
|
extern int rtnl_route_guess_scope(struct rtnl_route *);
|
||||||
extern void rtnl_route_set_mp_algo(struct rtnl_route *, uint32_t);
|
|
||||||
|
|
||||||
extern char * rtnl_route_table2str(int, char *, size_t);
|
extern char * rtnl_route_table2str(int, char *, size_t);
|
||||||
extern int rtnl_route_str2table(const char *);
|
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 char * rtnl_route_metric2str(int, char *, size_t);
|
||||||
extern int rtnl_route_str2metric(const char *);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,8 +23,6 @@ extern "C" {
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef uint32_t realm_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mask specying the size of each realm part
|
* Mask specying the size of each realm part
|
||||||
* @ingroup rtnl
|
* @ingroup rtnl
|
||||||
|
|
|
@ -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 void rtnl_rule_set_classid(struct rtnl_rule *, uint32_t);
|
||||||
extern uint32_t rtnl_rule_get_classid(struct rtnl_rule *);
|
extern uint32_t rtnl_rule_get_classid(struct rtnl_rule *);
|
||||||
|
|
||||||
extern void rtnl_rule_set_realms(struct rtnl_rule *, realm_t);
|
extern void rtnl_rule_set_realms(struct rtnl_rule *, uint32_t);
|
||||||
extern realm_t rtnl_rule_get_realms(struct rtnl_rule *);
|
extern uint32_t rtnl_rule_get_realms(struct rtnl_rule *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(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_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD)
|
||||||
#define CT_DIFF_ADDR(ATTR, 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_prefix(a->FIELD, b->FIELD)) \
|
||||||
: CT_DIFF(ATTR, nl_addr_cmp(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_PACKETS, ct_repl.packets);
|
||||||
diff |= CT_DIFF_VAL(REPL_BYTES, ct_repl.bytes);
|
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) &
|
diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) &
|
||||||
b->ct_status_mask);
|
b->ct_status_mask);
|
||||||
else
|
else
|
||||||
|
|
|
@ -318,7 +318,7 @@ int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return !(ops->oo_compare(obj, filter, filter->ce_mask,
|
return !(ops->oo_compare(obj, filter, filter->ce_mask,
|
||||||
LOOSE_FLAG_COMPARISON));
|
LOOSE_COMPARISON));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -585,7 +585,7 @@ static int addr_compare(struct nl_object *_a, struct nl_object *_b,
|
||||||
b->a_multicast));
|
b->a_multicast));
|
||||||
diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast));
|
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,
|
diff |= ADDR_DIFF(FLAGS,
|
||||||
(a->a_flags ^ b->a_flags) & b->a_flag_mask);
|
(a->a_flags ^ b->a_flags) & b->a_flag_mask);
|
||||||
else
|
else
|
||||||
|
|
|
@ -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(ADDR, nl_addr_cmp(a->l_addr, b->l_addr));
|
||||||
diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast));
|
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,
|
diff |= LINK_DIFF(FLAGS,
|
||||||
(a->l_flags ^ b->l_flags) & b->l_flag_mask);
|
(a->l_flags ^ b->l_flags) & b->l_flag_mask);
|
||||||
else
|
else
|
||||||
|
|
|
@ -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(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
|
||||||
diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst));
|
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,
|
diff |= NEIGH_DIFF(STATE,
|
||||||
(a->n_state ^ b->n_state) & b->n_state_mask);
|
(a->n_state ^ b->n_state) & b->n_state_mask);
|
||||||
diff |= NEIGH_DIFF(FLAGS,
|
diff |= NEIGH_DIFF(FLAGS,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* License as published by the Free Software Foundation version 2.1
|
* License as published by the Free Software Foundation version 2.1
|
||||||
* of the License.
|
* of the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,6 +21,14 @@
|
||||||
#include <netlink/route/rtnl.h>
|
#include <netlink/route/rtnl.h>
|
||||||
#include <netlink/route/route.h>
|
#include <netlink/route/route.h>
|
||||||
|
|
||||||
|
/** @cond SKIP */
|
||||||
|
#define NH_ATTR_FLAGS 0x000001
|
||||||
|
#define NH_ATTR_WEIGHT 0x000002
|
||||||
|
#define NH_ATTR_IFINDEX 0x000004
|
||||||
|
#define NH_ATTR_GATEWAY 0x000008
|
||||||
|
#define NH_ATTR_REALMS 0x000010
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Allocation/Freeing
|
* @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_flag_mask = src->rtnh_flag_mask;
|
||||||
nh->rtnh_weight = src->rtnh_weight;
|
nh->rtnh_weight = src->rtnh_weight;
|
||||||
nh->rtnh_ifindex = src->rtnh_ifindex;
|
nh->rtnh_ifindex = src->rtnh_ifindex;
|
||||||
nh->rtnh_mask = src->rtnh_mask;
|
nh->ce_mask = src->ce_mask;
|
||||||
|
|
||||||
if (src->rtnh_gateway) {
|
if (src->rtnh_gateway) {
|
||||||
nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
|
nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
|
||||||
|
@ -74,78 +82,251 @@ void rtnl_route_nh_free(struct rtnl_nexthop *nh)
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
|
||||||
* @name Attributes
|
uint32_t attrs, int loose)
|
||||||
*/
|
|
||||||
|
|
||||||
void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, int weight)
|
|
||||||
{
|
{
|
||||||
nh->rtnh_weight = weight;
|
int diff = 0;
|
||||||
nh->rtnh_mask |= NEXTHOP_HAS_WEIGHT;
|
|
||||||
|
#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)
|
struct nl_cache *link_cache;
|
||||||
return nh->rtnh_weight;
|
char buf[128];
|
||||||
else
|
|
||||||
return 0;
|
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)
|
void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
|
||||||
{
|
{
|
||||||
nh->rtnh_ifindex = 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)
|
int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
|
||||||
{
|
{
|
||||||
if (nh->rtnh_mask & NEXTHOP_HAS_IFINDEX)
|
return nh->rtnh_ifindex;
|
||||||
return nh->rtnh_ifindex;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
|
void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
|
||||||
{
|
{
|
||||||
struct nl_addr *old = nh->rtnh_gateway;
|
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)
|
if (old)
|
||||||
nl_addr_put(old);
|
nl_addr_put(old);
|
||||||
|
|
||||||
nh->rtnh_mask |= NEXTHOP_HAS_GATEWAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
|
struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
|
||||||
{
|
{
|
||||||
if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
|
return nh->rtnh_gateway;
|
||||||
return nh->rtnh_gateway;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
|
void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
|
||||||
{
|
{
|
||||||
nh->rtnh_flag_mask |= flags;
|
nh->rtnh_flag_mask |= flags;
|
||||||
nh->rtnh_flags |= 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)
|
void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
|
||||||
{
|
{
|
||||||
nh->rtnh_flag_mask |= flags;
|
nh->rtnh_flag_mask |= flags;
|
||||||
nh->rtnh_flags &= ~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)
|
unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
|
||||||
{
|
{
|
||||||
if (nh->rtnh_mask & NEXTHOP_HAS_FLAGS)
|
return nh->rtnh_flags;
|
||||||
return nh->rtnh_flags;
|
}
|
||||||
else
|
|
||||||
return 0;
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* License as published by the Free Software Foundation version 2.1
|
* License as published by the Free Software Foundation version 2.1
|
||||||
* of the License.
|
* of the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,183 +27,16 @@
|
||||||
|
|
||||||
static struct nl_cache_ops rtnl_route_ops;
|
static struct 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,
|
static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
|
||||||
struct nlmsghdr *nlh, struct nl_parser_param *pp)
|
struct nlmsghdr *nlh, struct nl_parser_param *pp)
|
||||||
{
|
{
|
||||||
struct rtmsg *rtm;
|
|
||||||
struct rtnl_route *route;
|
struct rtnl_route *route;
|
||||||
struct nlattr *tb[RTA_MAX + 1];
|
|
||||||
struct nl_addr *src = NULL, *dst = NULL, *addr;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
route = rtnl_route_alloc();
|
if (!(route = rtnl_route_parse(nlh)))
|
||||||
if (!route) {
|
return -EINVAL;
|
||||||
err = nl_errno(ENOMEM);
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
route->ce_msgtype = nlh->nlmsg_type;
|
if ((err = pp->pp_cb((struct nl_object *) route, pp)) < 0)
|
||||||
|
|
||||||
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)
|
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
err = P_ACCEPT;
|
err = P_ACCEPT;
|
||||||
|
@ -211,10 +44,6 @@ static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
|
||||||
errout:
|
errout:
|
||||||
rtnl_route_put(route);
|
rtnl_route_put(route);
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
errout_errno:
|
|
||||||
err = nl_get_errno();
|
|
||||||
goto errout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int route_request_update(struct nl_cache *c, struct nl_handle *h)
|
static int route_request_update(struct nl_cache *c, struct nl_handle *h)
|
||||||
|
@ -265,102 +94,17 @@ static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct nl_msg *msg;
|
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);
|
msg = nlmsg_alloc_simple(cmd, flags);
|
||||||
if (msg == NULL)
|
if (msg == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
|
if (rtnl_route_build_msg(msg, tmpl) < 0) {
|
||||||
goto nla_put_failure;
|
nlmsg_free(msg);
|
||||||
|
return NULL;
|
||||||
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 0
|
|
||||||
RTA_IIF,
|
|
||||||
RTA_MULTIPATH,
|
|
||||||
RTA_PROTOINFO,
|
|
||||||
RTA_FLOW,
|
|
||||||
RTA_CACHEINFO,
|
|
||||||
RTA_SESSION,
|
|
||||||
RTA_MP_ALGO,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
|
|
||||||
nla_put_failure:
|
|
||||||
nlmsg_free(msg);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
|
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);
|
return build_route_msg(tmpl, RTM_DELROUTE, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route,
|
int rtnl_route_delete(struct nl_handle *handle, struct rtnl_route *route,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct nl_msg *msg;
|
struct nl_msg *msg;
|
||||||
int err;
|
int err;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -840,13 +840,13 @@ int rtnl_rule_get_action(struct rtnl_rule *rule)
|
||||||
return nl_errno(ENOENT);
|
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->r_realms = realms;
|
||||||
rule->ce_mask |= RULE_ATTR_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)
|
if (rule->ce_mask & RULE_ATTR_REALMS)
|
||||||
return rule->r_realms;
|
return rule->r_realms;
|
||||||
|
|
|
@ -23,8 +23,8 @@ nl-qdisc-add
|
||||||
nl-qdisc-delete
|
nl-qdisc-delete
|
||||||
nl-qdisc-dump
|
nl-qdisc-dump
|
||||||
nl-route-add
|
nl-route-add
|
||||||
nl-route-del
|
nl-route-delete
|
||||||
nl-route-dump
|
nl-route-list
|
||||||
nl-route-get
|
nl-route-get
|
||||||
nl-rule-dump
|
nl-rule-dump
|
||||||
nl-tctree-dump
|
nl-tctree-dump
|
||||||
|
|
13
src/Makefile
13
src/Makefile
|
@ -6,36 +6,37 @@
|
||||||
# License as published by the Free Software Foundation version 2.1
|
# License as published by the Free Software Foundation version 2.1
|
||||||
# of the License.
|
# of the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
# Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
#
|
#
|
||||||
|
|
||||||
ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),)
|
ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),)
|
||||||
include ../Makefile.opts
|
include ../Makefile.opts
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS += -L../lib -lnl utils.o
|
LDFLAGS += -L../lib -lnl
|
||||||
CIN := $(wildcard nl-*.c) $(wildcard genl-*.c) $(wildcard nf-*.c)
|
CIN := $(wildcard nl-*.c) $(wildcard genl-*.c) $(wildcard nf-*.c)
|
||||||
TOOLS := $(CIN:%.c=%)
|
TOOLS := $(CIN:%.c=%)
|
||||||
|
|
||||||
all: $(TOOLS)
|
all: $(TOOLS)
|
||||||
|
|
||||||
$(TOOLS): utils.o
|
$(TOOLS): utils.o
|
||||||
|
nl-route-add nl-route-delete nl-route-list: route-utils.o
|
||||||
|
|
||||||
nl-%: nl-%.c
|
nl-%: nl-%.c
|
||||||
@echo " LD $@"; \
|
@echo " LD $@"; \
|
||||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
genl-%: genl-%.c
|
genl-%: genl-%.c
|
||||||
@echo " LD $@"; \
|
@echo " LD $@"; \
|
||||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
nf-%: nf-%.c
|
nf-%: nf-%.c
|
||||||
@echo " LD $@"; \
|
@echo " LD $@"; \
|
||||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo " CLEAN src"; \
|
@echo " CLEAN src"; \
|
||||||
rm -f $(TOOLS) utils.o
|
rm -f $(TOOLS) *.o
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
|
||||||
|
|
|
@ -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 <tgraf@suug.ch>
|
|
||||||
*/
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
|
@ -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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation version 2.1
|
* License as published by the Free Software Foundation version 2.1
|
||||||
* of the License.
|
* of the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils.h"
|
#include "route-utils.h"
|
||||||
|
|
||||||
|
static struct nl_cache *link_cache, *route_cache;
|
||||||
|
|
||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"Usage: nl-route-add [<filter>]\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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "f_route.c"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct nl_handle *nlh;
|
struct nl_handle *nlh;
|
||||||
struct nl_cache *link_cache, *route_cache;
|
|
||||||
struct rtnl_route *route;
|
struct rtnl_route *route;
|
||||||
int err = 1;
|
int err = 1;
|
||||||
|
|
||||||
if (nltool_init(argc, argv) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (argc < 2 || !strcmp(argv[1], "-h"))
|
|
||||||
print_usage();
|
|
||||||
|
|
||||||
nlh = nltool_alloc_handle();
|
nlh = nltool_alloc_handle();
|
||||||
if (!nlh)
|
nltool_connect(nlh, NETLINK_ROUTE);
|
||||||
goto errout;
|
link_cache = nltool_alloc_link_cache(nlh);
|
||||||
|
route_cache = nltool_alloc_route_cache(nlh);
|
||||||
|
|
||||||
route = rtnl_route_alloc();
|
route = rtnl_route_alloc();
|
||||||
if (!route)
|
if (!route)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
if (nltool_connect(nlh, NETLINK_ROUTE) < 0)
|
for (;;) {
|
||||||
goto errout_free;
|
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);
|
c = getopt_long(argc, argv, "d:s:i:n:P:t:m:p:S:x:T:h", long_opts, &optidx);
|
||||||
if (!link_cache)
|
if (c == -1)
|
||||||
goto errout_close;
|
break;
|
||||||
|
|
||||||
route_cache = nltool_alloc_route_cache(nlh);
|
switch (c) {
|
||||||
if (!route_cache)
|
case 'd': parse_dst(route, optarg); break;
|
||||||
goto errout_link_cache;
|
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) {
|
if (rtnl_route_add(nlh, route, 0) < 0) {
|
||||||
fprintf(stderr, "rtnl_route_add failed: %s\n",
|
fprintf(stderr, "rtnl_route_add failed: %s\n", nl_geterror());
|
||||||
nl_geterror());
|
goto errout_free;
|
||||||
goto errout_route_cache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
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:
|
errout_free:
|
||||||
rtnl_route_put(route);
|
rtnl_route_put(route);
|
||||||
errout:
|
errout:
|
||||||
|
nl_cache_free(route_cache);
|
||||||
|
nl_cache_free(link_cache);
|
||||||
|
nl_close(nlh);
|
||||||
nl_handle_destroy(nlh);
|
nl_handle_destroy(nlh);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <tgraf@suug.ch>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static void print_usage(void)
|
|
||||||
{
|
|
||||||
printf(
|
|
||||||
"Usage: nl-route-del [<filter>]\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;
|
|
||||||
}
|
|
|
@ -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 <tgraf@suug.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -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 <tgraf@suug.ch>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static void print_usage(void)
|
|
||||||
{
|
|
||||||
printf(
|
|
||||||
"Usage: nl-route-dump <mode> [<filter>]\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;
|
|
||||||
}
|
|
|
@ -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 <tgraf@suug.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -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 <tgraf@suug.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
|
@ -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 <tgraf@suug.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
70
src/utils.c
70
src/utils.c
|
@ -13,6 +13,21 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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[])
|
int nltool_init(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -24,7 +39,7 @@ int nltool_connect(struct nl_handle *nlh, int protocol)
|
||||||
|
|
||||||
err = nl_connect(nlh, protocol);
|
err = nl_connect(nlh, protocol);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
fprintf(stderr, "Unable to connect netlink socket%s\n",
|
fatal(err, "Unable to connect netlink socket: %s",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -32,7 +47,12 @@ int nltool_connect(struct nl_handle *nlh, int protocol)
|
||||||
|
|
||||||
struct nl_handle *nltool_alloc_handle(void)
|
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)
|
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);
|
cache = rtnl_link_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve link cache: %s\n",
|
fatal(nl_get_errno(), "Unable to retrieve link cache: %s",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
@ -85,10 +105,10 @@ struct nl_cache *nltool_alloc_addr_cache(struct nl_handle *nlh)
|
||||||
|
|
||||||
cache = rtnl_addr_alloc_cache(nlh);
|
cache = rtnl_addr_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve address cache: %s\n",
|
fatal(nl_get_errno(), "Unable to retrieve address cache: %s\n",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
@ -99,10 +119,10 @@ struct nl_cache *nltool_alloc_neigh_cache(struct nl_handle *nlh)
|
||||||
|
|
||||||
cache = rtnl_neigh_alloc_cache(nlh);
|
cache = rtnl_neigh_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve neighbour cache: %s\n",
|
fatal(nl_get_errno(), "Unable to retrieve neighbour cache: %s\n",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
@ -113,8 +133,8 @@ struct nl_cache *nltool_alloc_neightbl_cache(struct nl_handle *nlh)
|
||||||
|
|
||||||
cache = rtnl_neightbl_alloc_cache(nlh);
|
cache = rtnl_neightbl_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve neighbour table "
|
fatal(nl_get_errno(), "Unable to retrieve neighbour table "
|
||||||
"cache: %s\n", nl_geterror());
|
"cache: %s", nl_geterror());
|
||||||
else
|
else
|
||||||
nl_cache_mngt_provide(cache);
|
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);
|
cache = rtnl_route_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve route cache: %s\n",
|
fatal(nl_get_errno(), "Unable to retrieve route cache: %s\n",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
@ -141,10 +161,10 @@ struct nl_cache *nltool_alloc_rule_cache(struct nl_handle *nlh)
|
||||||
|
|
||||||
cache = rtnl_rule_alloc_cache(nlh);
|
cache = rtnl_rule_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve rule cache: %s\n",
|
fatal(nl_get_errno(), "Unable to retrieve rule cache: %s\n",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
@ -155,10 +175,10 @@ struct nl_cache *nltool_alloc_qdisc_cache(struct nl_handle *nlh)
|
||||||
|
|
||||||
cache = rtnl_qdisc_alloc_cache(nlh);
|
cache = rtnl_qdisc_alloc_cache(nlh);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
fprintf(stderr, "Unable to retrieve qdisc cache: %s\n",
|
fatal(nl_get_errno(), "Unable to retrieve qdisc cache: %s\n",
|
||||||
nl_geterror());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return 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);
|
cache = genl_ctrl_alloc_cache(nlh);
|
||||||
if (!cache)
|
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());
|
nl_geterror());
|
||||||
else
|
|
||||||
nl_cache_mngt_provide(cache);
|
nl_cache_mngt_provide(cache);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
#include <netlink/genl/mngt.h>
|
#include <netlink/genl/mngt.h>
|
||||||
#include <netlink/netfilter/ct.h>
|
#include <netlink/netfilter/ct.h>
|
||||||
|
|
||||||
|
extern void fatal(int err, const char *fmt, ...);
|
||||||
|
|
||||||
extern int nltool_init(int argc, char *argv[]);
|
extern int nltool_init(int argc, char *argv[]);
|
||||||
extern int nltool_connect(struct nl_handle *nlh, int protocol);
|
extern int nltool_connect(struct nl_handle *nlh, int protocol);
|
||||||
extern struct nl_addr *nltool_addr_parse(const char *str);
|
extern struct nl_addr *nltool_addr_parse(const char *str);
|
||||||
|
|
Reference in New Issue