mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-23 02:01:55 +00:00
Merge branch 'master' into birdtest
This commit is contained in:
commit
00572d96f9
@ -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.
|
||||
|
@ -462,7 +462,7 @@ static int f_flags;
|
||||
|
||||
static inline void f_rte_cow(void)
|
||||
{
|
||||
*f_rte = rte_cow(*f_rte);
|
||||
*f_rte = rte_cow(*f_rte);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -479,7 +479,7 @@ f_rta_cow(void)
|
||||
/* Store old rta to free it later */
|
||||
f_old_rta = (*f_rte)->attrs;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Alloc new rta, do shallow copy and update rte. Fields eattrs
|
||||
* and nexthops of rta are shared with f_old_rta (they will be
|
||||
* copied when the cached rta will be obtained at the end of
|
||||
@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||
#define ACCESS_RTE \
|
||||
do { if (!f_rte) runtime("No route to access"); } while (0)
|
||||
|
||||
#define BITFIELD_MASK(what) \
|
||||
(1u << (what->a2.i >> 24))
|
||||
|
||||
/**
|
||||
* interpret
|
||||
* @what: filter to interpret
|
||||
@ -526,7 +529,7 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||
* Each instruction has 4 fields: code (which is instruction code),
|
||||
* aux (which is extension to instruction code, typically type),
|
||||
* arg1 and arg2 - arguments. Depending on instruction, arguments
|
||||
* are either integers, or pointers to instruction trees. Common
|
||||
* are either integers, or pointers to instruction trees. Common
|
||||
* instructions like +, that have two expressions as arguments use
|
||||
* TWOARGS macro to get both of them evaluated.
|
||||
*
|
||||
@ -585,7 +588,7 @@ interpret(struct f_inst *what)
|
||||
default: runtime( "Usage of unknown type" );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case '&':
|
||||
case '|':
|
||||
ARG(v1, a1.p);
|
||||
@ -625,7 +628,7 @@ interpret(struct f_inst *what)
|
||||
|
||||
if (v1.type == T_INT) {
|
||||
ipv4_used = 0; key = v1.val.i;
|
||||
}
|
||||
}
|
||||
else if (v1.type == T_QUAD) {
|
||||
ipv4_used = 1; key = v1.val.i;
|
||||
}
|
||||
@ -724,7 +727,7 @@ interpret(struct f_inst *what)
|
||||
#endif
|
||||
runtime( "Assigning to variable of incompatible type" );
|
||||
}
|
||||
*vp = v2;
|
||||
*vp = v2;
|
||||
break;
|
||||
|
||||
/* some constants have value in a2, some in *a1.p, strange. */
|
||||
@ -864,12 +867,14 @@ interpret(struct f_inst *what)
|
||||
ACCESS_RTE;
|
||||
{
|
||||
eattr *e = NULL;
|
||||
u16 code = what->a2.i;
|
||||
|
||||
if (!(f_flags & FF_FORCE_TMPATTR))
|
||||
e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
|
||||
if (!e)
|
||||
e = ea_find( (*f_tmp_attrs), what->a2.i );
|
||||
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, what->a2.i );
|
||||
e = ea_find((*f_rte)->attrs->eattrs, code);
|
||||
|
||||
if (!e) {
|
||||
/* 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);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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.val.ad = adata_empty(f_pool, 0);
|
||||
break;
|
||||
@ -912,6 +918,10 @@ interpret(struct f_inst *what)
|
||||
res.type = T_PATH;
|
||||
res.val.ad = e->u.ptr;
|
||||
break;
|
||||
case EAF_TYPE_BITFIELD:
|
||||
res.type = T_BOOL;
|
||||
res.val.i = !!(e->u.data & BITFIELD_MASK(what));
|
||||
break;
|
||||
case EAF_TYPE_INT_SET:
|
||||
res.type = T_CLIST;
|
||||
res.val.ad = e->u.ptr;
|
||||
@ -933,13 +943,15 @@ interpret(struct f_inst *what)
|
||||
ONEARG;
|
||||
{
|
||||
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
|
||||
u16 code = what->a2.i;
|
||||
|
||||
l->next = NULL;
|
||||
l->flags = EALF_SORTED;
|
||||
l->count = 1;
|
||||
l->attrs[0].id = what->a2.i;
|
||||
l->attrs[0].id = code;
|
||||
l->attrs[0].flags = 0;
|
||||
l->attrs[0].type = what->aux | EAF_ORIGINATED;
|
||||
|
||||
switch (what->aux & EAF_TYPE_MASK) {
|
||||
case EAF_TYPE_INT:
|
||||
if (v1.type != T_INT)
|
||||
@ -978,6 +990,26 @@ interpret(struct f_inst *what)
|
||||
runtime( "Setting path attribute to non-path value" );
|
||||
l->attrs[0].u.ptr = v1.val.ad;
|
||||
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:
|
||||
if (v1.type != T_CLIST)
|
||||
runtime( "Setting clist attribute to non-clist value" );
|
||||
@ -1073,7 +1105,7 @@ interpret(struct f_inst *what)
|
||||
res = interpret(what->a2.p);
|
||||
if (res.type == T_RETURN)
|
||||
return res;
|
||||
res.type &= ~T_RETURN;
|
||||
res.type &= ~T_RETURN;
|
||||
break;
|
||||
case P('c','v'): /* Clear local variables */
|
||||
for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
|
||||
@ -1090,7 +1122,7 @@ interpret(struct f_inst *what)
|
||||
debug( "No else statement?\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* It is actually possible to have t->data NULL */
|
||||
|
||||
res = interpret(t->data);
|
||||
@ -1184,10 +1216,10 @@ interpret(struct f_inst *what)
|
||||
runtime("Can't add set");
|
||||
else if (!arg_set)
|
||||
res.val.ad = int_set_add(f_pool, v1.val.ad, n);
|
||||
else
|
||||
else
|
||||
res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
|
||||
break;
|
||||
|
||||
|
||||
case 'd':
|
||||
if (!arg_set)
|
||||
res.val.ad = int_set_del(f_pool, v1.val.ad, n);
|
||||
@ -1209,7 +1241,7 @@ interpret(struct f_inst *what)
|
||||
{
|
||||
/* Extended community list */
|
||||
int arg_set = 0;
|
||||
|
||||
|
||||
/* v2.val is either EC or EC-set */
|
||||
if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
|
||||
arg_set = 1;
|
||||
@ -1226,10 +1258,10 @@ interpret(struct f_inst *what)
|
||||
runtime("Can't add set");
|
||||
else if (!arg_set)
|
||||
res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
|
||||
else
|
||||
else
|
||||
res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
|
||||
break;
|
||||
|
||||
|
||||
case 'd':
|
||||
if (!arg_set)
|
||||
res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
|
||||
@ -1353,7 +1385,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'c':
|
||||
switch (f1->aux) {
|
||||
|
||||
case T_PREFIX_SET:
|
||||
@ -1381,7 +1413,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
case 'V':
|
||||
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
|
||||
return 0;
|
||||
break;
|
||||
@ -1399,12 +1431,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
case 'r': ONEARG; break;
|
||||
case P('c','p'): ONEARG; break;
|
||||
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
|
||||
ONEARG;
|
||||
ONEARG;
|
||||
if (!i_same(f1->a2.p, f2->a2.p))
|
||||
return 0;
|
||||
return 0;
|
||||
f2->a2.p = f1->a2.p;
|
||||
break;
|
||||
case P('c','v'): break; /* internal instruction */
|
||||
case P('c','v'): break; /* internal instruction */
|
||||
case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
|
||||
case P('i','M'): TWOARGS; break;
|
||||
case P('A','p'): TWOARGS; break;
|
||||
@ -1414,7 +1446,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||
case P('R','C'):
|
||||
TWOARGS;
|
||||
/* Does not really make sense - ROA check resuls may change anyway */
|
||||
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
|
||||
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
|
||||
((struct f_inst_roa_check *) f2)->rtc->name))
|
||||
return 0;
|
||||
break;
|
||||
|
196
lib/fletcher16.h
Normal file
196
lib/fletcher16.h
Normal 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
|
11
nest/route.h
11
nest/route.h
@ -417,13 +417,15 @@ typedef struct eattr {
|
||||
|
||||
#define EA_CODE_MASK 0xffff
|
||||
#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_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_IP_ADDRESS 0x04 /* IP 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_BITFIELD 0x09 /* 32-bit embedded bitfield */
|
||||
#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_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--; }
|
||||
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 */
|
||||
@ -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 */
|
||||
unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */
|
||||
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 */
|
||||
static inline int mpnh_same(struct mpnh *x, struct mpnh *y)
|
||||
|
105
nest/rt-attr.c
105
nest/rt-attr.c
@ -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
|
||||
@ -563,6 +639,32 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
|
||||
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
|
||||
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:
|
||||
as_path_format(ad, pos, end - pos);
|
||||
break;
|
||||
case EAF_TYPE_BITFIELD:
|
||||
bsprintf(pos, "%08x", e->u.data);
|
||||
break;
|
||||
case EAF_TYPE_INT_SET:
|
||||
ea_show_int_set(c, ad, 1, pos, buf, end);
|
||||
return;
|
||||
|
@ -2,14 +2,15 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
* (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2015 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "ospf.h"
|
||||
|
||||
#include "lib/fletcher16.h"
|
||||
|
||||
#ifndef CPU_BIG_ENDIAN
|
||||
void
|
||||
@ -150,145 +151,41 @@ lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
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];
|
||||
char *bp;
|
||||
int first = 1;
|
||||
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));
|
||||
struct fletcher16_context ctx;
|
||||
struct ospf_lsa_header hdr;
|
||||
u16 len = lsa->length;
|
||||
|
||||
/*
|
||||
char buf[1024];
|
||||
memcpy(buf, h, sizeof(struct ospf_lsa_header));
|
||||
memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header));
|
||||
buf_dump("CALC", buf, length);
|
||||
*/
|
||||
* lsa and body are in the host order, we need to compute Fletcher-16 checksum
|
||||
* for data in the network order. We also skip the initial age field.
|
||||
*/
|
||||
|
||||
(void) lsasum_check(h, body, 1);
|
||||
lsa_hton_hdr(lsa, &hdr);
|
||||
hdr.checksum = 0;
|
||||
|
||||
// log(L_WARN "Checksum result %4x", h->checksum);
|
||||
|
||||
lsa_ntoh_hdr(h, h);
|
||||
lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header));
|
||||
fletcher16_init(&ctx);
|
||||
fletcher16_update(&ctx, (u8 *) &hdr + 2, sizeof(struct ospf_lsa_header) - 2);
|
||||
fletcher16_update_n32(&ctx, body, len - 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
|
||||
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;
|
||||
int c0 = 0, c1 = 0;
|
||||
int x, y;
|
||||
u16 length;
|
||||
struct fletcher16_context ctx;
|
||||
|
||||
b = body;
|
||||
sp = (char *) h;
|
||||
sp += 2; /* Skip Age field */
|
||||
length = ntohs(h->length) - 2;
|
||||
if (update) h->checksum = 0;
|
||||
/* The whole LSA is at lsa_n in net order, we just skip initial age field */
|
||||
|
||||
for (ep = sp + length; sp < ep; sp = q)
|
||||
{ /* Actually MODX is very large, do we need the for-cyclus? */
|
||||
q = sp + MODX;
|
||||
if (q > ep)
|
||||
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)));
|
||||
}
|
||||
fletcher16_init(&ctx);
|
||||
fletcher16_update(&ctx, (u8 *) lsa_n + 2, lsa_len - 2);
|
||||
|
||||
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;
|
||||
return fletcher16_compute(&ctx) == 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
|
||||
/* Return codes from point of view of l1 */
|
||||
|
@ -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);
|
||||
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_SAME 0
|
||||
#define CMP_OLDER -1
|
||||
|
@ -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",
|
||||
lsa_type, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum);
|
||||
|
||||
/* RFC 2328 13. (1) - validate LSA checksum */
|
||||
if ((lsa_n->checksum == 0) || (lsasum_check(lsa_n, NULL, 0) != 0))
|
||||
/* RFC 2328 13. (1) - verify LSA checksum */
|
||||
if ((lsa_n->checksum == 0) || !lsa_verify_checksum(lsa_n, lsa_len))
|
||||
SKIP("invalid checksum");
|
||||
|
||||
/* RFC 2328 13. (2) */
|
||||
|
@ -129,7 +129,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||
en->lsa.age = 0;
|
||||
en->init_age = 0;
|
||||
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",
|
||||
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->init_age = 0;
|
||||
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",
|
||||
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->init_age = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
@ -834,7 +899,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||
net->n.prefix, net->n.pxlen);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -896,7 +961,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||
e->u.krt.type = i->rtm_type;
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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 New Issue
Block a user