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)
|
||||
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)
|
||||
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--; }
|
||||
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_walk(struct ea_walk_state *s, uint id, uint max);
|
||||
int ea_get_int(ea_list *, unsigned ea, int def);
|
||||
void ea_dump(ea_list *);
|
||||
void ea_sort(ea_list *); /* Sort entries in all sub-lists */
|
||||
|
|
|
@ -307,6 +307,82 @@ ea_find(ea_list *e, unsigned id)
|
|||
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
|
||||
* @e: attribute list
|
||||
|
|
|
@ -44,5 +44,7 @@ struct krt_state {
|
|||
|
||||
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
|
||||
|
|
|
@ -32,6 +32,59 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; }
|
|||
|
||||
/* 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
|
||||
|
||||
struct krt_params {
|
||||
|
|
|
@ -10,7 +10,12 @@ CF_HDR
|
|||
|
||||
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
|
||||
|
||||
|
@ -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_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); })
|
||||
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_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
|
||||
|
||||
|
|
|
@ -238,21 +238,24 @@ nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
nl_add_attr(struct nlmsghdr *h, unsigned bufsize, unsigned code,
|
||||
void *data, unsigned dlen)
|
||||
struct rtattr *
|
||||
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
|
||||
{
|
||||
unsigned len = RTA_LENGTH(dlen);
|
||||
unsigned pos = NLMSG_ALIGN(h->nlmsg_len);
|
||||
struct rtattr *a;
|
||||
uint pos = NLMSG_ALIGN(h->nlmsg_len);
|
||||
uint len = RTA_LENGTH(dlen);
|
||||
|
||||
if (pos + len > bufsize)
|
||||
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_len = 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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
#define RTNH_SIZE (sizeof(struct rtnexthop) + sizeof(struct rtattr) + sizeof(ip_addr))
|
||||
|
||||
static inline void
|
||||
add_mpnexthop(char *buf, ip_addr ipa, unsigned iface, unsigned char weight)
|
||||
static inline struct rtattr *
|
||||
nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
|
||||
{
|
||||
struct rtnexthop *nh = (void *) buf;
|
||||
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));
|
||||
return nl_add_attr(h, bufsize, code, NULL, 0);
|
||||
}
|
||||
|
||||
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
|
||||
nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
|
||||
{
|
||||
unsigned len = sizeof(struct rtattr);
|
||||
unsigned pos = NLMSG_ALIGN(h->nlmsg_len);
|
||||
char *buf = (char *)h + pos;
|
||||
struct rtattr *rt = (void *) buf;
|
||||
buf += len;
|
||||
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
|
||||
|
||||
for (; nh; nh = nh->next)
|
||||
{
|
||||
len += RTNH_SIZE;
|
||||
if (pos + len > bufsize)
|
||||
bug("nl_add_multipath: packet buffer overflow");
|
||||
{
|
||||
struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
|
||||
|
||||
add_mpnexthop(buf, nh->gw, nh->iface->index, nh->weight);
|
||||
buf += RTNH_SIZE;
|
||||
}
|
||||
rtnh->rtnh_flags = 0;
|
||||
rtnh->rtnh_hops = nh->weight;
|
||||
rtnh->rtnh_ifindex = nh->iface->index;
|
||||
|
||||
rt->rta_type = RTA_MULTIPATH;
|
||||
rt->rta_len = len;
|
||||
h->nlmsg_len = pos + len;
|
||||
nl_add_attr_u32(h, bufsize, RTA_GATEWAY, nh->gw);
|
||||
|
||||
nl_close_nexthop(h, rtnh);
|
||||
}
|
||||
|
||||
nl_close_attr(h, a);
|
||||
}
|
||||
|
||||
|
||||
static struct mpnh *
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -617,7 +671,7 @@ nh_bufsize(struct mpnh *nh)
|
|||
{
|
||||
int rv = 0;
|
||||
for (; nh != NULL; nh = nh->next)
|
||||
rv += RTNH_SIZE;
|
||||
rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -630,7 +684,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
|||
struct {
|
||||
struct nlmsghdr h;
|
||||
struct rtmsg r;
|
||||
char buf[128 + nh_bufsize(a->nexthops)];
|
||||
char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
|
||||
} r;
|
||||
|
||||
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;
|
||||
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))
|
||||
metric = ea->u.data;
|
||||
if (metric != 0)
|
||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, metric);
|
||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
|
||||
|
||||
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
|
||||
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))
|
||||
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 */
|
||||
|
||||
switch (a->dest)
|
||||
|
@ -932,6 +997,38 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
|||
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)
|
||||
krt_got_route(p, e);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -1191,7 +1191,7 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
|
|||
}
|
||||
|
||||
static int
|
||||
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
||||
krt_get_attr(eattr *a, byte *buf, int buflen)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
@ -1203,16 +1203,8 @@ krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
|||
bsprintf(buf, "metric");
|
||||
return GA_NAME;
|
||||
|
||||
case EA_KRT_PREFSRC:
|
||||
bsprintf(buf, "prefsrc");
|
||||
return GA_NAME;
|
||||
|
||||
case EA_KRT_REALM:
|
||||
bsprintf(buf, "realm");
|
||||
return GA_NAME;
|
||||
|
||||
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_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 */
|
||||
|
||||
|
@ -131,6 +129,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *);
|
|||
int krt_capable(rte *e);
|
||||
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);
|
||||
int krt_sys_get_attr(eattr *a, byte *buf, int buflen);
|
||||
|
||||
|
||||
/* kif sysdep */
|
||||
|
|
Loading…
Reference in a new issue