KRT: Add support for plenty of kernel route metrics
Linux kernel route metrics (RTA_METRICS netlink route attribute) are represented and accessible as new route attributes: krt_mtu, krt_window, krt_rtt, krt_rttvar, krt_sstresh, krt_cwnd, krt_advmss, krt_reordering, krt_hoplimit, krt_initcwnd, krt_rto_min, krt_initrwnd, krt_quickack, krt_lock_mtu, krt_lock_window, krt_lock_rtt, krt_lock_rttvar, krt_lock_sstresh, krt_lock_cwnd, krt_lock_advmss, krt_lock_reordering, krt_lock_hoplimit, krt_lock_rto_min, krt_feature_ecn, krt_feature_allfrag
This commit is contained in:
parent
315f23a047
commit
9fdf9d29b6
9 changed files with 368 additions and 65 deletions
|
@ -2248,7 +2248,7 @@ these attributes:
|
||||||
|
|
||||||
<tag>ip <cf/krt_prefsrc/</tag> (Linux)
|
<tag>ip <cf/krt_prefsrc/</tag> (Linux)
|
||||||
The preferred source address. Used in source address selection for
|
The preferred source address. Used in source address selection for
|
||||||
outgoing packets. Have to be one of IP addresses of the router.
|
outgoing packets. Has to be one of the IP addresses of the router.
|
||||||
|
|
||||||
<tag>int <cf/krt_realm/</tag> (Linux)
|
<tag>int <cf/krt_realm/</tag> (Linux)
|
||||||
The realm of the route. Can be used for traffic classification.
|
The realm of the route. Can be used for traffic classification.
|
||||||
|
|
|
@ -461,8 +461,14 @@ static inline void rt_lock_source(struct rte_src *src) { src->uc++; }
|
||||||
static inline void rt_unlock_source(struct rte_src *src) { src->uc--; }
|
static inline void rt_unlock_source(struct rte_src *src) { src->uc--; }
|
||||||
void rt_prune_sources(void);
|
void rt_prune_sources(void);
|
||||||
|
|
||||||
|
struct ea_walk_state {
|
||||||
|
ea_list *eattrs; /* Ccurrent ea_list, initially set by caller */
|
||||||
|
eattr *ea; /* Current eattr, initially NULL */
|
||||||
|
u32 visited[4]; /* Bitfield, limiting max to 128 */
|
||||||
|
};
|
||||||
|
|
||||||
eattr *ea_find(ea_list *, unsigned ea);
|
eattr *ea_find(ea_list *, unsigned ea);
|
||||||
|
eattr *ea_walk(struct ea_walk_state *s, uint id, uint max);
|
||||||
int ea_get_int(ea_list *, unsigned ea, int def);
|
int ea_get_int(ea_list *, unsigned ea, int def);
|
||||||
void ea_dump(ea_list *);
|
void ea_dump(ea_list *);
|
||||||
void ea_sort(ea_list *); /* Sort entries in all sub-lists */
|
void ea_sort(ea_list *); /* Sort entries in all sub-lists */
|
||||||
|
|
|
@ -307,6 +307,82 @@ ea_find(ea_list *e, unsigned id)
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ea_walk - walk through extended attributes
|
||||||
|
* @s: walk state structure
|
||||||
|
* @id: start of attribute ID interval
|
||||||
|
* @max: length of attribute ID interval
|
||||||
|
*
|
||||||
|
* Given an extended attribute list, ea_walk() walks through the list looking
|
||||||
|
* for first occurrences of attributes with ID in specified interval from @id to
|
||||||
|
* (@id + @max - 1), returning pointers to found &eattr structures, storing its
|
||||||
|
* walk state in @s for subsequent calls.
|
||||||
|
|
||||||
|
* The function ea_walk() is supposed to be called in a loop, with initially
|
||||||
|
* zeroed walk state structure @s with filled the initial extended attribute
|
||||||
|
* list, returning one found attribute in each call or %NULL when no other
|
||||||
|
* attribute exists. The extended attribute list or the arguments should not be
|
||||||
|
* modified between calls. The maximum value of @max is 128.
|
||||||
|
*/
|
||||||
|
eattr *
|
||||||
|
ea_walk(struct ea_walk_state *s, uint id, uint max)
|
||||||
|
{
|
||||||
|
ea_list *e = s->eattrs;
|
||||||
|
eattr *a = s->ea;
|
||||||
|
eattr *a_max;
|
||||||
|
|
||||||
|
max = id + max;
|
||||||
|
|
||||||
|
if (a)
|
||||||
|
goto step;
|
||||||
|
|
||||||
|
for (; e; e = e->next)
|
||||||
|
{
|
||||||
|
if (e->flags & EALF_BISECT)
|
||||||
|
{
|
||||||
|
int l, r, m;
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
r = e->count - 1;
|
||||||
|
while (l < r)
|
||||||
|
{
|
||||||
|
m = (l+r) / 2;
|
||||||
|
if (e->attrs[m].id < id)
|
||||||
|
l = m + 1;
|
||||||
|
else
|
||||||
|
r = m;
|
||||||
|
}
|
||||||
|
a = e->attrs + l;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a = e->attrs;
|
||||||
|
|
||||||
|
step:
|
||||||
|
a_max = e->attrs + e->count;
|
||||||
|
for (; a < a_max; a++)
|
||||||
|
if ((a->id >= id) && (a->id < max))
|
||||||
|
{
|
||||||
|
int n = a->id - id;
|
||||||
|
|
||||||
|
if (BIT32_TEST(s->visited, n))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BIT32_SET(s->visited, n);
|
||||||
|
|
||||||
|
if ((a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s->eattrs = e;
|
||||||
|
s->ea = a;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
else if (e->flags & EALF_BISECT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ea_get_int - fetch an integer attribute
|
* ea_get_int - fetch an integer attribute
|
||||||
* @e: attribute list
|
* @e: attribute list
|
||||||
|
|
|
@ -44,5 +44,7 @@ struct krt_state {
|
||||||
|
|
||||||
static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
|
static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
|
||||||
|
|
||||||
|
static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { }
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,59 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; }
|
||||||
|
|
||||||
/* Kernel routes */
|
/* Kernel routes */
|
||||||
|
|
||||||
|
#define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 0x10)
|
||||||
|
#define EA_KRT_REALM EA_CODE(EAP_KRT, 0x11)
|
||||||
|
|
||||||
|
|
||||||
|
#define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */
|
||||||
|
#define KRT_METRICS_OFFSET 0x20 /* Offset of EA_KRT_* vs RTAX_* */
|
||||||
|
|
||||||
|
#define KRT_FEATURES_MAX 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following attributes are parts of RTA_METRICS kernel route attribute, their
|
||||||
|
* ids must be consistent with their RTAX_* constants (+ KRT_METRICS_OFFSET)
|
||||||
|
*/
|
||||||
|
#define EA_KRT_METRICS EA_CODE(EAP_KRT, 0x20) /* Dummy one */
|
||||||
|
#define EA_KRT_LOCK EA_CODE(EAP_KRT, 0x21)
|
||||||
|
#define EA_KRT_MTU EA_CODE(EAP_KRT, 0x22)
|
||||||
|
#define EA_KRT_WINDOW EA_CODE(EAP_KRT, 0x23)
|
||||||
|
#define EA_KRT_RTT EA_CODE(EAP_KRT, 0x24)
|
||||||
|
#define EA_KRT_RTTVAR EA_CODE(EAP_KRT, 0x25)
|
||||||
|
#define EA_KRT_SSTRESH EA_CODE(EAP_KRT, 0x26)
|
||||||
|
#define EA_KRT_CWND EA_CODE(EAP_KRT, 0x27)
|
||||||
|
#define EA_KRT_ADVMSS EA_CODE(EAP_KRT, 0x28)
|
||||||
|
#define EA_KRT_REORDERING EA_CODE(EAP_KRT, 0x29)
|
||||||
|
#define EA_KRT_HOPLIMIT EA_CODE(EAP_KRT, 0x2a)
|
||||||
|
#define EA_KRT_INITCWND EA_CODE(EAP_KRT, 0x2b)
|
||||||
|
#define EA_KRT_FEATURES EA_CODE(EAP_KRT, 0x2c)
|
||||||
|
#define EA_KRT_RTO_MIN EA_CODE(EAP_KRT, 0x2d)
|
||||||
|
#define EA_KRT_INITRWND EA_CODE(EAP_KRT, 0x2e)
|
||||||
|
#define EA_KRT_QUICKACK EA_CODE(EAP_KRT, 0x2f)
|
||||||
|
|
||||||
|
/* Bits of EA_KRT_LOCK, also based on RTAX_* constants */
|
||||||
|
#define EA_KRT_LOCK_MTU EA_KRT_LOCK | EA_BIT(0x2)
|
||||||
|
#define EA_KRT_LOCK_WINDOW EA_KRT_LOCK | EA_BIT(0x3)
|
||||||
|
#define EA_KRT_LOCK_RTT EA_KRT_LOCK | EA_BIT(0x4)
|
||||||
|
#define EA_KRT_LOCK_RTTVAR EA_KRT_LOCK | EA_BIT(0x5)
|
||||||
|
#define EA_KRT_LOCK_SSTHRESH EA_KRT_LOCK | EA_BIT(0x6)
|
||||||
|
#define EA_KRT_LOCK_CWND EA_KRT_LOCK | EA_BIT(0x7)
|
||||||
|
#define EA_KRT_LOCK_ADVMSS EA_KRT_LOCK | EA_BIT(0x8)
|
||||||
|
#define EA_KRT_LOCK_REORDERING EA_KRT_LOCK | EA_BIT(0x9)
|
||||||
|
#define EA_KRT_LOCK_HOPLIMIT EA_KRT_LOCK | EA_BIT(0xa)
|
||||||
|
// define EA_KRT_LOCK_INITCWND EA_KRT_LOCK | EA_BIT(0xb)
|
||||||
|
// define EA_KRT_LOCK_FEATURES EA_KRT_LOCK | EA_BIT(0xc)
|
||||||
|
#define EA_KRT_LOCK_RTO_MIN EA_KRT_LOCK | EA_BIT(0xd)
|
||||||
|
// define EA_KRT_LOCK_INITRWND EA_KRT_LOCK | EA_BIT(0xe)
|
||||||
|
|
||||||
|
/* Bits of EA_KRT_FEATURES, based on RTAX_FEATURE_* constants */
|
||||||
|
#define EA_KRT_FEATURE_ECN EA_KRT_FEATURES | EA_BIT(0x0)
|
||||||
|
// define EA_KRT_FEATURE_SACK EA_KRT_FEATURES | EA_BIT(0x1)
|
||||||
|
// define EA_KRT_FEATURE_TSTAMP EA_KRT_FEATURES | EA_BIT(0x2)
|
||||||
|
#define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define NL_NUM_TABLES 256
|
#define NL_NUM_TABLES 256
|
||||||
|
|
||||||
struct krt_params {
|
struct krt_params {
|
||||||
|
|
|
@ -10,7 +10,12 @@ CF_HDR
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(KERNEL, TABLE, KRT_PREFSRC, KRT_REALM)
|
CF_KEYWORDS(KERNEL, TABLE, KRT_PREFSRC, KRT_REALM, KRT_MTU, KRT_WINDOW, KRT_RTT,
|
||||||
|
KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING,
|
||||||
|
KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK,
|
||||||
|
KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR,
|
||||||
|
KRT_LOCK_SSTRESH, KRT_LOCK_CWND, KRT_LOCK_ADVMSS, KRT_LOCK_REORDERING,
|
||||||
|
KRT_LOCK_HOPLIMIT, KRT_LOCK_RTO_MIN, KRT_FEATURE_ECN, KRT_FEATURE_ALLFRAG)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -24,8 +29,37 @@ kern_sys_item:
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
CF_ADDTO(dynamic_attr, KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); })
|
CF_ADDTO(dynamic_attr, KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); })
|
||||||
CF_ADDTO(dynamic_attr, KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); })
|
CF_ADDTO(dynamic_attr, KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); })
|
||||||
|
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); })
|
||||||
|
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_MTU); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_WINDOW); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTT); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTTVAR); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_SSTHRESH); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_CWND); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_ADVMSS); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_REORDERING); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_HOPLIMIT); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTO_MIN); })
|
||||||
|
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_FEATURE_ECN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ECN); })
|
||||||
|
CF_ADDTO(dynamic_attr, KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ALLFRAG); })
|
||||||
|
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
||||||
|
|
|
@ -238,21 +238,24 @@ nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
struct rtattr *
|
||||||
nl_add_attr(struct nlmsghdr *h, unsigned bufsize, unsigned code,
|
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
|
||||||
void *data, unsigned dlen)
|
|
||||||
{
|
{
|
||||||
unsigned len = RTA_LENGTH(dlen);
|
uint pos = NLMSG_ALIGN(h->nlmsg_len);
|
||||||
unsigned pos = NLMSG_ALIGN(h->nlmsg_len);
|
uint len = RTA_LENGTH(dlen);
|
||||||
struct rtattr *a;
|
|
||||||
|
|
||||||
if (pos + len > bufsize)
|
if (pos + len > bufsize)
|
||||||
bug("nl_add_attr: packet buffer overflow");
|
bug("nl_add_attr: packet buffer overflow");
|
||||||
a = (struct rtattr *)((char *)h + pos);
|
|
||||||
|
struct rtattr *a = (struct rtattr *)((char *)h + pos);
|
||||||
a->rta_type = code;
|
a->rta_type = code;
|
||||||
a->rta_len = len;
|
a->rta_len = len;
|
||||||
h->nlmsg_len = pos + len;
|
h->nlmsg_len = pos + len;
|
||||||
memcpy(RTA_DATA(a), data, dlen);
|
|
||||||
|
if (dlen > 0)
|
||||||
|
memcpy(RTA_DATA(a), data, dlen);
|
||||||
|
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -268,49 +271,59 @@ nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa)
|
||||||
nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
|
nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RTNH_SIZE (sizeof(struct rtnexthop) + sizeof(struct rtattr) + sizeof(ip_addr))
|
static inline struct rtattr *
|
||||||
|
nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
|
||||||
static inline void
|
|
||||||
add_mpnexthop(char *buf, ip_addr ipa, unsigned iface, unsigned char weight)
|
|
||||||
{
|
{
|
||||||
struct rtnexthop *nh = (void *) buf;
|
return nl_add_attr(h, bufsize, code, NULL, 0);
|
||||||
struct rtattr *rt = (void *) (buf + sizeof(*nh));
|
|
||||||
nh->rtnh_len = RTNH_SIZE;
|
|
||||||
nh->rtnh_flags = 0;
|
|
||||||
nh->rtnh_hops = weight;
|
|
||||||
nh->rtnh_ifindex = iface;
|
|
||||||
rt->rta_len = sizeof(*rt) + sizeof(ipa);
|
|
||||||
rt->rta_type = RTA_GATEWAY;
|
|
||||||
ipa_hton(ipa);
|
|
||||||
memcpy(buf + sizeof(*nh) + sizeof(*rt), &ipa, sizeof(ipa));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
|
||||||
|
{
|
||||||
|
a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct rtnexthop *
|
||||||
|
nl_open_nexthop(struct nlmsghdr *h, uint bufsize)
|
||||||
|
{
|
||||||
|
uint pos = NLMSG_ALIGN(h->nlmsg_len);
|
||||||
|
uint len = RTNH_LENGTH(0);
|
||||||
|
|
||||||
|
if (pos + len > bufsize)
|
||||||
|
bug("nl_open_nexthop: packet buffer overflow");
|
||||||
|
|
||||||
|
h->nlmsg_len = pos + len;
|
||||||
|
|
||||||
|
return (void *)h + pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
|
||||||
|
{
|
||||||
|
nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
|
nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
|
||||||
{
|
{
|
||||||
unsigned len = sizeof(struct rtattr);
|
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
|
||||||
unsigned pos = NLMSG_ALIGN(h->nlmsg_len);
|
|
||||||
char *buf = (char *)h + pos;
|
|
||||||
struct rtattr *rt = (void *) buf;
|
|
||||||
buf += len;
|
|
||||||
|
|
||||||
for (; nh; nh = nh->next)
|
for (; nh; nh = nh->next)
|
||||||
{
|
{
|
||||||
len += RTNH_SIZE;
|
struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
|
||||||
if (pos + len > bufsize)
|
|
||||||
bug("nl_add_multipath: packet buffer overflow");
|
|
||||||
|
|
||||||
add_mpnexthop(buf, nh->gw, nh->iface->index, nh->weight);
|
rtnh->rtnh_flags = 0;
|
||||||
buf += RTNH_SIZE;
|
rtnh->rtnh_hops = nh->weight;
|
||||||
}
|
rtnh->rtnh_ifindex = nh->iface->index;
|
||||||
|
|
||||||
rt->rta_type = RTA_MULTIPATH;
|
nl_add_attr_u32(h, bufsize, RTA_GATEWAY, nh->gw);
|
||||||
rt->rta_len = len;
|
|
||||||
h->nlmsg_len = pos + len;
|
nl_close_nexthop(h, rtnh);
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_close_attr(h, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct mpnh *
|
static struct mpnh *
|
||||||
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
||||||
{
|
{
|
||||||
|
@ -374,6 +387,47 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
|
||||||
|
{
|
||||||
|
struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
|
||||||
|
int t;
|
||||||
|
|
||||||
|
for (t = 1; t < max; t++)
|
||||||
|
if (metrics[0] & (1 << t))
|
||||||
|
nl_add_attr_u32(h, bufsize, t, metrics[t]);
|
||||||
|
|
||||||
|
nl_close_attr(h, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
|
||||||
|
{
|
||||||
|
struct rtattr *a = RTA_DATA(hdr);
|
||||||
|
int len = RTA_PAYLOAD(hdr);
|
||||||
|
|
||||||
|
metrics[0] = 0;
|
||||||
|
for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
|
||||||
|
{
|
||||||
|
if (a->rta_type == RTA_UNSPEC)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (a->rta_type >= max)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (RTA_PAYLOAD(a) != 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
metrics[0] |= 1 << a->rta_type;
|
||||||
|
metrics[a->rta_type] = *(u32 *)RTA_DATA(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scanning of interfaces
|
* Scanning of interfaces
|
||||||
|
@ -617,7 +671,7 @@ nh_bufsize(struct mpnh *nh)
|
||||||
{
|
{
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
for (; nh != NULL; nh = nh->next)
|
for (; nh != NULL; nh = nh->next)
|
||||||
rv += RTNH_SIZE;
|
rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +684,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr h;
|
struct nlmsghdr h;
|
||||||
struct rtmsg r;
|
struct rtmsg r;
|
||||||
char buf[128 + nh_bufsize(a->nexthops)];
|
char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
|
||||||
} r;
|
} r;
|
||||||
|
|
||||||
DBG("nl_send_route(%I/%d,new=%d)\n", net->n.prefix, net->n.pxlen, new);
|
DBG("nl_send_route(%I/%d,new=%d)\n", net->n.prefix, net->n.pxlen, new);
|
||||||
|
@ -649,13 +703,8 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
r.r.rtm_scope = RT_SCOPE_UNIVERSE;
|
r.r.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||||
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
|
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
|
||||||
|
|
||||||
u32 metric = 0;
|
|
||||||
if (new && e->attrs->source == RTS_INHERIT)
|
|
||||||
metric = e->u.krt.metric;
|
|
||||||
if (ea = ea_find(eattrs, EA_KRT_METRIC))
|
if (ea = ea_find(eattrs, EA_KRT_METRIC))
|
||||||
metric = ea->u.data;
|
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
|
||||||
if (metric != 0)
|
|
||||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, metric);
|
|
||||||
|
|
||||||
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
|
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
|
||||||
nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
|
nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
|
||||||
|
@ -663,6 +712,22 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
if (ea = ea_find(eattrs, EA_KRT_REALM))
|
if (ea = ea_find(eattrs, EA_KRT_REALM))
|
||||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
|
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
|
||||||
|
|
||||||
|
|
||||||
|
u32 metrics[KRT_METRICS_MAX];
|
||||||
|
metrics[0] = 0;
|
||||||
|
|
||||||
|
struct ea_walk_state ews = { .eattrs = eattrs };
|
||||||
|
while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
|
||||||
|
{
|
||||||
|
int id = ea->id - EA_KRT_METRICS;
|
||||||
|
metrics[0] |= 1 << id;
|
||||||
|
metrics[id] = ea->u.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metrics[0])
|
||||||
|
nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
|
||||||
|
|
||||||
|
|
||||||
/* a->iface != NULL checked in krt_capable() for router and device routes */
|
/* a->iface != NULL checked in krt_capable() for router and device routes */
|
||||||
|
|
||||||
switch (a->dest)
|
switch (a->dest)
|
||||||
|
@ -834,7 +899,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
net->n.prefix, net->n.pxlen);
|
net->n.prefix, net->n.pxlen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -896,7 +961,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
e->u.krt.type = i->rtm_type;
|
e->u.krt.type = i->rtm_type;
|
||||||
|
|
||||||
if (a[RTA_PRIORITY])
|
if (a[RTA_PRIORITY])
|
||||||
memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
|
memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));
|
||||||
else
|
else
|
||||||
e->u.krt.metric = 0;
|
e->u.krt.metric = 0;
|
||||||
|
|
||||||
|
@ -932,6 +997,38 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
memcpy(&ea->attrs[0].u.data, RTA_DATA(a[RTA_FLOW]), 4);
|
memcpy(&ea->attrs[0].u.data, RTA_DATA(a[RTA_FLOW]), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (a[RTA_METRICS])
|
||||||
|
{
|
||||||
|
u32 metrics[KRT_METRICS_MAX];
|
||||||
|
ea_list *ea = alloca(sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
|
||||||
|
int t, n = 0;
|
||||||
|
|
||||||
|
if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
|
||||||
|
{
|
||||||
|
log(L_ERR "KRT: Received route %I/%d with strange RTA_METRICS attribute",
|
||||||
|
net->n.prefix, net->n.pxlen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (t = 1; t < KRT_METRICS_MAX; t++)
|
||||||
|
if (metrics[0] & (1 << t))
|
||||||
|
{
|
||||||
|
ea->attrs[n].id = EA_CODE(EAP_KRT, KRT_METRICS_OFFSET + t);
|
||||||
|
ea->attrs[n].flags = 0;
|
||||||
|
ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */
|
||||||
|
ea->attrs[n].u.data = metrics[t];
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
ea->next = ra.eattrs;
|
||||||
|
ea->flags = EALF_SORTED;
|
||||||
|
ea->count = n;
|
||||||
|
ra.eattrs = ea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (scan)
|
if (scan)
|
||||||
krt_got_route(p, e);
|
krt_got_route(p, e);
|
||||||
else
|
else
|
||||||
|
@ -1130,6 +1227,50 @@ krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
|
||||||
d->sys.table_id = s->sys.table_id;
|
d->sys.table_id = s->sys.table_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *krt_metrics_names[KRT_METRICS_MAX] = {
|
||||||
|
NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
|
||||||
|
"reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *krt_features_names[KRT_FEATURES_MAX] = {
|
||||||
|
"ecn", NULL, NULL, "allfrag"
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
|
||||||
|
{
|
||||||
|
switch (a->id)
|
||||||
|
{
|
||||||
|
case EA_KRT_PREFSRC:
|
||||||
|
bsprintf(buf, "prefsrc");
|
||||||
|
return GA_NAME;
|
||||||
|
|
||||||
|
case EA_KRT_REALM:
|
||||||
|
bsprintf(buf, "realm");
|
||||||
|
return GA_NAME;
|
||||||
|
|
||||||
|
case EA_KRT_LOCK:
|
||||||
|
buf += bsprintf(buf, "lock:");
|
||||||
|
ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
|
||||||
|
return GA_FULL;
|
||||||
|
|
||||||
|
case EA_KRT_FEATURES:
|
||||||
|
buf += bsprintf(buf, "features:");
|
||||||
|
ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
|
||||||
|
return GA_FULL;
|
||||||
|
|
||||||
|
default:;
|
||||||
|
int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
|
||||||
|
if (id > 0 && id < KRT_METRICS_MAX)
|
||||||
|
{
|
||||||
|
bsprintf(buf, "%s", krt_metrics_names[id]);
|
||||||
|
return GA_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GA_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1191,7 +1191,7 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
krt_get_attr(eattr *a, byte *buf, int buflen)
|
||||||
{
|
{
|
||||||
switch (a->id)
|
switch (a->id)
|
||||||
{
|
{
|
||||||
|
@ -1203,16 +1203,8 @@ krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
||||||
bsprintf(buf, "metric");
|
bsprintf(buf, "metric");
|
||||||
return GA_NAME;
|
return GA_NAME;
|
||||||
|
|
||||||
case EA_KRT_PREFSRC:
|
|
||||||
bsprintf(buf, "prefsrc");
|
|
||||||
return GA_NAME;
|
|
||||||
|
|
||||||
case EA_KRT_REALM:
|
|
||||||
bsprintf(buf, "realm");
|
|
||||||
return GA_NAME;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return GA_UNKNOWN;
|
return krt_sys_get_attr(a, buf, buflen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,6 @@ struct kif_proto;
|
||||||
|
|
||||||
#define EA_KRT_SOURCE EA_CODE(EAP_KRT, 0)
|
#define EA_KRT_SOURCE EA_CODE(EAP_KRT, 0)
|
||||||
#define EA_KRT_METRIC EA_CODE(EAP_KRT, 1)
|
#define EA_KRT_METRIC EA_CODE(EAP_KRT, 1)
|
||||||
#define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 2)
|
|
||||||
#define EA_KRT_REALM EA_CODE(EAP_KRT, 3)
|
|
||||||
|
|
||||||
/* Whenever we recognize our own routes, we allow learing of foreign routes */
|
/* Whenever we recognize our own routes, we allow learing of foreign routes */
|
||||||
|
|
||||||
|
@ -131,6 +129,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *);
|
||||||
int krt_capable(rte *e);
|
int krt_capable(rte *e);
|
||||||
void krt_do_scan(struct krt_proto *);
|
void krt_do_scan(struct krt_proto *);
|
||||||
void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs);
|
void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs);
|
||||||
|
int krt_sys_get_attr(eattr *a, byte *buf, int buflen);
|
||||||
|
|
||||||
|
|
||||||
/* kif sysdep */
|
/* kif sysdep */
|
||||||
|
|
Loading…
Reference in a new issue