0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 18:08:45 +00:00

Merge branch 'master' into birdtest

This commit is contained in:
Pavel Tvrdík 2015-05-13 11:41:03 +02:00
commit 00572d96f9
15 changed files with 684 additions and 224 deletions

View File

@ -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.

View File

@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
#define ACCESS_RTE \ #define ACCESS_RTE \
do { if (!f_rte) runtime("No route to access"); } while (0) do { if (!f_rte) runtime("No route to access"); } while (0)
#define BITFIELD_MASK(what) \
(1u << (what->a2.i >> 24))
/** /**
* interpret * interpret
* @what: filter to interpret * @what: filter to interpret
@ -864,12 +867,14 @@ interpret(struct f_inst *what)
ACCESS_RTE; ACCESS_RTE;
{ {
eattr *e = NULL; eattr *e = NULL;
u16 code = what->a2.i;
if (!(f_flags & FF_FORCE_TMPATTR)) if (!(f_flags & FF_FORCE_TMPATTR))
e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); e = ea_find((*f_rte)->attrs->eattrs, code);
if (!e) if (!e)
e = ea_find( (*f_tmp_attrs), what->a2.i ); e = ea_find((*f_tmp_attrs), code);
if ((!e) && (f_flags & FF_FORCE_TMPATTR)) if ((!e) && (f_flags & FF_FORCE_TMPATTR))
e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i ); e = ea_find((*f_rte)->attrs->eattrs, code);
if (!e) { if (!e) {
/* A special case: undefined int_set looks like empty int_set */ /* A special case: undefined int_set looks like empty int_set */
@ -878,8 +883,9 @@ interpret(struct f_inst *what)
res.val.ad = adata_empty(f_pool, 0); res.val.ad = adata_empty(f_pool, 0);
break; break;
} }
/* The same special case for ec_set */ /* The same special case for ec_set */
else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
res.type = T_ECLIST; res.type = T_ECLIST;
res.val.ad = adata_empty(f_pool, 0); res.val.ad = adata_empty(f_pool, 0);
break; break;
@ -912,6 +918,10 @@ interpret(struct f_inst *what)
res.type = T_PATH; res.type = T_PATH;
res.val.ad = e->u.ptr; res.val.ad = e->u.ptr;
break; break;
case EAF_TYPE_BITFIELD:
res.type = T_BOOL;
res.val.i = !!(e->u.data & BITFIELD_MASK(what));
break;
case EAF_TYPE_INT_SET: case EAF_TYPE_INT_SET:
res.type = T_CLIST; res.type = T_CLIST;
res.val.ad = e->u.ptr; res.val.ad = e->u.ptr;
@ -933,13 +943,15 @@ interpret(struct f_inst *what)
ONEARG; ONEARG;
{ {
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
u16 code = what->a2.i;
l->next = NULL; l->next = NULL;
l->flags = EALF_SORTED; l->flags = EALF_SORTED;
l->count = 1; l->count = 1;
l->attrs[0].id = what->a2.i; l->attrs[0].id = code;
l->attrs[0].flags = 0; l->attrs[0].flags = 0;
l->attrs[0].type = what->aux | EAF_ORIGINATED; l->attrs[0].type = what->aux | EAF_ORIGINATED;
switch (what->aux & EAF_TYPE_MASK) { switch (what->aux & EAF_TYPE_MASK) {
case EAF_TYPE_INT: case EAF_TYPE_INT:
if (v1.type != T_INT) if (v1.type != T_INT)
@ -978,6 +990,26 @@ interpret(struct f_inst *what)
runtime( "Setting path attribute to non-path value" ); runtime( "Setting path attribute to non-path value" );
l->attrs[0].u.ptr = v1.val.ad; l->attrs[0].u.ptr = v1.val.ad;
break; break;
case EAF_TYPE_BITFIELD:
if (v1.type != T_BOOL)
runtime( "Setting bit in bitfield attribute to non-bool value" );
{
/* First, we have to find the old value */
eattr *e = NULL;
if (!(f_flags & FF_FORCE_TMPATTR))
e = ea_find((*f_rte)->attrs->eattrs, code);
if (!e)
e = ea_find((*f_tmp_attrs), code);
if ((!e) && (f_flags & FF_FORCE_TMPATTR))
e = ea_find((*f_rte)->attrs->eattrs, code);
u32 data = e ? e->u.data : 0;
if (v1.val.i)
l->attrs[0].u.data = data | BITFIELD_MASK(what);
else
l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
}
break;
case EAF_TYPE_INT_SET: case EAF_TYPE_INT_SET:
if (v1.type != T_CLIST) if (v1.type != T_CLIST)
runtime( "Setting clist attribute to non-clist value" ); runtime( "Setting clist attribute to non-clist value" );

196
lib/fletcher16.h Normal file
View File

@ -0,0 +1,196 @@
/*
* BIRD Library -- Fletcher-16 checksum
*
* (c) 2015 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2015 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* DOC: Fletcher-16 checksum
*
* Fletcher-16 checksum is a position-dependent checksum algorithm used for
* error-detection e.g. in OSPF LSAs.
*
* To generate Fletcher-16 checksum, zero the checksum field in data, initialize
* the context by fletcher16_init(), process the data by fletcher16_update(),
* compute the checksum value by fletcher16_final() and store it to the checksum
* field in data by put_u16() (or other means involving htons() conversion).
*
* To verify Fletcher-16 checksum, initialize the context by fletcher16_init(),
* process the data by fletcher16_update(), compute a passing checksum by
* fletcher16_compute() and check if it is zero.
*/
#ifndef _BIRD_FLETCHER16_H_
#define _BIRD_FLETCHER16_H_
#include "nest/bird.h"
struct fletcher16_context
{
int c0, c1;
};
/**
* fletcher16_init - initialize Fletcher-16 context
* @ctx: the context
*/
static inline void
fletcher16_init(struct fletcher16_context *ctx)
{
ctx->c0 = ctx->c1 = 0;
}
/**
* fletcher16_update - process data to Fletcher-16 context
* @ctx: the context
* @buf: data buffer
* @len: data length
*
* fletcher16_update() reads data from the buffer @buf and updates passing sums
* in the context @ctx. It may be used multiple times for multiple blocks of
* checksummed data.
*/
static inline void
fletcher16_update(struct fletcher16_context *ctx, const u8* buf, int len)
{
/*
* The Fletcher-16 sum is essentially a sequence of
* ctx->c1 += ctx->c0 += *buf++, modulo 255.
*
* In the inner loop, we eliminate modulo operation and we do some loop
* unrolling. MODX is the maximal number of steps that can be done without
* modulo before overflow, see RFC 1008 for details. We use a bit smaller
* value to cover for initial steps due to loop unrolling.
*/
#define MODX 4096
int blen, i;
blen = len % 4;
len -= blen;
for (i = 0; i < blen; i++)
ctx->c1 += ctx->c0 += *buf++;
do {
blen = MIN(len, MODX);
len -= blen;
for (i = 0; i < blen; i += 4)
{
ctx->c1 += ctx->c0 += *buf++;
ctx->c1 += ctx->c0 += *buf++;
ctx->c1 += ctx->c0 += *buf++;
ctx->c1 += ctx->c0 += *buf++;
}
ctx->c0 %= 255;
ctx->c1 %= 255;
} while (len);
}
/**
* fletcher16_update_n32 - process data to Fletcher-16 context, with endianity adjustment
* @ctx: the context
* @buf: data buffer
* @len: data length
*
* fletcher16_update_n32() works like fletcher16_update(), except it applies
* 32-bit host/network endianity swap to the data before they are processed.
* I.e., it assumes that the data is a sequence of u32 that must be converted by
* ntohl() or htonl() before processing. The @buf need not to be aligned, but
* its length (@len) must be multiple of 4. Note that on big endian systems the
* host endianity is the same as the network endianity, therefore there is no
* endianity swap.
*/
static inline void
fletcher16_update_n32(struct fletcher16_context *ctx, const u8* buf, int len)
{
/* See fletcher16_update() for details */
int blen, i;
do {
blen = MIN(len, MODX);
len -= blen;
for (i = 0; i < blen; i += 4)
{
#ifdef CPU_BIG_ENDIAN
ctx->c1 += ctx->c0 += *buf++;
ctx->c1 += ctx->c0 += *buf++;
ctx->c1 += ctx->c0 += *buf++;
ctx->c1 += ctx->c0 += *buf++;
#else
ctx->c1 += ctx->c0 += buf[3];
ctx->c1 += ctx->c0 += buf[2];
ctx->c1 += ctx->c0 += buf[1];
ctx->c1 += ctx->c0 += buf[0];
buf += 4;
#endif
}
ctx->c0 %= 255;
ctx->c1 %= 255;
} while (len);
}
/**
* fletcher16_final - compute final Fletcher-16 checksum value
* @ctx: the context
* @len: total data length
* @pos: offset in data where the checksum will be stored
*
* fletcher16_final() computes the final checksum value and returns it.
* The caller is responsible for storing it in the appropriate position.
* The checksum value depends on @len and @pos, but only their difference
* (i.e. the offset from the end) is significant.
*
* The checksum value is represented as u16, although it is defined as two
* consecutive bytes. We treat them as one u16 in big endian / network order.
* I.e., the returned value is in the form that would be returned by get_u16()
* from the checksum field in the data buffer, therefore the caller should use
* put_u16() or an explicit host-to-network conversion when storing it to the
* checksum field in the data buffer.
*
* Note that the returned checksum value is always nonzero.
*/
static inline u16
fletcher16_final(struct fletcher16_context *ctx, int len, int pos)
{
int x = ((len - pos - 1) * ctx->c0 - ctx->c1) % 255;
if (x <= 0)
x += 255;
int y = 510 - ctx->c0 - x;
if (y > 255)
y -= 255;
return (x << 8) | y;
}
/**
* fletcher16_compute - compute Fletcher-16 sum for verification
* @ctx: the context
*
* fletcher16_compute() returns a passing Fletcher-16 sum for processed data.
* If the data contains the proper Fletcher-16 checksum value, the returned
* value is zero.
*/
static inline u16
fletcher16_compute(struct fletcher16_context *ctx)
{
return (ctx->c0 << 8) | ctx->c1;
}
#endif

View File

@ -417,13 +417,15 @@ typedef struct eattr {
#define EA_CODE_MASK 0xffff #define EA_CODE_MASK 0xffff
#define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */ #define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */
#define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */
#define EAF_TYPE_MASK 0x0f /* Mask with this to get type */ #define EAF_TYPE_MASK 0x0f /* Mask with this to get type */
#define EAF_TYPE_INT 0x01 /* 32-bit signed integer number */ #define EAF_TYPE_INT 0x01 /* 32-bit unsigned integer number */
#define EAF_TYPE_OPAQUE 0x02 /* Opaque byte string (not filterable) */ #define EAF_TYPE_OPAQUE 0x02 /* Opaque byte string (not filterable) */
#define EAF_TYPE_IP_ADDRESS 0x04 /* IP address */ #define EAF_TYPE_IP_ADDRESS 0x04 /* IP address */
#define EAF_TYPE_ROUTER_ID 0x05 /* Router ID (IPv4 address) */ #define EAF_TYPE_ROUTER_ID 0x05 /* Router ID (IPv4 address) */
#define EAF_TYPE_AS_PATH 0x06 /* BGP AS path (encoding per RFC 1771:4.3) */ #define EAF_TYPE_AS_PATH 0x06 /* BGP AS path (encoding per RFC 1771:4.3) */
#define EAF_TYPE_BITFIELD 0x09 /* 32-bit embedded bitfield */
#define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */ #define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */
#define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */ #define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */
#define EAF_TYPE_UNDEF 0x0f /* `force undefined' entry */ #define EAF_TYPE_UNDEF 0x0f /* `force undefined' entry */
@ -459,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 */
@ -469,6 +477,7 @@ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffe
int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */ int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */
unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */ unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */
ea_list *ea_append(ea_list *to, ea_list *what); ea_list *ea_append(ea_list *to, ea_list *what);
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */ int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */
static inline int mpnh_same(struct mpnh *x, struct mpnh *y) static inline int mpnh_same(struct mpnh *x, struct mpnh *y)

View File

@ -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
@ -563,6 +639,32 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
return GA_UNKNOWN; return GA_UNKNOWN;
} }
void
ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
{
byte *bound = buf + bufsize - 32;
u32 data = a->u.data;
int i;
for (i = min; i < max; i++)
if ((data & (1u << i)) && names[i])
{
if (buf > bound)
{
strcpy(buf, " ...");
return;
}
buf += bsprintf(buf, " %s", names[i]);
data &= ~(1u << i);
}
if (data)
bsprintf(buf, " %08x", data);
return;
}
static inline void static inline void
opaque_format(struct adata *ad, byte *buf, unsigned int size) opaque_format(struct adata *ad, byte *buf, unsigned int size)
{ {
@ -665,6 +767,9 @@ ea_show(struct cli *c, eattr *e)
case EAF_TYPE_AS_PATH: case EAF_TYPE_AS_PATH:
as_path_format(ad, pos, end - pos); as_path_format(ad, pos, end - pos);
break; break;
case EAF_TYPE_BITFIELD:
bsprintf(pos, "%08x", e->u.data);
break;
case EAF_TYPE_INT_SET: case EAF_TYPE_INT_SET:
ea_show_int_set(c, ad, 1, pos, buf, end); ea_show_int_set(c, ad, 1, pos, buf, end);
return; return;

View File

@ -2,14 +2,15 @@
* BIRD -- OSPF * BIRD -- OSPF
* *
* (c) 1999--2004 Ondrej Filip <feela@network.cz> * (c) 1999--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org> * (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2009--2014 CZ.NIC z.s.p.o. * (c) 2009--2015 CZ.NIC z.s.p.o.
* *
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
#include "ospf.h" #include "ospf.h"
#include "lib/fletcher16.h"
#ifndef CPU_BIG_ENDIAN #ifndef CPU_BIG_ENDIAN
void void
@ -150,144 +151,40 @@ lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
} }
/*
void void
buf_dump(const char *hdr, const byte *buf, int blen) lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body)
{ {
char b2[1024]; struct fletcher16_context ctx;
char *bp; struct ospf_lsa_header hdr;
int first = 1; u16 len = lsa->length;
int i;
const char *lhdr = hdr;
bp = b2;
for(i = 0; i < blen; i++)
{
if ((i > 0) && ((i % 16) == 0))
{
*bp = 0;
log(L_WARN "%s\t%s", lhdr, b2);
lhdr = "";
bp = b2;
}
bp += snprintf(bp, 1022, "%02x ", buf[i]);
}
*bp = 0;
log(L_WARN "%s\t%s", lhdr, b2);
}
*/
#define MODX 4102 /* larges signed value without overflow */
/* Fletcher Checksum -- Refer to RFC1008. */
#define MODX 4102
#define LSA_CHECKSUM_OFFSET 15
/* FIXME This is VERY uneficient, I have huge endianity problems */
void
lsasum_calculate(struct ospf_lsa_header *h, void *body)
{
u16 length = h->length;
// log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
lsa_hton_hdr(h, h);
lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
/* /*
char buf[1024]; * lsa and body are in the host order, we need to compute Fletcher-16 checksum
memcpy(buf, h, sizeof(struct ospf_lsa_header)); * for data in the network order. We also skip the initial age field.
memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header));
buf_dump("CALC", buf, length);
*/ */
(void) lsasum_check(h, body, 1); lsa_hton_hdr(lsa, &hdr);
hdr.checksum = 0;
// log(L_WARN "Checksum result %4x", h->checksum); fletcher16_init(&ctx);
fletcher16_update(&ctx, (u8 *) &hdr + 2, sizeof(struct ospf_lsa_header) - 2);
lsa_ntoh_hdr(h, h); fletcher16_update_n32(&ctx, body, len - sizeof(struct ospf_lsa_header));
lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header)); lsa->checksum = fletcher16_final(&ctx, len, OFFSETOF(struct ospf_lsa_header, checksum));
} }
/*
* Calculates the Fletcher checksum of an OSPF LSA.
*
* If 'update' is non-zero, the checkbytes (X and Y in RFC905) are calculated
* and the checksum field in the header is updated. The return value is the
* checksum as placed in the header (in network byte order).
*
* If 'update' is zero, only C0 and C1 are calculated and the header is kept
* intact. The return value is a combination of C0 and C1; if the return value
* is exactly zero the checksum is considered valid, any non-zero value is
* invalid.
*
* Note that this function expects the input LSA to be in network byte order.
*/
u16 u16
lsasum_check(struct ospf_lsa_header *h, void *body, int update) lsa_verify_checksum(const void *lsa_n, int lsa_len)
{ {
u8 *sp, *ep, *p, *q, *b; struct fletcher16_context ctx;
int c0 = 0, c1 = 0;
int x, y;
u16 length;
b = body; /* The whole LSA is at lsa_n in net order, we just skip initial age field */
sp = (char *) h;
sp += 2; /* Skip Age field */
length = ntohs(h->length) - 2;
if (update) h->checksum = 0;
for (ep = sp + length; sp < ep; sp = q) fletcher16_init(&ctx);
{ /* Actually MODX is very large, do we need the for-cyclus? */ fletcher16_update(&ctx, (u8 *) lsa_n + 2, lsa_len - 2);
q = sp + MODX;
if (q > ep) return fletcher16_compute(&ctx) == 0;
q = ep;
for (p = sp; p < q; p++)
{
/*
* I count with bytes from header and than from body
* but if there is no body, it's appended to header
* (probably checksum in update receiving) and I go on
* after header
*/
if ((b == NULL) || (p < (u8 *) (h + 1)))
{
c0 += *p;
}
else
{
c0 += *(b + (p - (u8 *) (h + 1)));
} }
c1 += c0;
}
c0 %= 255;
c1 %= 255;
}
if (!update) {
/*
* When testing the checksum, we don't need to calculate x and y. The
* checksum passes if c0 and c1 are both 0.
*/
return (c0 << 8) | (c1 & 0xff);
}
x = (int)((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
if (x <= 0)
x += 255;
y = 510 - c0 - x;
if (y > 255)
y -= 255;
((u8 *) & h->checksum)[0] = x;
((u8 *) & h->checksum)[1] = y;
return h->checksum;
}
int int
lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2) lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)

View File

@ -46,9 +46,9 @@ static inline u32 lsa_get_etype(struct ospf_lsa_header *h, struct ospf_proto *p)
int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa); int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa);
void lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body);
u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
void lsasum_calculate(struct ospf_lsa_header *header, void *body);
u16 lsasum_check(struct ospf_lsa_header *h, void *body, int update);
#define CMP_NEWER 1 #define CMP_NEWER 1
#define CMP_SAME 0 #define CMP_SAME 0
#define CMP_OLDER -1 #define CMP_OLDER -1

View File

@ -530,8 +530,8 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
DBG("Update Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n", DBG("Update Type: %04x, Id: %R, Rt: %R, Sn: 0x%08x, Age: %u, Sum: %u\n",
lsa_type, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum); lsa_type, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum);
/* RFC 2328 13. (1) - validate LSA checksum */ /* RFC 2328 13. (1) - verify LSA checksum */
if ((lsa_n->checksum == 0) || (lsasum_check(lsa_n, NULL, 0) != 0)) if ((lsa_n->checksum == 0) || !lsa_verify_checksum(lsa_n, lsa_len))
SKIP("invalid checksum"); SKIP("invalid checksum");
/* RFC 2328 13. (2) */ /* RFC 2328 13. (2) */

View File

@ -129,7 +129,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
en->lsa.age = 0; en->lsa.age = 0;
en->init_age = 0; en->init_age = 0;
en->inst_time = now; en->inst_time = now;
lsasum_calculate(&en->lsa, en->lsa_body); lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
@ -238,7 +238,7 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
en->lsa.age = 0; en->lsa.age = 0;
en->init_age = 0; en->init_age = 0;
en->inst_time = now; en->inst_time = now;
lsasum_calculate(&en->lsa, en->lsa_body); lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
@ -382,7 +382,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
en->lsa.age = 0; en->lsa.age = 0;
en->init_age = 0; en->init_age = 0;
en->inst_time = now; en->inst_time = now;
lsasum_calculate(&en->lsa, en->lsa_body); lsa_generate_checksum(&en->lsa, en->lsa_body);
ospf_flood_lsa(p, en, NULL); ospf_flood_lsa(p, en, NULL);
} }

View File

@ -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

View File

@ -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 {

View File

@ -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
@ -27,6 +32,35 @@ 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
CF_END CF_END

View File

@ -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;
if (dlen > 0)
memcpy(RTA_DATA(a), data, dlen); 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;
nl_add_attr_u32(h, bufsize, RTA_GATEWAY, nh->gw);
nl_close_nexthop(h, rtnh);
} }
rt->rta_type = RTA_MULTIPATH; nl_close_attr(h, a);
rt->rta_len = len;
h->nlmsg_len = pos + len;
} }
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)
@ -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

View File

@ -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);
} }
} }

View File

@ -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 */