mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-23 10:11:53 +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)
|
<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.
|
||||||
|
@ -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
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_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)
|
||||||
|
105
nest/rt-attr.c
105
nest/rt-attr.c
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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) */
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,5 +44,7 @@ struct krt_state {
|
|||||||
|
|
||||||
static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
|
static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
|
||||||
|
|
||||||
|
static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { }
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +32,59 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; }
|
|||||||
|
|
||||||
/* Kernel routes */
|
/* Kernel routes */
|
||||||
|
|
||||||
|
#define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 0x10)
|
||||||
|
#define EA_KRT_REALM EA_CODE(EAP_KRT, 0x11)
|
||||||
|
|
||||||
|
|
||||||
|
#define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */
|
||||||
|
#define KRT_METRICS_OFFSET 0x20 /* Offset of EA_KRT_* vs RTAX_* */
|
||||||
|
|
||||||
|
#define KRT_FEATURES_MAX 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following attributes are parts of RTA_METRICS kernel route attribute, their
|
||||||
|
* ids must be consistent with their RTAX_* constants (+ KRT_METRICS_OFFSET)
|
||||||
|
*/
|
||||||
|
#define EA_KRT_METRICS EA_CODE(EAP_KRT, 0x20) /* Dummy one */
|
||||||
|
#define EA_KRT_LOCK EA_CODE(EAP_KRT, 0x21)
|
||||||
|
#define EA_KRT_MTU EA_CODE(EAP_KRT, 0x22)
|
||||||
|
#define EA_KRT_WINDOW EA_CODE(EAP_KRT, 0x23)
|
||||||
|
#define EA_KRT_RTT EA_CODE(EAP_KRT, 0x24)
|
||||||
|
#define EA_KRT_RTTVAR EA_CODE(EAP_KRT, 0x25)
|
||||||
|
#define EA_KRT_SSTRESH EA_CODE(EAP_KRT, 0x26)
|
||||||
|
#define EA_KRT_CWND EA_CODE(EAP_KRT, 0x27)
|
||||||
|
#define EA_KRT_ADVMSS EA_CODE(EAP_KRT, 0x28)
|
||||||
|
#define EA_KRT_REORDERING EA_CODE(EAP_KRT, 0x29)
|
||||||
|
#define EA_KRT_HOPLIMIT EA_CODE(EAP_KRT, 0x2a)
|
||||||
|
#define EA_KRT_INITCWND EA_CODE(EAP_KRT, 0x2b)
|
||||||
|
#define EA_KRT_FEATURES EA_CODE(EAP_KRT, 0x2c)
|
||||||
|
#define EA_KRT_RTO_MIN EA_CODE(EAP_KRT, 0x2d)
|
||||||
|
#define EA_KRT_INITRWND EA_CODE(EAP_KRT, 0x2e)
|
||||||
|
#define EA_KRT_QUICKACK EA_CODE(EAP_KRT, 0x2f)
|
||||||
|
|
||||||
|
/* Bits of EA_KRT_LOCK, also based on RTAX_* constants */
|
||||||
|
#define EA_KRT_LOCK_MTU EA_KRT_LOCK | EA_BIT(0x2)
|
||||||
|
#define EA_KRT_LOCK_WINDOW EA_KRT_LOCK | EA_BIT(0x3)
|
||||||
|
#define EA_KRT_LOCK_RTT EA_KRT_LOCK | EA_BIT(0x4)
|
||||||
|
#define EA_KRT_LOCK_RTTVAR EA_KRT_LOCK | EA_BIT(0x5)
|
||||||
|
#define EA_KRT_LOCK_SSTHRESH EA_KRT_LOCK | EA_BIT(0x6)
|
||||||
|
#define EA_KRT_LOCK_CWND EA_KRT_LOCK | EA_BIT(0x7)
|
||||||
|
#define EA_KRT_LOCK_ADVMSS EA_KRT_LOCK | EA_BIT(0x8)
|
||||||
|
#define EA_KRT_LOCK_REORDERING EA_KRT_LOCK | EA_BIT(0x9)
|
||||||
|
#define EA_KRT_LOCK_HOPLIMIT EA_KRT_LOCK | EA_BIT(0xa)
|
||||||
|
// define EA_KRT_LOCK_INITCWND EA_KRT_LOCK | EA_BIT(0xb)
|
||||||
|
// define EA_KRT_LOCK_FEATURES EA_KRT_LOCK | EA_BIT(0xc)
|
||||||
|
#define EA_KRT_LOCK_RTO_MIN EA_KRT_LOCK | EA_BIT(0xd)
|
||||||
|
// define EA_KRT_LOCK_INITRWND EA_KRT_LOCK | EA_BIT(0xe)
|
||||||
|
|
||||||
|
/* Bits of EA_KRT_FEATURES, based on RTAX_FEATURE_* constants */
|
||||||
|
#define EA_KRT_FEATURE_ECN EA_KRT_FEATURES | EA_BIT(0x0)
|
||||||
|
// define EA_KRT_FEATURE_SACK EA_KRT_FEATURES | EA_BIT(0x1)
|
||||||
|
// define EA_KRT_FEATURE_TSTAMP EA_KRT_FEATURES | EA_BIT(0x2)
|
||||||
|
#define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define NL_NUM_TABLES 256
|
#define NL_NUM_TABLES 256
|
||||||
|
|
||||||
struct krt_params {
|
struct krt_params {
|
||||||
|
@ -10,7 +10,12 @@ CF_HDR
|
|||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(KERNEL, TABLE, KRT_PREFSRC, KRT_REALM)
|
CF_KEYWORDS(KERNEL, TABLE, KRT_PREFSRC, KRT_REALM, KRT_MTU, KRT_WINDOW, KRT_RTT,
|
||||||
|
KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING,
|
||||||
|
KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK,
|
||||||
|
KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR,
|
||||||
|
KRT_LOCK_SSTRESH, KRT_LOCK_CWND, KRT_LOCK_ADVMSS, KRT_LOCK_REORDERING,
|
||||||
|
KRT_LOCK_HOPLIMIT, KRT_LOCK_RTO_MIN, KRT_FEATURE_ECN, KRT_FEATURE_ALLFRAG)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -1191,7 +1191,7 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
krt_get_attr(eattr *a, byte *buf, int buflen)
|
||||||
{
|
{
|
||||||
switch (a->id)
|
switch (a->id)
|
||||||
{
|
{
|
||||||
@ -1203,16 +1203,8 @@ krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
|||||||
bsprintf(buf, "metric");
|
bsprintf(buf, "metric");
|
||||||
return GA_NAME;
|
return GA_NAME;
|
||||||
|
|
||||||
case EA_KRT_PREFSRC:
|
|
||||||
bsprintf(buf, "prefsrc");
|
|
||||||
return GA_NAME;
|
|
||||||
|
|
||||||
case EA_KRT_REALM:
|
|
||||||
bsprintf(buf, "realm");
|
|
||||||
return GA_NAME;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return GA_UNKNOWN;
|
return krt_sys_get_attr(a, buf, buflen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@ struct kif_proto;
|
|||||||
|
|
||||||
#define EA_KRT_SOURCE EA_CODE(EAP_KRT, 0)
|
#define EA_KRT_SOURCE EA_CODE(EAP_KRT, 0)
|
||||||
#define EA_KRT_METRIC EA_CODE(EAP_KRT, 1)
|
#define EA_KRT_METRIC EA_CODE(EAP_KRT, 1)
|
||||||
#define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 2)
|
|
||||||
#define EA_KRT_REALM EA_CODE(EAP_KRT, 3)
|
|
||||||
|
|
||||||
/* Whenever we recognize our own routes, we allow learing of foreign routes */
|
/* Whenever we recognize our own routes, we allow learing of foreign routes */
|
||||||
|
|
||||||
@ -131,6 +129,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *);
|
|||||||
int krt_capable(rte *e);
|
int krt_capable(rte *e);
|
||||||
void krt_do_scan(struct krt_proto *);
|
void krt_do_scan(struct krt_proto *);
|
||||||
void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs);
|
void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs);
|
||||||
|
int krt_sys_get_attr(eattr *a, byte *buf, int buflen);
|
||||||
|
|
||||||
|
|
||||||
/* kif sysdep */
|
/* kif sysdep */
|
||||||
|
Loading…
Reference in New Issue
Block a user