0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Merge commit '17f91f9e6e70f7e3f29502e854823c0d48571eaa' into haugesund

This commit is contained in:
Maria Matejka 2022-05-30 16:59:24 +02:00
commit 5051e3c4af
54 changed files with 1056 additions and 878 deletions

View File

@ -86,9 +86,12 @@ static uint cf_hash(const byte *c);
HASH_DEFINE_REHASH_FN(SYM, struct symbol)
HASH(struct keyword) kw_hash;
HASH(struct ea_class) ea_name_hash;
struct sym_scope *conf_this_scope;
struct sym_scope *global_root_scope;
static struct sym_scope global_root_scope__init = { .active = 1, };
struct sym_scope *global_root_scope = &global_root_scope__init;
linpool *cfg_mem;
@ -598,6 +601,25 @@ cf_new_symbol(const byte *c)
return s;
}
static struct symbol *
cf_root_symbol(const byte *c)
{
uint l = strlen(c);
if (l > SYM_MAX_LEN)
bug("Root symbol %s too long", c);
struct symbol *s = mb_alloc(&root_pool, sizeof(struct symbol) + l + 1);
*s = (struct symbol) { .scope = global_root_scope, .class = SYM_VOID, };
memcpy(s->name, c, l+1);
if (!global_root_scope->hash.data)
HASH_INIT(global_root_scope->hash, &root_pool, SYM_ORDER);
HASH_INSERT2(global_root_scope->hash, SYM, &root_pool, s);
return s;
}
/**
* cf_find_symbol_scope - find a symbol by name
* @scope: config scope
@ -652,7 +674,7 @@ cf_localize_symbol(struct symbol *sym)
/* If the symbol type is void, it has been recently allocated just in this scope. */
if (!sym->class)
return sym;
/* If the scope is the current, it is already defined in this scope. */
if (sym->scope == conf_this_scope)
cf_error("Symbol already defined");
@ -716,8 +738,34 @@ cf_lex_init_kh(void)
struct keyword *k;
for (k=keyword_list; k->name; k++)
HASH_INSERT(kw_hash, KW, k);
}
global_root_scope = mb_allocz(&root_pool, sizeof(*global_root_scope));
void
ea_lex_register(struct ea_class *def)
{
struct symbol *sym = cf_root_symbol(def->name);
sym->class = SYM_ATTRIBUTE;
sym->attribute = def;
def->sym = sym;
}
void
ea_lex_unregister(struct ea_class *def)
{
struct symbol *sym = def->sym;
HASH_REMOVE2(global_root_scope->hash, SYM, &root_pool, sym);
mb_free(sym);
def->sym = NULL;
}
struct ea_class *
ea_class_find_by_name(const char *name)
{
struct symbol *sym = cf_find_symbol(global_root_scope, name);
if (!sym || (sym->class != SYM_ATTRIBUTE))
return NULL;
else
return sym->attribute;
}
/**

View File

@ -121,7 +121,7 @@ struct symbol {
const struct f_line *function; /* For SYM_FUNCTION */
const struct filter *filter; /* For SYM_FILTER */
struct rtable_config *table; /* For SYM_TABLE */
struct f_dynamic_attr *attribute; /* For SYM_ATTRIBUTE */
struct ea_class *attribute; /* For SYM_ATTRIBUTE */
struct f_val *val; /* For SYM_CONSTANT */
uint offset; /* For SYM_VARIABLE */
};

View File

@ -71,8 +71,9 @@ CF_DECLS
} xp;
enum filter_return fret;
enum ec_subtype ecs;
struct f_dynamic_attr fda;
struct ea_class *ea_class;
struct f_static_attr fsa;
struct f_attr_bit fab;
struct f_lval flv;
struct f_line *fl;
const struct filter *f;

View File

@ -22,6 +22,13 @@ static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
#define f_generate_complex(fi_code, da, arg) \
f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
#define f_generate_complex_sym(fi_code, sym, arg) ({ \
if (sym->class != SYM_ATTRIBUTE) \
cf_error("Can't empty %s: not an attribute", sym->name); \
f_generate_complex(fi_code, sym->attribute, arg); \
})
/*
* Sets and their items are during parsing handled as lists, linked
* through left ptr. The first item in a list also contains a pointer
@ -161,27 +168,31 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
}
static inline struct f_inst *
f_generate_empty(struct f_dynamic_attr dyn)
f_generate_empty(const struct symbol *sym)
{
const struct f_val *empty = f_get_empty(dyn.type);
if (sym->class != SYM_ATTRIBUTE)
cf_error("Can't empty %s: not an attribute", sym->name);
const struct ea_class *def = sym->attribute;
const struct f_val *empty = f_get_empty(def->type);
if (!empty)
cf_error("Can't empty that attribute");
cf_error("Can't empty attribute %s", def->name);
return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, *empty), dyn);
return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, *empty), def);
}
#define BA_AS_PATH 0x02
static inline struct f_inst *
f_implicit_roa_check(struct rtable_config *tab)
{
struct f_dynamic_attr fda = f_new_dynamic_attr(T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
const struct ea_class *def = ea_class_find("bgp_path");
if (!def)
cf_error("Fatal: Couldn't find BGP path attribute definition.");
struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1);
return f_new_inst(FI_ROA_CHECK,
f_new_inst(FI_RTA_GET, fsa),
f_new_inst(FI_AS_PATH_LAST, f_new_inst(FI_EA_GET, fda)),
f_new_inst(FI_AS_PATH_LAST, f_new_inst(FI_EA_GET, def)),
tab);
}
@ -293,8 +304,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <xp> cmds_int cmd_prep
%type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
%type <fda> dynamic_attr attr_bit
%type <fsa> static_attr
%type <fab> attr_bit
%type <f> filter where_filter
%type <fl> filter_body function_body
%type <flv> lvalue
@ -335,7 +346,14 @@ filter_eval:
conf: custom_attr ;
custom_attr: ATTRIBUTE type symbol ';' {
cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
if (($3->class == SYM_ATTRIBUTE) && ($3->scope == new_config->root_scope))
cf_error("Duplicate attribute %s definition", $3->name);
cf_define_symbol($3, SYM_ATTRIBUTE, attribute,
ea_register_alloc(new_config->pool, (struct ea_class) {
.name = $3->name,
.type = $2,
})->class);
};
conf: bt_test_suite ;
@ -736,7 +754,7 @@ symbol_value: CF_SYM_KNOWN
$$ = f_new_inst(FI_VAR_GET, $1);
break;
case SYM_ATTRIBUTE:
$$ = f_new_inst(FI_EA_GET, *$1->attribute);
$$ = f_new_inst(FI_EA_GET, $1->attribute);
break;
default:
cf_error("Can't get value of symbol %s", $1->name);
@ -785,11 +803,9 @@ term:
| constructor { $$ = $1; }
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
| dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
| attr_bit {
struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)});
$$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1), c));
$$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1.class), c));
}
| term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
@ -833,8 +849,6 @@ term:
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
/* | term '.' LEN { $$->code = P('P','l'); } */
| function_call
;
@ -867,7 +881,9 @@ cmd:
$$ = f_new_inst(FI_VAR_SET, $3, $1);
break;
case SYM_ATTRIBUTE:
$$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
if ($1->attribute->readonly)
cf_error("Attribute %s is read-only", $1->attribute->name);
$$ = f_new_inst(FI_EA_SET, $3, $1->attribute);
break;
default:
cf_error("Can't assign to symbol %s", $1->name);
@ -877,22 +893,23 @@ cmd:
DBG( "Ook, we'll return the value\n" );
$$ = f_new_inst(FI_RETURN, $2);
}
| dynamic_attr '=' term ';' {
$$ = f_new_inst(FI_EA_SET, $3, $1);
}
| static_attr '=' term ';' {
if ($1.readonly)
cf_error( "This static attribute is read-only.");
$$ = f_new_inst(FI_RTA_SET, $3, $1);
}
| UNSET '(' dynamic_attr ')' ';' {
$$ = f_new_inst(FI_EA_UNSET, $3);
| UNSET '(' CF_SYM_KNOWN ')' ';' {
if ($3->class != SYM_ATTRIBUTE)
cf_error("Can't unset %s", $3->name);
if ($3->attribute->readonly)
cf_error("Attribute %s is read-only", $3->attribute->name);
$$ = f_new_inst(FI_EA_UNSET, $3->attribute);
}
| attr_bit '=' term ';' {
$$ = f_new_inst(FI_CONDITION, $3,
f_generate_complex(FI_BITOR, $1,
f_generate_complex(FI_BITOR, $1.class,
f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)})),
f_generate_complex(FI_BITAND, $1,
f_generate_complex(FI_BITAND, $1.class,
f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << $1.bit)}))
);
}
@ -919,11 +936,11 @@ cmd:
$$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
}
| dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
| dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
| dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
| dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
| dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
| CF_SYM_KNOWN '.' EMPTY ';' { $$ = f_generate_empty($1); }
| CF_SYM_KNOWN '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); }
| CF_SYM_KNOWN '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); }
| CF_SYM_KNOWN '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); }
| CF_SYM_KNOWN '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
| BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
;
@ -934,8 +951,17 @@ get_cf_position:
};
lvalue:
CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
CF_SYM_KNOWN {
switch ($1->class) {
case SYM_VARIABLE_RANGE:
$$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
break;
case SYM_ATTRIBUTE:
$$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1->attribute };
break;
}
}
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
| dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
;
CF_END

View File

@ -21,13 +21,6 @@ struct f_val {
#define fputip(a) ({ ip_addr *ax = falloc(sizeof(*ax)); *ax = (a); ax; })
/* Dynamic attribute definition (eattrs) */
struct f_dynamic_attr {
btype type; /* EA type (EAF_*) */
u8 bit; /* For bitfield accessors */
uint ea_code; /* EA code */
};
enum f_sa_code {
SA_FROM = 1,
SA_GW,
@ -53,7 +46,6 @@ struct f_static_attr {
/* Filter l-value type */
enum f_lval_type {
F_LVAL_VARIABLE,
F_LVAL_PREFERENCE,
F_LVAL_SA,
F_LVAL_EA,
};
@ -63,7 +55,7 @@ struct f_lval {
enum f_lval_type type;
union {
struct symbol *sym;
struct f_dynamic_attr da;
const struct ea_class *da;
struct f_static_attr sa;
};
};

View File

@ -94,7 +94,7 @@ FID_DUMP_BODY()m4_dnl
debug("%s" $4 "\n", INDENT, $5);
]])
FID_INTERPRET_EXEC()m4_dnl
const $1 $2 = whati->$2
$1 $2 = whati->$2
FID_INTERPRET_BODY')
# Instruction arguments are needed only until linearization is done.
@ -256,7 +256,7 @@ FID_INTERPRET_BODY()')
m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)')
m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], "route table %s", item->rtc->name)')
m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)')
m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)')
m4_define(DYNAMIC_ATTR, `FID_MEMBER(const struct ea_class *, da, f1->da != f2->da,,)')
m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access"); } while (0)]],NEVER_CONSTANT())')
# 2) Code wrapping

View File

@ -662,14 +662,14 @@
DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
RESULT_TYPE(da.type);
RESULT_TYPE(da->type);
{
const struct f_val *empty;
eattr *e = ea_find(*fs->eattrs, da.ea_code);
const eattr *e = ea_find(*fs->eattrs, da->id);
if (e)
{
ASSERT_DIE(e->type == da.type);
ASSERT_DIE(e->type == da->type);
switch (e->type) {
case T_IP:
@ -682,7 +682,7 @@
}]]);
}
}
else if (empty = f_get_empty(da.type))
else if (empty = f_get_empty(da->type))
RESULT_VAL(*empty);
else
RESULT_VOID;
@ -694,16 +694,16 @@
ACCESS_EATTRS;
ARG_ANY(1);
DYNAMIC_ATTR;
ARG_TYPE(1, da.type);
ARG_TYPE(1, da->type);
{
struct eattr *a;
if (da.type >= EAF_TYPE__MAX)
if (da->type >= EAF_TYPE__MAX)
bug("Unsupported attribute type");
f_rta_cow(fs);
switch (da.type) {
switch (da->type) {
case T_OPAQUE:
case T_IFACE:
runtime( "Setting opaque attribute is not allowed" );
@ -711,12 +711,12 @@
case T_IP:
a = ea_set_attr(fs->eattrs,
EA_LITERAL_STORE_ADATA(da.ea_code, da.type, 0, &v1.val.ip, sizeof(ip_addr)));
EA_LITERAL_STORE_ADATA(da, 0, &v1.val.ip, sizeof(ip_addr)));
break;
default:
a = ea_set_attr(fs->eattrs,
EA_LITERAL_GENERIC(da.ea_code, da.type, 0, .u = v1.val.bval));
EA_LITERAL_GENERIC(da->id, da->type, 0, .u = v1.val.bval));
break;
}
@ -731,7 +731,7 @@
ACCESS_EATTRS;
f_rta_cow(fs);
ea_unset_attr(fs->eattrs, 1, da.ea_code);
ea_unset_attr(fs->eattrs, 1, da);
}
INST(FI_LENGTH, 1, 1) { /* Get length of */

View File

@ -87,15 +87,17 @@ void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit);
struct filter *f_new_where(struct f_inst *);
static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, uint code)
{ return (struct f_dynamic_attr) { .type = type, .ea_code = code }; }
static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, uint code)
{ return (struct f_dynamic_attr) { .type = T_INT, .bit = bit, .ea_code = code }; }
static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
struct f_attr_bit {
const struct ea_class *class;
uint bit;
};
#define f_new_dynamic_attr_bit(_bit, _name) ((struct f_attr_bit) { .bit = _bit, .class = ea_class_find(_name) })
/* Hook for call bt_assert() function in configuration */
extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);

View File

@ -2,7 +2,7 @@
* Filters: utility functions
*
* Copyright 1998 Pavel Machek <pavel@ucw.cz>
* 2017 Jan Maria Matejka <mq@ucw.cz>
* 2017 Maria Matejka <mq@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@ -40,129 +40,3 @@ struct filter *f_new_where(struct f_inst *where)
f->root = f_linearize(cond);
return f;
}
#define CA_KEY(n) n->name, n->fda.type
#define CA_NEXT(n) n->next
#define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb))
#define CA_FN(n,t) (mem_hash(n, strlen(n)) ^ (t*0xaae99453U))
#define CA_ORDER 8 /* Fixed */
struct ca_storage {
struct ca_storage *next;
struct f_dynamic_attr fda;
u32 uc;
char name[0];
};
HASH(struct ca_storage) ca_hash;
static struct idm ca_idm;
static struct ca_storage **ca_storage;
static uint ca_storage_max;
static void
ca_free(resource *r)
{
struct custom_attribute *ca = (void *) r;
struct ca_storage *cas = HASH_FIND(ca_hash, CA, ca->name, ca->fda->type);
ASSERT(cas);
ca->name = NULL;
ca->fda = NULL;
if (!--cas->uc) {
uint id = EA_CUSTOM_ID(cas->fda.ea_code);
idm_free(&ca_idm, id);
HASH_REMOVE(ca_hash, CA, cas);
ca_storage[id] = NULL;
mb_free(cas);
}
}
static void
ca_dump(resource *r)
{
struct custom_attribute *ca = (void *) r;
debug("name \"%s\" id 0x%04x ea_type 0x%02x\n",
ca->name, ca->fda->ea_code, ca->fda->type);
}
static struct resclass ca_class = {
.name = "Custom attribute",
.size = sizeof(struct custom_attribute),
.free = ca_free,
.dump = ca_dump,
.lookup = NULL,
.memsize = NULL,
};
struct custom_attribute *
ca_lookup(pool *p, const char *name, btype type)
{
switch (type) {
case T_INT:
case T_IP:
case T_QUAD:
case T_PATH:
case T_CLIST:
case T_ECLIST:
case T_LCLIST:
break;
default:
cf_error("Custom route attribute of unsupported type");
}
static int inited = 0;
if (!inited) {
idm_init(&ca_idm, &root_pool, 8);
HASH_INIT(ca_hash, &root_pool, CA_ORDER);
ca_storage_max = 256;
ca_storage = mb_allocz(&root_pool, sizeof(struct ca_storage *) * ca_storage_max);
inited++;
}
struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, type);
if (cas) {
cas->uc++;
} else {
uint id = idm_alloc(&ca_idm);
if (id >= EA_CUSTOM_BIT)
cf_error("Too many custom attributes.");
if (id >= ca_storage_max) {
ca_storage_max *= 2;
ca_storage = mb_realloc(ca_storage, sizeof(struct ca_storage *) * ca_storage_max * 2);
}
cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1);
cas->fda = f_new_dynamic_attr(type, EA_CUSTOM(id));
cas->uc = 1;
strcpy(cas->name, name);
ca_storage[id] = cas;
HASH_INSERT(ca_hash, CA, cas);
}
struct custom_attribute *ca = ralloc(p, &ca_class);
ca->fda = &(cas->fda);
ca->name = cas->name;
return ca;
}
const char *
ea_custom_name(uint ea)
{
uint id = EA_CUSTOM_ID(ea);
if (id >= ca_storage_max)
return NULL;
if (!ca_storage[id])
return NULL;
return ca_storage[id]->name;
}

View File

@ -70,13 +70,4 @@ void filters_dump_all(void);
#define FF_SILENT 2 /* Silent filter execution */
/* Custom route attributes */
struct custom_attribute {
resource r;
struct f_dynamic_attr *fda;
const char *name;
};
struct custom_attribute *ca_lookup(pool *p, const char *name, btype type);
#endif

View File

@ -9,7 +9,109 @@ router id 62.168.0.1;
/* We have to setup any protocol */
protocol device { }
/* Setting some custom attributes, enough to force BIRD to reallocate the attribute idmap */
attribute int test_ca_int1;
attribute int test_ca_int2;
attribute int test_ca_int3;
attribute int test_ca_int4;
attribute int test_ca_int5;
attribute int test_ca_int6;
attribute int test_ca_int7;
attribute int test_ca_int8;
attribute int test_ca_int9;
attribute int test_ca_int10;
attribute ip test_ca_ip1;
attribute ip test_ca_ip2;
attribute ip test_ca_ip3;
attribute ip test_ca_ip4;
attribute ip test_ca_ip5;
attribute ip test_ca_ip6;
attribute ip test_ca_ip7;
attribute ip test_ca_ip8;
attribute ip test_ca_ip9;
attribute ip test_ca_ip10;
attribute quad test_ca_quad1;
attribute quad test_ca_quad2;
attribute quad test_ca_quad3;
attribute quad test_ca_quad4;
attribute quad test_ca_quad5;
attribute quad test_ca_quad6;
attribute quad test_ca_quad7;
attribute quad test_ca_quad8;
attribute quad test_ca_quad9;
attribute quad test_ca_quad10;
attribute bgppath test_ca_bgppath1;
attribute bgppath test_ca_bgppath2;
attribute bgppath test_ca_bgppath3;
attribute bgppath test_ca_bgppath4;
attribute bgppath test_ca_bgppath5;
attribute bgppath test_ca_bgppath6;
attribute bgppath test_ca_bgppath7;
attribute bgppath test_ca_bgppath8;
attribute bgppath test_ca_bgppath9;
attribute bgppath test_ca_bgppath10;
attribute clist test_ca_clist1;
attribute clist test_ca_clist2;
attribute clist test_ca_clist3;
attribute clist test_ca_clist4;
attribute clist test_ca_clist5;
attribute clist test_ca_clist6;
attribute clist test_ca_clist7;
attribute clist test_ca_clist8;
attribute clist test_ca_clist9;
attribute clist test_ca_clist10;
attribute eclist test_ca_eclist1;
attribute eclist test_ca_eclist2;
attribute eclist test_ca_eclist3;
attribute eclist test_ca_eclist4;
attribute eclist test_ca_eclist5;
attribute eclist test_ca_eclist6;
attribute eclist test_ca_eclist7;
attribute eclist test_ca_eclist8;
attribute eclist test_ca_eclist9;
attribute eclist test_ca_eclist10;
attribute lclist test_ca_lclist1;
attribute lclist test_ca_lclist2;
attribute lclist test_ca_lclist3;
attribute lclist test_ca_lclist4;
attribute lclist test_ca_lclist5;
attribute lclist test_ca_lclist6;
attribute lclist test_ca_lclist7;
attribute lclist test_ca_lclist8;
attribute lclist test_ca_lclist9;
attribute lclist test_ca_lclist10;
attribute lclist test_ca_lclist_max1;
attribute lclist test_ca_lclist_max2;
attribute lclist test_ca_lclist_max3;
attribute lclist test_ca_lclist_max4;
attribute lclist test_ca_lclist_max5;
attribute lclist test_ca_lclist_max6;
attribute lclist test_ca_lclist_max7;
attribute lclist test_ca_lclist_max8;
attribute lclist test_ca_lclist_max9;
attribute lclist test_ca_lclist_max10;
attribute lclist test_ca_lclist_max11;
attribute lclist test_ca_lclist_max12;
attribute lclist test_ca_lclist_max13;
attribute lclist test_ca_lclist_max14;
attribute lclist test_ca_lclist_max15;
attribute lclist test_ca_lclist_max16;
attribute lclist test_ca_lclist_max17;
attribute lclist test_ca_lclist_max18;
attribute lclist test_ca_lclist_max19;
attribute lclist test_ca_lclist_max20;
attribute lclist test_ca_lclist_max21;
/* Uncomment this to get an error */
#attribute int bgp_path;
/*
* Common definitions and functions
@ -1331,6 +1433,7 @@ function __test2()
filter testf
int j;
bool t;
{
print "Heya, filtering route to ", net.ip, " prefixlen ", net.len, " source ", source;
print "This route was from ", from;
@ -1342,6 +1445,52 @@ int j;
rip_metric = 14;
unset(rip_metric);
test_ca_int1 = 42;
test_ca_ip2 = 1.3.5.7;
test_ca_quad3 = 2.4.6.8;
test_ca_bgppath4 = +empty+;
test_ca_clist5 = -empty-;
test_ca_eclist6 = --empty--;
test_ca_lclist7 = ---empty---;
igp_metric = 53;
babel_metric = 64;
t = defined(babel_router_id);
j = babel_seqno;
bgp_origin = ORIGIN_IGP;
bgp_path = +empty+;
bgp_next_hop = 3456:789a:bcde:f012::3456:789a;
bgp_med = 71;
bgp_local_pref = 942;
t = defined(bgp_atomic_aggr);
t = defined(bgp_aggregator);
bgp_community = -empty-;
bgp_originator_id = 9.7.5.3;
bgp_cluster_list = -empty-;
t = defined(bgp_mp_reach_nlri);
t = defined(bgp_mp_unreach_nlri);
bgp_ext_community = --empty--;
bgp_as4_path = +empty+;
t = defined(bgp_as4_aggregator);
t = defined(bgp_aigp);
bgp_large_community = ---empty---;
t = defined(bgp_mpls_label_stack);
ospf_metric1 = 64;
ospf_metric2 = 111;
ospf_tag = 654432;
radv_preference = RA_PREF_LOW;
radv_lifetime = 28;
rip_metric = 2;
rip_tag = 4;
t = defined(rip_from);
krt_source = 17;
krt_metric = 19;
# krt_lock_mtu = false;
# krt_lock_window = true;
# krt_lock_rtt = krt_lock_rttvar && krt_lock_sstresh || krt_lock_cwnd;

View File

@ -55,8 +55,8 @@ t_ev_run_list(void)
olock_init();
timer_init();
io_init();
rt_init();
io_init();
if_init();
// roa_init();
config_init();

View File

@ -41,8 +41,6 @@ struct linpool {
uint total, total_large;
};
_Thread_local linpool *tmp_linpool;
static void lp_free(resource *);
static void lp_dump(resource *);
static resource *lp_lookup(resource *, unsigned long);

View File

@ -292,6 +292,25 @@ resource_init(void)
tmp_init(&root_pool);
}
_Thread_local struct tmp_resources tmp_res;
void
tmp_init(pool *p)
{
tmp_res.lp = lp_new_default(p);
tmp_res.parent = p;
tmp_res.pool = rp_new(p, "TMP");
}
void
tmp_flush(void)
{
lp_flush(tmp_linpool);
rfree(tmp_res.pool);
tmp_res.pool = rp_new(tmp_res.parent, "TMP");
}
/**
* DOC: Memory blocks
*

View File

@ -80,14 +80,21 @@ void lp_flush(linpool *); /* Free everything, but leave linpool */
void lp_save(linpool *m, lp_state *p); /* Save state */
void lp_restore(linpool *m, lp_state *p); /* Restore state */
extern _Thread_local linpool *tmp_linpool; /* Temporary linpool autoflushed regularily */
struct tmp_resources {
pool *pool, *parent;
linpool *lp;
};
extern _Thread_local struct tmp_resources tmp_res;
#define tmp_linpool tmp_res.lp
#define tmp_alloc(sz) lp_alloc(tmp_linpool, sz)
#define tmp_allocu(sz) lp_allocu(tmp_linpool, sz)
#define tmp_allocz(sz) lp_allocz(tmp_linpool, sz)
#define tmp_init(p) tmp_linpool = lp_new_default(p)
#define tmp_flush() lp_flush(tmp_linpool)
void tmp_init(pool *p);
void tmp_flush(void);
#define lp_new_default lp_new

View File

@ -152,19 +152,7 @@ typedef struct eattr {
} eattr;
#define EA_CODE(proto,id) (((proto) << 8) | (id))
#define EA_ID(ea) ((ea) & 0xff)
#define EA_PROTO(ea) ((ea) >> 8)
#define EA_CUSTOM(id) ((id) | EA_CUSTOM_BIT)
#define EA_IS_CUSTOM(ea) ((ea) & EA_CUSTOM_BIT)
#define EA_CUSTOM_ID(ea) ((ea) & ~EA_CUSTOM_BIT)
const char *ea_custom_name(uint ea);
#define EA_GEN_IGP_METRIC EA_CODE(PROTOCOL_NONE, 0)
#define EA_CODE_MASK 0xffff
#define EA_CUSTOM_BIT 0x8000
#define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */
#define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */
#define EA_BIT_GET(ea) ((ea) >> 24)
@ -181,32 +169,67 @@ typedef struct ea_list {
#define EALF_BISECT 2 /* Use interval bisection for searching */
#define EALF_CACHED 4 /* Attributes belonging to cached rta */
struct ea_class {
#define EA_CLASS_INSIDE \
const char *name; /* Name (both print and filter) */ \
struct symbol *sym; /* Symbol to export to configs */ \
uint id; /* Autoassigned attribute ID */ \
uint uc; /* Reference count */ \
btype type; /* Data type ID */ \
uint readonly:1; /* This attribute can't be changed by filters */ \
uint conf:1; /* Requested by config */ \
void (*format)(const eattr *ea, byte *buf, uint size); \
EA_CLASS_INSIDE;
};
struct ea_class_ref {
resource r;
struct ea_class *class;
};
extern struct ea_class ea_gen_igp_metric;
void ea_register_init(struct ea_class *);
struct ea_class_ref *ea_register_alloc(pool *, struct ea_class);
#define EA_REGISTER_ALL_HELPER(x) ea_register_init(x);
#define EA_REGISTER_ALL(...) MACRO_FOREACH(EA_REGISTER_ALL_HELPER, __VA_ARGS__)
struct ea_class *ea_class_find_by_id(uint id);
struct ea_class *ea_class_find_by_name(const char *name);
static inline struct ea_class *ea_class_self(struct ea_class *self) { return self; }
#define ea_class_find(_arg) _Generic((_arg), \
uint: ea_class_find_by_id, \
word: ea_class_find_by_id, \
char *: ea_class_find_by_name, \
const char *: ea_class_find_by_name, \
struct ea_class *: ea_class_self)(_arg)
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);
/**
* ea_get_int - fetch an integer attribute
* @e: attribute list
* @id: attribute ID
* @def: default value
*
* This function is a shortcut for retrieving a value of an integer attribute
* by calling ea_find() to find the attribute, extracting its value or returning
* a provided default if no such attribute is present.
*/
static inline u32
ea_get_int(ea_list *e, unsigned id, u32 def)
#define ea_find(_l, _arg) _Generic((_arg), uint: ea_find_by_id, struct ea_class *: ea_find_by_class, char *: ea_find_by_name)(_l, _arg)
eattr *ea_find_by_id(ea_list *, unsigned ea);
static inline eattr *ea_find_by_class(ea_list *l, const struct ea_class *def)
{ return ea_find_by_id(l, def->id); }
static inline eattr *ea_find_by_name(ea_list *l, const char *name)
{
eattr *a = ea_find(e, id);
return a ? a->u.data : def;
const struct ea_class *def = ea_class_find_by_name(name);
return def ? ea_find_by_class(l, def) : NULL;
}
#define ea_get_int(_l, _ident, _def) ({ \
struct ea_class *cls = ea_class_find((_ident)); \
ASSERT_DIE(cls->type & EAF_EMBEDDED); \
const eattr *ea = ea_find((_l), cls->id); \
(ea ? ea->u.data : (_def)); \
})
eattr *ea_walk(struct ea_walk_state *s, uint id, uint max);
void ea_dump(ea_list *);
int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */
uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
@ -221,19 +244,22 @@ void ea_list_copy(ea_list *dest, ea_list *src, uint size);
#define EA_LOCAL_LIST(N) struct { ea_list l; eattr a[N]; }
#define EA_LITERAL_EMBEDDED(_id, _type, _flags, _val) ({ \
#define EA_LITERAL_EMBEDDED(_class, _flags, _val) ({ \
btype _type = (_class)->type; \
ASSERT_DIE(_type & EAF_EMBEDDED); \
EA_LITERAL_GENERIC(_id, _type, _flags, .u.i = _val); \
EA_LITERAL_GENERIC((_class)->id, _type, _flags, .u.i = _val); \
})
#define EA_LITERAL_STORE_ADATA(_id, _type, _flags, _buf, _len) ({ \
#define EA_LITERAL_STORE_ADATA(_class, _flags, _buf, _len) ({ \
btype _type = (_class)->type; \
ASSERT_DIE(!(_type & EAF_EMBEDDED)); \
EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = tmp_store_adata((_buf), (_len))); \
EA_LITERAL_GENERIC((_class)->id, _type, _flags, .u.ad = tmp_store_adata((_buf), (_len))); \
})
#define EA_LITERAL_DIRECT_ADATA(_id, _type, _flags, _adata) ({ \
#define EA_LITERAL_DIRECT_ADATA(_class, _flags, _adata) ({ \
btype _type = (_class)->type; \
ASSERT_DIE(!(_type & EAF_EMBEDDED)); \
EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = _adata); \
EA_LITERAL_GENERIC((_class)->id, _type, _flags, .u.ad = _adata); \
})
#define EA_LITERAL_GENERIC(_id, _type, _flags, ...) \
@ -255,19 +281,19 @@ ea_set_attr(ea_list **to, eattr a)
}
static inline void
ea_unset_attr(ea_list **to, _Bool local, uint code)
ea_unset_attr(ea_list **to, _Bool local, const struct ea_class *def)
{
ea_set_attr(to, EA_LITERAL_GENERIC(code, 0, 0,
ea_set_attr(to, EA_LITERAL_GENERIC(def->id, 0, 0,
.fresh = local, .originated = local, .undef = 1));
}
static inline void
ea_set_attr_u32(ea_list **to, uint id, uint flags, uint type, u32 data)
{ ea_set_attr(to, EA_LITERAL_EMBEDDED(id, type, flags, data)); }
ea_set_attr_u32(ea_list **to, const struct ea_class *def, uint flags, u64 data)
{ ea_set_attr(to, EA_LITERAL_EMBEDDED(def, flags, data)); }
static inline void
ea_set_attr_data(ea_list **to, uint id, uint flags, uint type, void *data, uint len)
{ ea_set_attr(to, EA_LITERAL_STORE_ADATA(id, type, flags, data, len)); }
ea_set_attr_data(ea_list **to, const struct ea_class *def, uint flags, void *data, uint len)
{ ea_set_attr(to, EA_LITERAL_STORE_ADATA(def, flags, data, len)); }
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK)

View File

@ -120,7 +120,7 @@ CF_KEYWORDS(PASSWORD, KEY, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CH
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, BLAKE2S128, BLAKE2S256, BLAKE2B256, BLAKE2B512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
@ -924,9 +924,6 @@ proto_patt2:
| TEXT { $$.ptr = $1; $$.patt = 1; }
;
dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_GEN_IGP_METRIC); } ;
CF_CODE
CF_END

View File

@ -26,7 +26,6 @@ pool *proto_pool;
list STATIC_LIST_INIT(proto_list);
static list STATIC_LIST_INIT(protocol_list);
struct protocol *class_to_protocol[PROTOCOL__MAX];
#define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); })
#define PD(p, msg, args...) ({ if (p->debug & D_STATES) log(L_TRACE "%s: " msg, p->name, ## args); })
@ -1743,9 +1742,6 @@ void
proto_build(struct protocol *p)
{
add_tail(&protocol_list, &p->n);
ASSERT(p->class);
ASSERT(!class_to_protocol[p->class]);
class_to_protocol[p->class] = p;
}
/* FIXME: convert this call to some protocol hook */

View File

@ -38,38 +38,20 @@ struct symbol;
* Routing Protocol
*/
enum protocol_class {
PROTOCOL_NONE,
PROTOCOL_BABEL,
PROTOCOL_BFD,
PROTOCOL_BGP,
PROTOCOL_DEVICE,
PROTOCOL_DIRECT,
PROTOCOL_KERNEL,
PROTOCOL_OSPF,
PROTOCOL_MRT,
PROTOCOL_PERF,
PROTOCOL_PIPE,
PROTOCOL_RADV,
PROTOCOL_RIP,
PROTOCOL_RPKI,
PROTOCOL_STATIC,
PROTOCOL__MAX
};
extern struct protocol *class_to_protocol[PROTOCOL__MAX];
struct protocol {
node n;
char *name;
char *template; /* Template for automatic generation of names */
int name_counter; /* Counter for automatic name generation */
enum protocol_class class; /* Machine readable protocol class */
uint preference; /* Default protocol preference */
uint channel_mask; /* Mask of accepted channel types (NB_*) */
uint proto_size; /* Size of protocol data structure */
uint config_size; /* Size of protocol config data structure */
uint eattr_begin; /* First ID of registered eattrs */
uint eattr_end; /* End of eattr id zone */
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
void (*postconfig)(struct proto_config *); /* After configuring each instance */
struct proto * (*init)(struct proto_config *); /* Create new instance */
@ -79,7 +61,7 @@ struct protocol {
int (*shutdown)(struct proto *); /* Stop the instance */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
// int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
};

View File

@ -60,6 +60,11 @@
const adata null_adata; /* adata of length 0 */
struct ea_class ea_gen_igp_metric = {
.name = "igp_metric",
.type = T_INT,
};
const char * const rta_src_names[RTS_MAX] = {
[RTS_STATIC] = "static",
[RTS_INHERIT] = "inherit",
@ -401,6 +406,117 @@ nexthop_free(struct nexthop *o)
* Extended Attributes
*/
#define EA_CLASS_INITIAL_MAX 128
static struct ea_class **ea_class_global = NULL;
static uint ea_class_max;
static struct idm ea_class_idm;
/* Config parser lex register function */
void ea_lex_register(struct ea_class *def);
void ea_lex_unregister(struct ea_class *def);
static void
ea_class_free(struct ea_class *cl)
{
/* No more ea class references. Unregister the attribute. */
idm_free(&ea_class_idm, cl->id);
ea_class_global[cl->id] = NULL;
ea_lex_unregister(cl);
}
static void
ea_class_ref_free(resource *r)
{
struct ea_class_ref *ref = SKIP_BACK(struct ea_class_ref, r, r);
if (!--ref->class->uc)
ea_class_free(ref->class);
}
static void
ea_class_ref_dump(resource *r)
{
struct ea_class_ref *ref = SKIP_BACK(struct ea_class_ref, r, r);
debug("name \"%s\", type=%d\n", ref->class->name, ref->class->type);
}
static struct resclass ea_class_ref_class = {
.name = "Attribute class reference",
.size = sizeof(struct ea_class_ref),
.free = ea_class_ref_free,
.dump = ea_class_ref_dump,
.lookup = NULL,
.memsize = NULL,
};
static void
ea_class_init(void)
{
idm_init(&ea_class_idm, rta_pool, EA_CLASS_INITIAL_MAX);
ea_class_global = mb_allocz(rta_pool,
sizeof(*ea_class_global) * (ea_class_max = EA_CLASS_INITIAL_MAX));
}
static struct ea_class_ref *
ea_ref_class(pool *p, struct ea_class *def)
{
def->uc++;
struct ea_class_ref *ref = ralloc(p, &ea_class_ref_class);
ref->class = def;
return ref;
}
static struct ea_class_ref *
ea_register(pool *p, struct ea_class *def)
{
def->id = idm_alloc(&ea_class_idm);
ASSERT_DIE(ea_class_global);
while (def->id >= ea_class_max)
ea_class_global = mb_realloc(ea_class_global, sizeof(*ea_class_global) * (ea_class_max *= 2));
ASSERT_DIE(def->id < ea_class_max);
ea_class_global[def->id] = def;
ea_lex_register(def);
return ea_ref_class(p, def);
}
struct ea_class_ref *
ea_register_alloc(pool *p, struct ea_class cl)
{
struct ea_class *clp = ea_class_find_by_name(cl.name);
if (clp && clp->type == cl.type)
return ea_ref_class(p, clp);
uint namelen = strlen(cl.name) + 1;
struct {
struct ea_class cl;
char name[0];
} *cla = mb_alloc(rta_pool, sizeof(struct ea_class) + namelen);
cla->cl = cl;
memcpy(cla->name, cl.name, namelen);
cla->cl.name = cla->name;
return ea_register(p, &cla->cl);
}
void
ea_register_init(struct ea_class *clp)
{
ASSERT_DIE(!ea_class_find_by_name(clp->name));
ea_register(&root_pool, clp);
}
struct ea_class *
ea_class_find_by_id(uint id)
{
ASSERT_DIE(id < ea_class_max);
ASSERT_DIE(ea_class_global[id]);
return ea_class_global[id];
}
static inline eattr *
ea__find(ea_list *e, unsigned id)
{
@ -444,7 +560,7 @@ ea__find(ea_list *e, unsigned id)
* to its &eattr structure or %NULL if no such attribute exists.
*/
eattr *
ea_find(ea_list *e, unsigned id)
ea_find_by_id(ea_list *e, unsigned id)
{
eattr *a = ea__find(e, id & EA_CODE_MASK);
@ -784,28 +900,46 @@ ea_list_copy(ea_list *n, ea_list *o, uint elen)
ASSERT_DIE(adpos == elen);
}
static void
ea_list_ref(ea_list *l)
{
for(uint i=0; i<l->count; i++)
{
eattr *a = &l->attrs[i];
ASSERT_DIE(a->id < ea_class_max);
struct ea_class *cl = ea_class_global[a->id];
ASSERT_DIE(cl && cl->uc);
cl->uc++;
}
}
static void
ea_list_unref(ea_list *l)
{
for(uint i=0; i<l->count; i++)
{
eattr *a = &l->attrs[i];
ASSERT_DIE(a->id < ea_class_max);
struct ea_class *cl = ea_class_global[a->id];
ASSERT_DIE(cl && cl->uc);
if (!--cl->uc)
ea_class_free(cl);
}
}
static inline void
ea_free(ea_list *o)
{
if (o)
{
ea_list_unref(o);
ASSERT(!o->next);
mb_free(o);
}
}
static int
get_generic_attr(const eattr *a, byte **buf, int buflen UNUSED)
{
if (a->id == EA_GEN_IGP_METRIC)
{
*buf += bsprintf(*buf, "igp_metric");
return GA_NAME;
}
return GA_UNKNOWN;
}
void
ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
{
@ -905,47 +1039,27 @@ ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte
void
ea_show(struct cli *c, const eattr *e)
{
struct protocol *p;
int status = GA_UNKNOWN;
const struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
byte buf[CLI_MSG_SIZE];
byte *pos = buf, *end = buf + sizeof(buf);
if (EA_IS_CUSTOM(e->id))
{
const char *name = ea_custom_name(e->id);
if (name)
{
pos += bsprintf(pos, "%s", name);
status = GA_NAME;
}
else
pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
}
else if (p = class_to_protocol[EA_PROTO(e->id)])
{
pos += bsprintf(pos, "%s.", p->name);
if (p->get_attr)
status = p->get_attr(e, pos, end - pos);
pos += strlen(pos);
}
else if (EA_PROTO(e->id))
pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
ASSERT_DIE(e->id < ea_class_max);
struct ea_class *cls = ea_class_global[e->id];
ASSERT_DIE(cls);
pos += bsprintf(pos, "%s", cls->name);
*pos++ = ':';
*pos++ = ' ';
if (e->undef)
bsprintf(pos, "undefined (should not happen)");
else if (cls->format)
cls->format(e, buf, end - buf);
else
status = get_generic_attr(e, &pos, end - pos);
if (status < GA_NAME)
pos += bsprintf(pos, "%02x", EA_ID(e->id));
if (status < GA_FULL)
{
*pos++ = ':';
*pos++ = ' ';
if (e->undef)
bsprintf(pos, "undefined");
else
switch (e->type)
{
switch (e->type)
{
case T_INT:
bsprintf(pos, "%u", e->u.data);
break;
@ -970,13 +1084,10 @@ ea_show(struct cli *c, const eattr *e)
case T_LCLIST:
ea_show_lc_set(c, ad, pos, buf, end);
return;
case T_IFACE:
bsprintf(pos, "%s", ((struct iface *) e->u.ptr)->name);
return;
default:
bsprintf(pos, "<type %02x>", e->type);
}
}
}
cli_printf(c, -1012, "\t%s", buf);
}
@ -1006,7 +1117,7 @@ ea_dump(ea_list *e)
for(i=0; i<e->count; i++)
{
eattr *a = &e->attrs[i];
debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags);
debug(" %04x.%02x", a->id, a->flags);
debug("=%c",
"?iO?IRP???S??pE?"
"??L???N?????????"
@ -1157,6 +1268,7 @@ rta_copy(rta *o)
uint elen = ea_list_size(o->eattrs);
r->eattrs = mb_alloc(rta_pool, elen);
ea_list_copy(r->eattrs, o->eattrs, elen);
ea_list_ref(r->eattrs);
r->eattrs->flags |= EALF_CACHED;
return r;
}
@ -1357,6 +1469,9 @@ rta_init(void)
rta_alloc_hash();
rte_src_init();
ea_class_init();
ea_register_init(&ea_gen_igp_metric);
}
/*

View File

@ -184,7 +184,6 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src)
struct protocol proto_device = {
.name = "Direct",
.template = "direct%d",
.class = PROTOCOL_DIRECT,
.preference = DEF_PREF_DIRECT,
.channel_mask = NB_IP | NB_IP6_SADR,
.proto_size = sizeof(struct rt_dev_proto),

View File

@ -2653,14 +2653,14 @@ net_flow_has_dst_prefix(const net_addr *n)
static inline int
rta_as_path_is_empty(rta *a)
{
eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
eattr *e = ea_find(a->eattrs, "bgp_path");
return !e || (as_path_getlen(e->u.ptr) == 0);
}
static inline u32
rta_get_first_asn(rta *a)
{
eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
eattr *e = ea_find(a->eattrs, "bgp_path");
u32 asn;
return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0;
@ -2704,8 +2704,8 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
return 0;
/* Find ORIGINATOR_ID values */
u32 orig_a = ea_get_int(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0);
u32 orig_b = ea_get_int(rb->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0);
u32 orig_a = ea_get_int(a->eattrs, "bgp_originator_id", 0);
u32 orig_b = ea_get_int(rb->attrs->eattrs, "bgp_originator_id", 0);
/* Originator is either ORIGINATOR_ID (if present), or BGP neighbor address (if not) */
if ((orig_a != orig_b) || (!orig_a && !orig_b && !ipa_equal(a->from, rb->attrs->from)))
@ -3536,7 +3536,7 @@ if_local_addr(ip_addr a, struct iface *i)
u32
rt_get_igp_metric(rte *rt)
{
eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
eattr *ea = ea_find(rt->attrs->eattrs, "igp_metric");
if (ea)
return ea->u.data;

View File

@ -37,6 +37,7 @@
#include <stdlib.h>
#include "babel.h"
#include "lib/macro.h"
#define LOG_PKT_AUTH(msg, args...) \
log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args)
@ -58,6 +59,8 @@ static void babel_update_cost(struct babel_neighbor *n);
static inline void babel_kick_timer(struct babel_proto *p);
static inline void babel_iface_kick_timer(struct babel_iface *ifa);
static struct ea_class ea_babel_metric, ea_babel_router_id, ea_babel_seqno;
/*
* Functions to maintain data structures
*/
@ -646,9 +649,9 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
} eattrs = {
.l.count = 3,
.a = {
EA_LITERAL_EMBEDDED(EA_BABEL_METRIC, T_INT, 0, r->metric),
EA_LITERAL_STORE_ADATA(EA_BABEL_ROUTER_ID, T_OPAQUE, 0, &r->router_id, sizeof(r->router_id)),
EA_LITERAL_EMBEDDED(EA_BABEL_SEQNO, T_INT, 0, r->seqno),
EA_LITERAL_EMBEDDED(&ea_babel_metric, 0, r->metric),
EA_LITERAL_STORE_ADATA(&ea_babel_router_id, 0, &r->router_id, sizeof(r->router_id)),
EA_LITERAL_EMBEDDED(&ea_babel_seqno, 0, r->seqno),
}
};
@ -2021,39 +2024,41 @@ static void
babel_get_route_info(rte *rte, byte *buf)
{
u64 rid = 0;
eattr *e = ea_find(rte->attrs->eattrs, EA_BABEL_ROUTER_ID);
eattr *e = ea_find(rte->attrs->eattrs, &ea_babel_router_id);
if (e)
memcpy(&rid, e->u.ptr->data, sizeof(u64));
buf += bsprintf(buf, " (%d/%d) [%lR]", rte->attrs->pref,
ea_get_int(rte->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY), rid);
ea_get_int(rte->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY), rid);
}
static int
babel_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
static void
babel_router_id_format(const eattr *a, byte *buf, uint len)
{
switch (a->id)
{
case EA_BABEL_SEQNO:
return GA_FULL;
case EA_BABEL_METRIC:
bsprintf(buf, "metric: %d", a->u.data);
return GA_FULL;
case EA_BABEL_ROUTER_ID:
{
u64 rid = 0;
memcpy(&rid, a->u.ptr->data, sizeof(u64));
bsprintf(buf, "router_id: %lR", rid);
return GA_FULL;
}
default:
return GA_UNKNOWN;
}
u64 rid = 0;
memcpy(&rid, a->u.ptr->data, sizeof(u64));
bsnprintf(buf, len, "%lR", rid);
}
static struct ea_class ea_babel_metric = {
.name = "babel_metric",
.type = T_INT,
};
static struct ea_class ea_babel_router_id = {
.name = "babel_router_id",
.type = T_OPAQUE,
.readonly = 1,
.format = babel_router_id_format,
};
static struct ea_class ea_babel_seqno = {
.name = "babel_seqno",
.type = T_INT,
.readonly = 1,
};
void
babel_show_interfaces(struct proto *P, const char *iff)
{
@ -2275,13 +2280,13 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
{
/* Update */
uint rt_seqno;
uint rt_metric = ea_get_int(new->attrs->eattrs, EA_BABEL_METRIC, 0);
uint rt_metric = ea_get_int(new->attrs->eattrs, &ea_babel_metric, 0);
u64 rt_router_id = 0;
if (new->src->proto == P)
{
rt_seqno = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
eattr *e = ea_find(new->attrs->eattrs, EA_BABEL_ROUTER_ID);
rt_seqno = ea_get_int(new->attrs->eattrs, &ea_babel_seqno, 0);
eattr *e = ea_find(new->attrs->eattrs, &ea_babel_router_id);
if (e)
memcpy(&rt_router_id, e->u.ptr->data, sizeof(u64));
}
@ -2332,8 +2337,8 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
static int
babel_rte_better(struct rte *new, struct rte *old)
{
uint new_metric = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
uint old_metric = ea_find(old->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
uint new_metric = ea_get_int(new->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY);
uint old_metric = ea_get_int(old->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY);
return new_metric < old_metric;
}
@ -2341,7 +2346,7 @@ babel_rte_better(struct rte *new, struct rte *old)
static u32
babel_rte_igp_metric(struct rte *rt)
{
return ea_get_int(rt->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY);
return ea_get_int(rt->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY);
}
@ -2474,11 +2479,9 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
return 1;
}
struct protocol proto_babel = {
.name = "Babel",
.template = "babel%d",
.class = PROTOCOL_BABEL,
.preference = DEF_PREF_BABEL,
.channel_mask = NB_IP | NB_IP6_SADR,
.proto_size = sizeof(struct babel_proto),
@ -2490,11 +2493,16 @@ struct protocol proto_babel = {
.shutdown = babel_shutdown,
.reconfigure = babel_reconfigure,
.get_route_info = babel_get_route_info,
.get_attr = babel_get_attr
};
void
babel_build(void)
{
proto_build(&proto_babel);
EA_REGISTER_ALL(
&ea_babel_metric,
&ea_babel_router_id,
&ea_babel_seqno
);
}

View File

@ -26,10 +26,6 @@
#include "lib/string.h"
#include "lib/timer.h"
#define EA_BABEL_METRIC EA_CODE(PROTOCOL_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(PROTOCOL_BABEL, 1)
#define EA_BABEL_SEQNO EA_CODE(PROTOCOL_BABEL, 2)
#define BABEL_MAGIC 42
#define BABEL_VERSION 2
#define BABEL_PORT 6696

View File

@ -163,8 +163,6 @@ babel_iface_opt_list:
babel_iface:
babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish;
dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_BABEL_METRIC); } ;
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
CF_CLI(SHOW BABEL INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])

View File

@ -1183,7 +1183,6 @@ bfd_show_sessions(struct proto *P)
struct protocol proto_bfd = {
.name = "BFD",
.template = "bfd%d",
.class = PROTOCOL_BFD,
.proto_size = sizeof(struct bfd_proto),
.config_size = sizeof(struct bfd_config),
.init = bfd_init,

View File

@ -21,6 +21,7 @@
#include "lib/resource.h"
#include "lib/string.h"
#include "lib/unaligned.h"
#include "lib/macro.h"
#include "bgp.h"
@ -64,28 +65,37 @@
* format - Optional hook that converts eattr to textual representation.
*/
struct bgp_attr_desc {
const char *name;
uint type;
uint flags;
void (*export)(struct bgp_export_state *s, eattr *a);
int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to);
void (*format)(const eattr *ea, byte *buf, uint size);
union bgp_attr_desc {
struct ea_class class;
struct {
EA_CLASS_INSIDE;
uint flags;
void (*export)(struct bgp_export_state *s, eattr *a);
int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to);
};
};
static const struct bgp_attr_desc bgp_attr_table[];
static union bgp_attr_desc bgp_attr_table[];
static inline const union bgp_attr_desc *bgp_find_attr_desc(eattr *a)
{
const struct ea_class *class = ea_class_find(a->id);
static inline int bgp_attr_known(uint code);
if ((class < &bgp_attr_table[0].class) || (class >= &bgp_attr_table[BGP_ATTR_MAX].class))
return NULL;
return (const union bgp_attr_desc *) class;
}
#define BGP_EA_ID(code) (bgp_attr_table[code].id)
#define EA_BGP_ID(code) (((union bgp_attr_desc *) ea_class_find(code)) - bgp_attr_table)
void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val)
{
ASSERT(bgp_attr_known(code));
const union bgp_attr_desc *desc = &bgp_attr_table[code];
ea_set_attr(to, EA_LITERAL_EMBEDDED(
EA_CODE(PROTOCOL_BGP, code),
bgp_attr_table[code].type,
&desc->class,
flags & ~BAF_EXT_LEN,
val
));
@ -93,11 +103,10 @@ void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val)
void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *ad)
{
ASSERT(bgp_attr_known(code));
const union bgp_attr_desc *desc = &bgp_attr_table[code];
ea_set_attr(to, EA_LITERAL_DIRECT_ADATA(
EA_CODE(PROTOCOL_BGP, code),
bgp_attr_table[code].type,
&desc->class,
flags & ~BAF_EXT_LEN,
ad
));
@ -106,17 +115,23 @@ void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *a
void
bgp_set_attr_data(ea_list **to, uint code, uint flags, void *data, uint len)
{
ASSERT(bgp_attr_known(code));
const union bgp_attr_desc *desc = &bgp_attr_table[code];
ea_set_attr(to, EA_LITERAL_STORE_ADATA(
EA_CODE(PROTOCOL_BGP, code),
bgp_attr_table[code].type,
&desc->class,
flags & ~BAF_EXT_LEN,
data,
len
));
}
void
bgp_unset_attr(ea_list **to, uint code)
{
const union bgp_attr_desc *desc = &bgp_attr_table[code];
ea_unset_attr(to, 0, &desc->class);
}
#define REPORT(msg, args...) \
({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
@ -172,7 +187,7 @@ bgp_encode_u8(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
if (size < (3+1))
return -1;
bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 1);
bgp_put_attr_hdr3(buf, EA_BGP_ID(a->id), a->flags, 1);
buf[3] = a->u.data;
return 3+1;
@ -184,7 +199,7 @@ bgp_encode_u32(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
if (size < (3+4))
return -1;
bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 4);
bgp_put_attr_hdr3(buf, EA_BGP_ID(a->id), a->flags, 4);
put_u32(buf+3, a->u.data);
return 3+4;
@ -198,7 +213,7 @@ bgp_encode_u32s(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size
if (size < (4+len))
return -1;
uint hdr = bgp_put_attr_hdr(buf, EA_ID(a->id), a->flags, len);
uint hdr = bgp_put_attr_hdr(buf, EA_BGP_ID(a->id), a->flags, len);
put_u32s(buf + hdr, (u32 *) a->u.ptr->data, len / 4);
return hdr + len;
@ -219,7 +234,7 @@ bgp_put_attr(byte *buf, uint size, uint code, uint flags, const byte *data, uint
static int
bgp_encode_raw(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
{
return bgp_put_attr(buf, size, EA_ID(a->id), a->flags, a->u.ptr->data, a->u.ptr->length);
return bgp_put_attr(buf, size, EA_BGP_ID(a->id), a->flags, a->u.ptr->data, a->u.ptr->length);
}
@ -359,7 +374,7 @@ bgp_aigp_set_metric(struct linpool *pool, const struct adata *ad, u64 metric)
int
bgp_total_aigp_metric_(struct rta *a, u64 *metric, const struct adata **ad)
{
eattr *ea = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP));
eattr *ea = ea_find(a->eattrs, BGP_EA_ID(BA_AIGP));
if (!ea)
return 0;
@ -993,11 +1008,30 @@ bgp_format_mpls_label_stack(const eattr *a, byte *buf, uint size)
pos[lnum ? -1 : 0] = 0;
}
static inline void
bgp_export_unknown(struct bgp_export_state *s UNUSED, eattr *a)
{
if (!(a->flags & BAF_TRANSITIVE))
UNSET(a);
a->flags |= BAF_PARTIAL;
}
static inline void
bgp_decode_unknown(struct bgp_parse_state *s UNUSED, uint code, uint flags, byte *data, uint len, ea_list **to)
{
if (!(flags & BAF_OPTIONAL))
WITHDRAW("Unknown attribute (code %u) - conflicting flags (%02x)", code, flags);
/* Cannot use bgp_set_attr_data() as it works on known attributes only */
ea_set_attr_data(to, EA_CODE(PROTOCOL_BGP, code), flags, T_OPAQUE, data, len);
ea_set_attr_data(to, &bgp_attr_table[code].class, flags, data, len);
}
static inline void
bgp_format_unknown(const eattr *a, byte *buf, uint size)
{
if (a->flags & BAF_TRANSITIVE)
bsnprintf(buf, size, "(transitive)");
}
@ -1005,9 +1039,9 @@ bgp_decode_unknown(struct bgp_parse_state *s UNUSED, uint code, uint flags, byte
* Attribute table
*/
static const struct bgp_attr_desc bgp_attr_table[] = {
static union bgp_attr_desc bgp_attr_table[BGP_ATTR_MAX] = {
[BA_ORIGIN] = {
.name = "origin",
.name = "bgp_origin",
.type = T_ENUM_BGP_ORIGIN,
.flags = BAF_TRANSITIVE,
.export = bgp_export_origin,
@ -1016,14 +1050,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.format = bgp_format_origin,
},
[BA_AS_PATH] = {
.name = "as_path",
.name = "bgp_path",
.type = T_PATH,
.flags = BAF_TRANSITIVE,
.encode = bgp_encode_as_path,
.decode = bgp_decode_as_path,
},
[BA_NEXT_HOP] = {
.name = "next_hop",
.name = "bgp_next_hop",
.type = T_IP,
.flags = BAF_TRANSITIVE,
.encode = bgp_encode_next_hop,
@ -1031,14 +1065,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.format = bgp_format_next_hop,
},
[BA_MULTI_EXIT_DISC] = {
.name = "med",
.name = "bgp_med",
.type = T_INT,
.flags = BAF_OPTIONAL,
.encode = bgp_encode_u32,
.decode = bgp_decode_med,
},
[BA_LOCAL_PREF] = {
.name = "local_pref",
.name = "bgp_local_pref",
.type = T_INT,
.flags = BAF_TRANSITIVE,
.export = bgp_export_local_pref,
@ -1046,14 +1080,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.decode = bgp_decode_local_pref,
},
[BA_ATOMIC_AGGR] = {
.name = "atomic_aggr",
.name = "bgp_atomic_aggr",
.type = T_OPAQUE,
.flags = BAF_TRANSITIVE,
.encode = bgp_encode_raw,
.decode = bgp_decode_atomic_aggr,
},
[BA_AGGREGATOR] = {
.name = "aggregator",
.name = "bgp_aggregator",
.type = T_OPAQUE,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.encode = bgp_encode_aggregator,
@ -1061,7 +1095,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.format = bgp_format_aggregator,
},
[BA_COMMUNITY] = {
.name = "community",
.name = "bgp_community",
.type = T_CLIST,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.export = bgp_export_community,
@ -1069,7 +1103,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.decode = bgp_decode_community,
},
[BA_ORIGINATOR_ID] = {
.name = "originator_id",
.name = "bgp_originator_id",
.type = T_QUAD,
.flags = BAF_OPTIONAL,
.export = bgp_export_originator_id,
@ -1077,7 +1111,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.decode = bgp_decode_originator_id,
},
[BA_CLUSTER_LIST] = {
.name = "cluster_list",
.name = "bgp_cluster_list",
.type = T_CLIST,
.flags = BAF_OPTIONAL,
.export = bgp_export_cluster_list,
@ -1086,19 +1120,19 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.format = bgp_format_cluster_list,
},
[BA_MP_REACH_NLRI] = {
.name = "mp_reach_nlri",
.name = "bgp_mp_reach_nlri",
.type = T_OPAQUE,
.flags = BAF_OPTIONAL,
.decode = bgp_decode_mp_reach_nlri,
},
[BA_MP_UNREACH_NLRI] = {
.name = "mp_unreach_nlri",
.name = "bgp_mp_unreach_nlri",
.type = T_OPAQUE,
.flags = BAF_OPTIONAL,
.decode = bgp_decode_mp_unreach_nlri,
},
[BA_EXT_COMMUNITY] = {
.name = "ext_community",
.name = "bgp_ext_community",
.type = T_ECLIST,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.export = bgp_export_ext_community,
@ -1106,14 +1140,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.decode = bgp_decode_ext_community,
},
[BA_AS4_PATH] = {
.name = "as4_path",
.name = "bgp_as4_path",
.type = T_PATH,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.encode = bgp_encode_raw,
.decode = bgp_decode_as4_path,
},
[BA_AS4_AGGREGATOR] = {
.name = "as4_aggregator",
.name = "bgp_as4_aggregator",
.type = T_OPAQUE,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.encode = bgp_encode_raw,
@ -1121,7 +1155,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.format = bgp_format_aggregator,
},
[BA_AIGP] = {
.name = "aigp",
.name = "bgp_aigp",
.type = T_OPAQUE,
.flags = BAF_OPTIONAL | BAF_DECODE_FLAGS,
.export = bgp_export_aigp,
@ -1130,7 +1164,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.format = bgp_format_aigp,
},
[BA_LARGE_COMMUNITY] = {
.name = "large_community",
.name = "bgp_large_community",
.type = T_LCLIST,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.export = bgp_export_large_community,
@ -1138,8 +1172,9 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
.decode = bgp_decode_large_community,
},
[BA_MPLS_LABEL_STACK] = {
.name = "mpls_label_stack",
.name = "bgp_mpls_label_stack",
.type = T_CLIST,
.readonly = 1,
.export = bgp_export_mpls_label_stack,
.encode = bgp_encode_mpls_label_stack,
.decode = bgp_decode_mpls_label_stack,
@ -1147,12 +1182,32 @@ static const struct bgp_attr_desc bgp_attr_table[] = {
},
};
static inline int
bgp_attr_known(uint code)
eattr *
bgp_find_attr(ea_list *attrs, uint code)
{
return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name;
return ea_find(attrs, BGP_EA_ID(code));
}
void
bgp_register_attrs(void)
{
for (uint i=0; i<ARRAY_SIZE(bgp_attr_table); i++)
{
if (!bgp_attr_table[i].name)
bgp_attr_table[i] = (union bgp_attr_desc) {
.name = mb_sprintf(&root_pool, "bgp_unknown_0x%02x", i),
.type = T_OPAQUE,
.flags = BAF_OPTIONAL,
.readonly = 1,
.export = bgp_export_unknown,
.encode = bgp_encode_raw,
.decode = bgp_decode_unknown,
.format = bgp_format_unknown,
};
ea_register_init(&bgp_attr_table[i].class);
}
}
/*
* Attribute export
@ -1161,38 +1216,24 @@ bgp_attr_known(uint code)
static inline void
bgp_export_attr(struct bgp_export_state *s, eattr *a, ea_list *to)
{
if (EA_PROTO(a->id) != PROTOCOL_BGP)
const union bgp_attr_desc *desc = bgp_find_attr_desc(a);
if (!desc)
return;
uint code = EA_ID(a->id);
if (bgp_attr_known(code))
{
const struct bgp_attr_desc *desc = &bgp_attr_table[code];
/* The flags might have been zero if the attr was added by filters */
a->flags = (a->flags & BAF_PARTIAL) | desc->flags;
/* Set partial bit if new opt-trans attribute is attached to non-local route */
if ((s->src != NULL) && (a->originated) &&
(a->flags & BAF_OPTIONAL) && (a->flags & BAF_TRANSITIVE))
a->flags |= BAF_PARTIAL;
/* Call specific hook */
CALL(desc->export, s, a);
/* Attribute might become undefined in hook */
if (a->undef)
return;
}
else
{
/* Don't re-export unknown non-transitive attributes */
if (!(a->flags & BAF_TRANSITIVE))
return;
/* The flags might have been zero if the attr was added locally */
a->flags = (a->flags & BAF_PARTIAL) | desc->flags;
/* Set partial bit if new opt-trans attribute is attached to non-local route */
if ((s->src != NULL) && (a->originated) &&
(a->flags & BAF_OPTIONAL) && (a->flags & BAF_TRANSITIVE))
a->flags |= BAF_PARTIAL;
}
/* Call specific hook */
CALL(desc->export, s, a);
/* Attribute might become undefined in hook */
if (a->undef)
return;
/* Append updated attribute */
to->attrs[to->count++] = *a;
@ -1240,14 +1281,9 @@ bgp_export_attrs(struct bgp_export_state *s, const ea_list *a)
static inline int
bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
{
ASSERT(EA_PROTO(a->id) == PROTOCOL_BGP);
uint code = EA_ID(a->id);
if (bgp_attr_known(code))
return bgp_attr_table[code].encode(s, a, buf, size);
else
return bgp_encode_raw(s, a, buf, size);
const union bgp_attr_desc *desc = bgp_find_attr_desc(a);
ASSERT_DIE(desc);
return desc->encode(s, a, buf, size);
}
/**
@ -1312,7 +1348,7 @@ bgp_cluster_list_loopy(struct bgp_proto *p, ea_list *attrs)
}
static inline void
bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
bgp_decode_attr(struct bgp_parse_state *s, byte code, byte flags, byte *data, uint len, ea_list **to)
{
/* Handle duplicate attributes; RFC 7606 3 (g) */
if (BIT32_TEST(s->attrs_seen, code))
@ -1324,24 +1360,15 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui
}
BIT32_SET(s->attrs_seen, code);
if (bgp_attr_known(code))
{
const struct bgp_attr_desc *desc = &bgp_attr_table[code];
ASSERT_DIE(bgp_attr_table[code].id);
const union bgp_attr_desc *desc = &bgp_attr_table[code];
/* Handle conflicting flags; RFC 7606 3 (c) */
if (((flags ^ desc->flags) & (BAF_OPTIONAL | BAF_TRANSITIVE)) &&
!(desc->flags & BAF_DECODE_FLAGS))
WITHDRAW("Malformed %s attribute - conflicting flags (%02x)", desc->name, flags);
/* Handle conflicting flags; RFC 7606 3 (c) */
if (((flags ^ desc->flags) & (BAF_OPTIONAL | BAF_TRANSITIVE)) &&
!(desc->flags & BAF_DECODE_FLAGS))
WITHDRAW("Malformed %s attribute - conflicting flags (%02x, expected %02x)", desc->name, flags, desc->flags);
desc->decode(s, code, flags, data, len, to);
}
else /* Unknown attribute */
{
if (!(flags & BAF_OPTIONAL))
WITHDRAW("Unknown attribute (code %u) - conflicting flags (%02x)", code, flags);
bgp_decode_unknown(s, code, flags, data, len, to);
}
desc->decode(s, code, flags, data, len, to);
}
/**
@ -1359,7 +1386,8 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
{
struct bgp_proto *p = s->proto;
ea_list *attrs = NULL;
uint code, flags, alen;
uint alen;
byte code, flags;
byte *pos = data;
/* Parse the attributes */
@ -1704,7 +1732,7 @@ bgp_preexport(struct channel *c, rte *e)
/* Handle well-known communities, RFC 1997 */
struct eattr *com;
if (p->cf->interpret_communities &&
(com = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
(com = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY))))
{
const struct adata *d = com->u.ptr;
@ -1881,7 +1909,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, c
static inline u32
bgp_get_neighbor(rte *r)
{
eattr *e = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
eattr *e = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_AS_PATH));
u32 as;
if (e && as_path_get_first_regular(e->u.ptr, &as))
@ -1902,7 +1930,7 @@ rte_stale(rte *r)
return 0;
/* If staleness is unknown, compute and cache it */
eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
eattr *a = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY));
if (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE))
{
r->pflags |= BGP_REF_STALE;
@ -1948,8 +1976,8 @@ bgp_rte_better(rte *new, rte *old)
return 1;
/* Start with local preferences */
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF));
y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF));
n = x ? x->u.data : new_bgp->cf->default_local_pref;
o = y ? y->u.data : old_bgp->cf->default_local_pref;
if (n > o)
@ -1968,8 +1996,8 @@ bgp_rte_better(rte *new, rte *old)
/* RFC 4271 9.1.2.2. a) Use AS path lengths */
if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths)
{
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_AS_PATH));
y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_AS_PATH));
n = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
o = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
if (n < o)
@ -1979,8 +2007,8 @@ bgp_rte_better(rte *new, rte *old)
}
/* RFC 4271 9.1.2.2. b) Use origins */
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_ORIGIN));
y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_ORIGIN));
n = x ? x->u.data : ORIGIN_INCOMPLETE;
o = y ? y->u.data : ORIGIN_INCOMPLETE;
if (n < o)
@ -2002,8 +2030,8 @@ bgp_rte_better(rte *new, rte *old)
if (new_bgp->cf->med_metric || old_bgp->cf->med_metric ||
(bgp_get_neighbor(new) == bgp_get_neighbor(old)))
{
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC));
y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC));
n = x ? x->u.data : new_bgp->cf->default_med;
o = y ? y->u.data : old_bgp->cf->default_med;
if (n < o)
@ -2028,8 +2056,8 @@ bgp_rte_better(rte *new, rte *old)
/* RFC 4271 9.1.2.2. f) Compare BGP identifiers */
/* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighbor ID */
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID));
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID));
x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_ORIGINATOR_ID));
y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_ORIGINATOR_ID));
n = x ? x->u.data : new_bgp->remote_id;
o = y ? y->u.data : old_bgp->remote_id;
@ -2046,8 +2074,8 @@ bgp_rte_better(rte *new, rte *old)
return 0;
/* RFC 4456 9. b) Compare cluster list lengths */
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST));
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST));
x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_CLUSTER_LIST));
y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_CLUSTER_LIST));
n = x ? int_set_get_size(x->u.ptr) : 0;
o = y ? int_set_get_size(y->u.ptr) : 0;
if (n < o)
@ -2081,8 +2109,8 @@ bgp_rte_mergable(rte *pri, rte *sec)
return 0;
/* Start with local preferences */
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF));
y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF));
p = x ? x->u.data : pri_bgp->cf->default_local_pref;
s = y ? y->u.data : sec_bgp->cf->default_local_pref;
if (p != s)
@ -2091,8 +2119,8 @@ bgp_rte_mergable(rte *pri, rte *sec)
/* RFC 4271 9.1.2.2. a) Use AS path lengths */
if (pri_bgp->cf->compare_path_lengths || sec_bgp->cf->compare_path_lengths)
{
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_AS_PATH));
y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_AS_PATH));
p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
@ -2104,8 +2132,8 @@ bgp_rte_mergable(rte *pri, rte *sec)
}
/* RFC 4271 9.1.2.2. b) Use origins */
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_ORIGIN));
y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_ORIGIN));
p = x ? x->u.data : ORIGIN_INCOMPLETE;
s = y ? y->u.data : ORIGIN_INCOMPLETE;
if (p != s)
@ -2115,8 +2143,8 @@ bgp_rte_mergable(rte *pri, rte *sec)
if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric ||
(bgp_get_neighbor(pri) == bgp_get_neighbor(sec)))
{
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC));
y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC));
p = x ? x->u.data : pri_bgp->cf->default_med;
s = y ? y->u.data : sec_bgp->cf->default_med;
if (p != s)
@ -2281,7 +2309,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
rte *
bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
{
eattr *ea = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
eattr *ea = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY));
const struct adata *ad = ea ? ea->u.ptr : NULL;
uint flags = ea ? ea->flags : BAF_PARTIAL;
@ -2351,37 +2379,11 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
}
}
int
bgp_get_attr(const eattr *a, byte *buf, int buflen)
{
uint i = EA_ID(a->id);
const struct bgp_attr_desc *d;
int len;
if (bgp_attr_known(i))
{
d = &bgp_attr_table[i];
len = bsprintf(buf, "%s", d->name);
buf += len;
if (d->format)
{
*buf++ = ':';
*buf++ = ' ';
d->format(a, buf, buflen - len - 2);
return GA_FULL;
}
return GA_NAME;
}
bsprintf(buf, "%02x%s", i, (a->flags & BAF_TRANSITIVE) ? " [t]" : "");
return GA_NAME;
}
void
bgp_get_route_info(rte *e, byte *buf)
{
eattr *p = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
eattr *o = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
eattr *p = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_AS_PATH));
eattr *o = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_ORIGIN));
u32 origas;
buf += bsprintf(buf, " (%d", e->attrs->pref);

View File

@ -2579,7 +2579,6 @@ struct channel_class channel_bgp = {
struct protocol proto_bgp = {
.name = "BGP",
.template = "bgp%d",
.class = PROTOCOL_BGP,
.preference = DEF_PREF_BGP,
.channel_mask = NB_IP | NB_VPN | NB_FLOW,
.proto_size = sizeof(struct bgp_proto),
@ -2591,7 +2590,6 @@ struct protocol proto_bgp = {
.reconfigure = bgp_reconfigure,
.copy_config = bgp_copy_config,
.get_status = bgp_get_status,
.get_attr = bgp_get_attr,
.get_route_info = bgp_get_route_info,
.show_proto_info = bgp_show_proto_info
};
@ -2599,4 +2597,5 @@ struct protocol proto_bgp = {
void bgp_build(void)
{
proto_build(&proto_bgp);
bgp_register_attrs();
}

View File

@ -538,17 +538,13 @@ rta_resolvable(rta *a)
/* attrs.c */
static inline eattr *
bgp_find_attr(ea_list *attrs, uint code)
{
return ea_find(attrs, EA_CODE(PROTOCOL_BGP, code));
}
eattr *
bgp_find_attr(ea_list *attrs, uint code);
void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val);
void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *ad);
void bgp_set_attr_data(ea_list **to, uint code, uint flags, void *data, uint len);
#define bgp_unset_attr(to, code) ea_unset_attr(to, 0, code)
void bgp_unset_attr(ea_list **to, uint code);
int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
@ -573,7 +569,6 @@ struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old);
int bgp_preexport(struct channel *, struct rte *);
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *);
int bgp_total_aigp_metric_(rta *a, u64 *metric, const struct adata **ad);
@ -590,6 +585,8 @@ bgp_total_aigp_metric(rta *a)
return metric;
}
void bgp_register_attrs(void);
/* packets.c */
@ -626,26 +623,31 @@ void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to);
#define BAF_DECODE_FLAGS 0x0100 /* Private flag - attribute flags are handled by the decode hook */
#define BA_ORIGIN 0x01 /* RFC 4271 */ /* WM */
#define BA_AS_PATH 0x02 /* WM */
#define BA_NEXT_HOP 0x03 /* WM */
#define BA_MULTI_EXIT_DISC 0x04 /* ON */
#define BA_LOCAL_PREF 0x05 /* WD */
#define BA_ATOMIC_AGGR 0x06 /* WD */
#define BA_AGGREGATOR 0x07 /* OT */
#define BA_COMMUNITY 0x08 /* RFC 1997 */ /* OT */
#define BA_ORIGINATOR_ID 0x09 /* RFC 4456 */ /* ON */
#define BA_CLUSTER_LIST 0x0a /* RFC 4456 */ /* ON */
#define BA_MP_REACH_NLRI 0x0e /* RFC 4760 */
#define BA_MP_UNREACH_NLRI 0x0f /* RFC 4760 */
#define BA_EXT_COMMUNITY 0x10 /* RFC 4360 */
#define BA_AS4_PATH 0x11 /* RFC 6793 */
#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */
#define BA_AIGP 0x1a /* RFC 7311 */
#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */
enum bgp_attr_id {
BA_ORIGIN = 0x01, /* RFC 4271 */ /* WM */
BA_AS_PATH = 0x02, /* WM */
BA_NEXT_HOP = 0x03, /* WM */
BA_MULTI_EXIT_DISC = 0x04, /* ON */
BA_LOCAL_PREF = 0x05, /* WD */
BA_ATOMIC_AGGR = 0x06, /* WD */
BA_AGGREGATOR = 0x07, /* OT */
BA_COMMUNITY = 0x08, /* RFC 1997 */ /* OT */
BA_ORIGINATOR_ID = 0x09, /* RFC 4456 */ /* ON */
BA_CLUSTER_LIST = 0x0a, /* RFC 4456 */ /* ON */
BA_MP_REACH_NLRI = 0x0e, /* RFC 4760 */
BA_MP_UNREACH_NLRI = 0x0f, /* RFC 4760 */
BA_EXT_COMMUNITY = 0x10, /* RFC 4360 */
BA_AS4_PATH = 0x11, /* RFC 6793 */
BA_AS4_AGGREGATOR = 0x12, /* RFC 6793 */
BA_AIGP = 0x1a, /* RFC 7311 */
BA_LARGE_COMMUNITY = 0x20, /* RFC 8092 */
/* Bird's private internal BGP attributes */
#define BA_MPLS_LABEL_STACK 0xfe /* MPLS label stack transfer attribute */
BA_MPLS_LABEL_STACK = 0x100, /* MPLS label stack transfer attribute */
/* Maximum */
BGP_ATTR_MAX,
};
/* BGP connection states */

View File

@ -316,36 +316,6 @@ bgp_channel_end:
bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end;
dynamic_attr: BGP_ORIGIN
{ $$ = f_new_dynamic_attr(T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ;
dynamic_attr: BGP_PATH
{ $$ = f_new_dynamic_attr(T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ;
dynamic_attr: BGP_NEXT_HOP
{ $$ = f_new_dynamic_attr(T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ;
dynamic_attr: BGP_MED
{ $$ = f_new_dynamic_attr(T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ;
dynamic_attr: BGP_LOCAL_PREF
{ $$ = f_new_dynamic_attr(T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ;
dynamic_attr: BGP_ATOMIC_AGGR
{ $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ;
dynamic_attr: BGP_AGGREGATOR
{ $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
dynamic_attr: BGP_COMMUNITY
{ $$ = f_new_dynamic_attr(T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ;
dynamic_attr: BGP_ORIGINATOR_ID
{ $$ = f_new_dynamic_attr(T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ;
dynamic_attr: BGP_CLUSTER_LIST
{ $$ = f_new_dynamic_attr(T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ;
dynamic_attr: BGP_EXT_COMMUNITY
{ $$ = f_new_dynamic_attr(T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ;
dynamic_attr: BGP_AIGP
{ $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ;
dynamic_attr: BGP_LARGE_COMMUNITY
{ $$ = f_new_dynamic_attr(T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)
CF_CODE

View File

@ -904,7 +904,6 @@ mrt_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSE
struct protocol proto_mrt = {
.name = "MRT",
.template = "mrt%d",
.class = PROTOCOL_MRT,
.proto_size = sizeof(struct mrt_proto),
.config_size = sizeof(struct mrt_config),
.init = mrt_init,

View File

@ -505,11 +505,6 @@ ospf_iface:
ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
;
dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_METRIC1); } ;
dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_METRIC2); } ;
dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_TAG); } ;
dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(T_QUAD, EA_OSPF_ROUTER_ID); } ;
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optproto, [<name>], [[Show information about OSPF protocol]])
{ PROTO_WALK_CMD($3, &proto_ospf, p) ospf_sh(p); };

View File

@ -106,6 +106,7 @@
#include <stdlib.h>
#include "ospf.h"
#include "lib/macro.h"
static int ospf_preexport(struct channel *C, rte *new);
static void ospf_reload_routes(struct channel *C);
@ -386,7 +387,7 @@ ospf_init(struct proto_config *CF)
static int
ospf_rte_better(struct rte *new, struct rte *old)
{
u32 new_metric1 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
u32 new_metric1 = ea_get_int(new->attrs->eattrs, &ea_ospf_metric1, LSINFINITY);
if (new_metric1 == LSINFINITY)
return 0;
@ -396,13 +397,13 @@ ospf_rte_better(struct rte *new, struct rte *old)
if(new->attrs->source == RTS_OSPF_EXT2)
{
u32 old_metric2 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY);
u32 new_metric2 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY);
u32 old_metric2 = ea_get_int(old->attrs->eattrs, &ea_ospf_metric2, LSINFINITY);
u32 new_metric2 = ea_get_int(new->attrs->eattrs, &ea_ospf_metric2, LSINFINITY);
if(new_metric2 < old_metric2) return 1;
if(new_metric2 > old_metric2) return 0;
}
u32 old_metric1 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
u32 old_metric1 = ea_get_int(old->attrs->eattrs, &ea_ospf_metric1, LSINFINITY);
if (new_metric1 < old_metric1)
return 1;
@ -415,7 +416,7 @@ ospf_rte_igp_metric(struct rte *rt)
if (rt->attrs->source == RTS_OSPF_EXT2)
return IGP_METRIC_UNKNOWN;
return ea_get_int(rt->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
return ea_get_int(rt->attrs->eattrs, &ea_ospf_metric1, LSINFINITY);
}
void
@ -587,42 +588,26 @@ ospf_get_route_info(rte * rte, byte * buf)
}
buf += bsprintf(buf, " %s", type);
buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY));
buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, &ea_ospf_metric1, LSINFINITY));
if (rte->attrs->source == RTS_OSPF_EXT2)
buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY));
buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, &ea_ospf_metric2, LSINFINITY));
buf += bsprintf(buf, ")");
if (rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2)
{
eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_TAG);
eattr *ea = ea_find(rte->attrs->eattrs, &ea_ospf_tag);
if (ea && (ea->u.data > 0))
buf += bsprintf(buf, " [%x]", ea->u.data);
}
eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_ROUTER_ID);
eattr *ea = ea_find(rte->attrs->eattrs, &ea_ospf_router_id);
if (ea)
buf += bsprintf(buf, " [%R]", ea->u.data);
}
static int
ospf_get_attr(const eattr * a, byte * buf, int buflen UNUSED)
static void
ospf_tag_format(const eattr * a, byte * buf, uint buflen)
{
switch (a->id)
{
case EA_OSPF_METRIC1:
bsprintf(buf, "metric1");
return GA_NAME;
case EA_OSPF_METRIC2:
bsprintf(buf, "metric2");
return GA_NAME;
case EA_OSPF_TAG:
bsprintf(buf, "tag: 0x%08x", a->u.data);
return GA_FULL;
case EA_OSPF_ROUTER_ID:
bsprintf(buf, "router_id");
return GA_NAME;
default:
return GA_UNKNOWN;
}
bsnprintf(buf, buflen, "0x%08x", a->u.data);
}
static void
@ -1520,7 +1505,6 @@ ospf_sh_lsadb(struct lsadb_show_data *ld)
struct protocol proto_ospf = {
.name = "OSPF",
.template = "ospf%d",
.class = PROTOCOL_OSPF,
.preference = DEF_PREF_OSPF,
.channel_mask = NB_IP,
.proto_size = sizeof(struct ospf_proto),
@ -1531,12 +1515,39 @@ struct protocol proto_ospf = {
.shutdown = ospf_shutdown,
.reconfigure = ospf_reconfigure,
.get_status = ospf_get_status,
.get_attr = ospf_get_attr,
.get_route_info = ospf_get_route_info
};
struct ea_class ea_ospf_metric1 = {
.name = "ospf_metric1",
.type = T_INT,
};
struct ea_class ea_ospf_metric2 = {
.name = "ospf_metric2",
.type = T_INT,
};
struct ea_class ea_ospf_tag = {
.name = "ospf_tag",
.type = T_INT,
.format = ospf_tag_format,
};
struct ea_class ea_ospf_router_id = {
.name = "ospf_router_id",
.type = T_QUAD,
};
void
ospf_build(void)
{
proto_build(&proto_ospf);
EA_REGISTER_ALL(
&ea_ospf_metric1,
&ea_ospf_metric2,
&ea_ospf_tag,
&ea_ospf_router_id
);
}

View File

@ -939,12 +939,7 @@ struct lsadb_show_data {
u32 router; /* Advertising router, 0 -> all */
};
#define EA_OSPF_METRIC1 EA_CODE(PROTOCOL_OSPF, 0)
#define EA_OSPF_METRIC2 EA_CODE(PROTOCOL_OSPF, 1)
#define EA_OSPF_TAG EA_CODE(PROTOCOL_OSPF, 2)
#define EA_OSPF_ROUTER_ID EA_CODE(PROTOCOL_OSPF, 3)
extern struct ea_class ea_ospf_metric1, ea_ospf_metric2, ea_ospf_tag, ea_ospf_router_id;
/*
* For regular networks, neighbor address must match network prefix.

View File

@ -2075,18 +2075,18 @@ again1:
eattrs.l = (ea_list) {};
eattrs.a[eattrs.l.count++] =
EA_LITERAL_EMBEDDED(EA_OSPF_METRIC1, T_INT, 0, nf->n.metric1);
EA_LITERAL_EMBEDDED(&ea_ospf_metric1, 0, nf->n.metric1);
if (nf->n.type == RTS_OSPF_EXT2)
eattrs.a[eattrs.l.count++] =
EA_LITERAL_EMBEDDED(EA_OSPF_METRIC2, T_INT, 0, nf->n.metric2);
EA_LITERAL_EMBEDDED(&ea_ospf_metric2, 0, nf->n.metric2);
if ((nf->n.type == RTS_OSPF_EXT1) || (nf->n.type == RTS_OSPF_EXT2))
eattrs.a[eattrs.l.count++] =
EA_LITERAL_EMBEDDED(EA_OSPF_TAG, T_INT, 0, nf->n.tag);
EA_LITERAL_EMBEDDED(&ea_ospf_tag, 0, nf->n.tag);
eattrs.a[eattrs.l.count++] =
EA_LITERAL_EMBEDDED(EA_OSPF_ROUTER_ID, T_QUAD, 0, nf->n.rid);
EA_LITERAL_EMBEDDED(&ea_ospf_router_id, 0, nf->n.rid);
a0.eattrs = &eattrs.l;

View File

@ -1338,8 +1338,8 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rt
/* Get route attributes */
rta *a = new->attrs;
eattr *m1a = ea_find(a->eattrs, EA_OSPF_METRIC1);
eattr *m2a = ea_find(a->eattrs, EA_OSPF_METRIC2);
eattr *m1a = ea_find(a->eattrs, &ea_ospf_metric1);
eattr *m2a = ea_find(a->eattrs, &ea_ospf_metric2);
uint m1 = m1a ? m1a->u.data : 0;
uint m2 = m2a ? m2a->u.data : 10000;
@ -1363,7 +1363,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rt
uint ebit = m2a || !m1a;
uint metric = ebit ? m2 : m1;
uint tag = ea_get_int(a->eattrs, EA_OSPF_TAG, 0);
uint tag = ea_get_int(a->eattrs, &ea_ospf_tag, 0);
ip_addr fwd = IPA_NONE;
if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface))

View File

@ -305,7 +305,6 @@ perf_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUS
struct protocol proto_perf = {
.name = "Perf",
.template = "perf%d",
.class = PROTOCOL_PERF,
.channel_mask = NB_IP,
.proto_size = sizeof(struct perf_proto),
.config_size = sizeof(struct perf_config),

View File

@ -299,7 +299,6 @@ pipe_update_debug(struct proto *P)
struct protocol proto_pipe = {
.name = "Pipe",
.template = "pipe%d",
.class = PROTOCOL_PIPE,
.proto_size = sizeof(struct pipe_proto),
.config_size = sizeof(struct pipe_config),
.postconfig = pipe_postconfig,

View File

@ -336,9 +336,6 @@ radv_sensitive:
| SENSITIVE bool { $$ = $2; }
;
dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ;
dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(T_INT, EA_RA_LIFETIME); } ;
CF_CODE
CF_END

View File

@ -10,6 +10,7 @@
#include <stdlib.h>
#include "radv.h"
#include "lib/macro.h"
/**
* DOC: Router Advertisements
@ -42,6 +43,8 @@
* RFC 6106 - DNS extensions (RDDNS, DNSSL)
*/
static struct ea_class ea_radv_preference, ea_radv_lifetime;
static void radv_prune_prefixes(struct radv_iface *ifa);
static void radv_prune_routes(struct radv_proto *p);
@ -444,11 +447,11 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rt
{
/* Update */
ea = ea_find(new->attrs->eattrs, EA_RA_PREFERENCE);
ea = ea_find(new->attrs->eattrs, &ea_radv_preference);
uint preference = ea ? ea->u.data : RA_PREF_MEDIUM;
uint preference_set = !!ea;
ea = ea_find(new->attrs->eattrs, EA_RA_LIFETIME);
ea = ea_find(new->attrs->eattrs, &ea_radv_lifetime);
uint lifetime = ea ? ea->u.data : 0;
uint lifetime_set = !!ea;
@ -738,27 +741,26 @@ radv_pref_str(u32 pref)
}
}
/* The buffer has some minimal size */
static int
radv_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
static void
radv_preference_format(const eattr *a, byte *buf, uint buflen)
{
switch (a->id)
{
case EA_RA_PREFERENCE:
bsprintf(buf, "preference: %s", radv_pref_str(a->u.data));
return GA_FULL;
case EA_RA_LIFETIME:
bsprintf(buf, "lifetime");
return GA_NAME;
default:
return GA_UNKNOWN;
}
bsnprintf(buf, buflen, "%s", radv_pref_str(a->u.data));
}
static struct ea_class ea_radv_preference = {
.name = "radv_preference",
.type = T_ENUM_RA_PREFERENCE,
.format = radv_preference_format,
};
static struct ea_class ea_radv_lifetime = {
.name = "radv_lifetime",
.type = T_INT,
};
struct protocol proto_radv = {
.name = "RAdv",
.template = "radv%d",
.class = PROTOCOL_RADV,
.channel_mask = NB_IP6,
.proto_size = sizeof(struct radv_proto),
.config_size = sizeof(struct radv_config),
@ -769,11 +771,15 @@ struct protocol proto_radv = {
.reconfigure = radv_reconfigure,
.copy_config = radv_copy_config,
.get_status = radv_get_status,
.get_attr = radv_get_attr
};
void
radv_build(void)
{
proto_build(&proto_radv);
EA_REGISTER_ALL(
&ea_radv_preference,
&ea_radv_lifetime
);
}

View File

@ -195,10 +195,6 @@ struct radv_iface
#define RA_PREF_HIGH 0x08
#define RA_PREF_MASK 0x18
/* Attributes */
#define EA_RA_PREFERENCE EA_CODE(PROTOCOL_RADV, 0)
#define EA_RA_LIFETIME EA_CODE(PROTOCOL_RADV, 1)
#ifdef LOCAL_DEBUG
#define RADV_FORCE_DEBUG 1
#else

View File

@ -190,9 +190,6 @@ rip_iface:
rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish;
dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_RIP_METRIC); } ;
dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(T_INT, EA_RIP_TAG); } ;
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
CF_CLI(SHOW RIP INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])

View File

@ -78,6 +78,7 @@
#include <stdlib.h>
#include "rip.h"
#include "lib/macro.h"
static inline void rip_lock_neighbor(struct rip_neighbor *n);
@ -88,6 +89,7 @@ static inline void rip_iface_kick_timer(struct rip_iface *ifa);
static void rip_iface_timer(timer *timer);
static void rip_trigger_update(struct rip_proto *p);
static struct ea_class ea_rip_metric, ea_rip_tag, ea_rip_from;
/*
* RIP routes
@ -200,9 +202,9 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
} ea_block = {
.l.count = 3,
.a = {
EA_LITERAL_EMBEDDED(EA_RIP_METRIC, T_INT, 0, rt_metric),
EA_LITERAL_EMBEDDED(EA_RIP_TAG, T_INT, 0, rt_tag),
EA_LITERAL_DIRECT_ADATA(EA_RIP_FROM, T_IFACE, 0, &ea_block.riad.ad),
EA_LITERAL_EMBEDDED(&ea_rip_metric, 0, rt_metric),
EA_LITERAL_EMBEDDED(&ea_rip_tag, 0, rt_tag),
EA_LITERAL_DIRECT_ADATA(&ea_rip_from, 0, &ea_block.riad.ad),
},
.riad = {
.ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) },
@ -325,9 +327,9 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, s
if (new)
{
/* Update */
u32 rt_tag = ea_get_int(new->attrs->eattrs, EA_RIP_TAG, 0);
u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1);
const eattr *rie = ea_find(new->attrs->eattrs, EA_RIP_FROM);
u32 rt_tag = ea_get_int(new->attrs->eattrs, &ea_rip_tag, 0);
u32 rt_metric = ea_get_int(new->attrs->eattrs, &ea_rip_metric, 1);
const eattr *rie = ea_find(new->attrs->eattrs, &ea_rip_from);
struct iface *rt_from = rie ? ((struct rip_iface_adata *) rie->u.ptr)->iface : NULL;
if (rt_metric > p->infinity)
@ -1094,8 +1096,8 @@ rip_rte_better(struct rte *new, struct rte *old)
ASSERT_DIE(new->src == old->src);
struct rip_proto *p = (struct rip_proto *) new->src->proto;
u32 new_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, p->infinity);
u32 old_metric = ea_get_int(old->attrs->eattrs, EA_RIP_METRIC, p->infinity);
u32 new_metric = ea_get_int(new->attrs->eattrs, &ea_rip_metric, p->infinity);
u32 old_metric = ea_get_int(old->attrs->eattrs, &ea_rip_metric, p->infinity);
return new_metric < old_metric;
}
@ -1103,7 +1105,7 @@ rip_rte_better(struct rte *new, struct rte *old)
static u32
rip_rte_igp_metric(struct rte *rt)
{
return ea_get_int(rt->attrs->eattrs, EA_RIP_METRIC, IGP_METRIC_UNKNOWN);
return ea_get_int(rt->attrs->eattrs, &ea_rip_metric, IGP_METRIC_UNKNOWN);
}
static void
@ -1204,8 +1206,8 @@ static void
rip_get_route_info(rte *rte, byte *buf)
{
struct rip_proto *p = (struct rip_proto *) rte->src->proto;
u32 rt_metric = ea_get_int(rte->attrs->eattrs, EA_RIP_METRIC, p->infinity);
u32 rt_tag = ea_get_int(rte->attrs->eattrs, EA_RIP_TAG, 0);
u32 rt_metric = ea_get_int(rte->attrs->eattrs, &ea_rip_metric, p->infinity);
u32 rt_tag = ea_get_int(rte->attrs->eattrs, &ea_rip_tag, 0);
buf += bsprintf(buf, " (%d/%d)", rte->attrs->pref, rt_metric);
@ -1213,24 +1215,29 @@ rip_get_route_info(rte *rte, byte *buf)
bsprintf(buf, " [%04x]", rt_tag);
}
static int
rip_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
static void
rip_tag_format(const eattr *a, byte *buf, uint buflen)
{
switch (a->id)
{
case EA_RIP_METRIC:
bsprintf(buf, "metric: %d", a->u.data);
return GA_FULL;
case EA_RIP_TAG:
bsprintf(buf, "tag: %04x", a->u.data);
return GA_FULL;
default:
return GA_UNKNOWN;
}
bsnprintf(buf, buflen, "tag: %04x", a->u.data);
}
static struct ea_class ea_rip_metric = {
.name = "rip_metric",
.type = T_INT,
};
static struct ea_class ea_rip_tag = {
.name = "rip_tag",
.type = T_INT,
.format = rip_tag_format,
};
static struct ea_class ea_rip_from = {
.name = "rip_from",
.type = T_IFACE,
.readonly = 1,
};
void
rip_show_interfaces(struct proto *P, const char *iff)
{
@ -1333,7 +1340,6 @@ rip_dump(struct proto *P)
struct protocol proto_rip = {
.name = "RIP",
.template = "rip%d",
.class = PROTOCOL_RIP,
.preference = DEF_PREF_RIP,
.channel_mask = NB_IP,
.proto_size = sizeof(struct rip_proto),
@ -1345,11 +1351,16 @@ struct protocol proto_rip = {
.shutdown = rip_shutdown,
.reconfigure = rip_reconfigure,
.get_route_info = rip_get_route_info,
.get_attr = rip_get_attr
};
void
rip_build(void)
{
proto_build(&proto_rip);
EA_REGISTER_ALL(
&ea_rip_metric,
&ea_rip_tag,
&ea_rip_from
);
}

View File

@ -195,10 +195,6 @@ struct rip_rte
#define RIP_ENTRY_VALID 1 /* Valid outgoing route */
#define RIP_ENTRY_STALE 2 /* Stale outgoing route, waiting for GC */
#define EA_RIP_METRIC EA_CODE(PROTOCOL_RIP, 0)
#define EA_RIP_TAG EA_CODE(PROTOCOL_RIP, 1)
#define EA_RIP_FROM EA_CODE(PROTOCOL_RIP, 2)
static inline int rip_is_v2(struct rip_proto *p)
{ return p->rip2; }

View File

@ -952,7 +952,6 @@ rpki_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUS
struct protocol proto_rpki = {
.name = "RPKI",
.template = "rpki%d",
.class = PROTOCOL_RPKI,
.preference = DEF_PREF_RPKI,
.proto_size = sizeof(struct rpki_proto),
.config_size = sizeof(struct rpki_config),

View File

@ -397,16 +397,16 @@ static_reload_routes(struct channel *C)
static int
static_rte_better(rte *new, rte *old)
{
u32 n = ea_get_int(new->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
u32 o = ea_get_int(old->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
u32 n = ea_get_int(new->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN);
u32 o = ea_get_int(old->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN);
return n < o;
}
static int
static_rte_mergable(rte *pri, rte *sec)
{
u32 a = ea_get_int(pri->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
u32 b = ea_get_int(sec->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
u32 a = ea_get_int(pri->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN);
u32 b = ea_get_int(sec->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN);
return a == b;
}
@ -694,7 +694,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
static void
static_get_route_info(rte *rte, byte *buf)
{
eattr *a = ea_find(rte->attrs->eattrs, EA_GEN_IGP_METRIC);
eattr *a = ea_find(rte->attrs->eattrs, &ea_gen_igp_metric);
if (a)
buf += bsprintf(buf, " (%d/%u)", rte->attrs->pref, a->u.data);
else
@ -752,7 +752,6 @@ static_show(struct proto *P)
struct protocol proto_static = {
.name = "Static",
.template = "static%d",
.class = PROTOCOL_STATIC,
.preference = DEF_PREF_STATIC,
.channel_mask = NB_ANY,
.proto_size = sizeof(struct static_proto),

View File

@ -34,38 +34,6 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
#define KRT_ALLOW_MERGE_PATHS 1
#define EA_KRT_PREFSRC EA_CODE(PROTOCOL_KERNEL, 0x10)
#define EA_KRT_REALM EA_CODE(PROTOCOL_KERNEL, 0x11)
#define EA_KRT_SCOPE EA_CODE(PROTOCOL_KERNEL, 0x12)
#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(PROTOCOL_KERNEL, 0x20) /* Dummy one */
#define EA_KRT_LOCK EA_CODE(PROTOCOL_KERNEL, 0x21)
#define EA_KRT_MTU EA_CODE(PROTOCOL_KERNEL, 0x22)
#define EA_KRT_WINDOW EA_CODE(PROTOCOL_KERNEL, 0x23)
#define EA_KRT_RTT EA_CODE(PROTOCOL_KERNEL, 0x24)
#define EA_KRT_RTTVAR EA_CODE(PROTOCOL_KERNEL, 0x25)
#define EA_KRT_SSTRESH EA_CODE(PROTOCOL_KERNEL, 0x26)
#define EA_KRT_CWND EA_CODE(PROTOCOL_KERNEL, 0x27)
#define EA_KRT_ADVMSS EA_CODE(PROTOCOL_KERNEL, 0x28)
#define EA_KRT_REORDERING EA_CODE(PROTOCOL_KERNEL, 0x29)
#define EA_KRT_HOPLIMIT EA_CODE(PROTOCOL_KERNEL, 0x2a)
#define EA_KRT_INITCWND EA_CODE(PROTOCOL_KERNEL, 0x2b)
#define EA_KRT_FEATURES EA_CODE(PROTOCOL_KERNEL, 0x2c)
#define EA_KRT_RTO_MIN EA_CODE(PROTOCOL_KERNEL, 0x2d)
#define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e)
#define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f)
struct krt_params {
u32 table_id; /* Kernel table ID we sync with */
u32 metric; /* Kernel metric used for all routes */

View File

@ -28,39 +28,22 @@ kern_sys_item:
| NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; }
;
dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(T_IP, EA_KRT_PREFSRC); } ;
dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REALM); } ;
dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SCOPE); } ;
dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(T_INT, EA_KRT_MTU); } ;
dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(T_INT, EA_KRT_WINDOW); } ;
dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTT); } ;
dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTTVAR); } ;
dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SSTRESH); } ;
dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_CWND); } ;
dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(T_INT, EA_KRT_ADVMSS); } ;
dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REORDERING); } ;
dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_HOPLIMIT); } ;
dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITCWND); } ;
dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTO_MIN); } ;
dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITRWND); } ;
dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(T_INT, EA_KRT_QUICKACK); } ;
/* Bits of EA_KRT_LOCK, based on RTAX_* constants */
attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, EA_KRT_LOCK); } ;
attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, "krt_lock"); } ;
attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, "krt_lock"); } ;
attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, "krt_lock"); } ;
attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, "krt_lock"); } ;
attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, "krt_lock"); } ;
attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, "krt_lock"); } ;
attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, "krt_lock"); } ;
attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, "krt_lock"); } ;
attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, "krt_lock"); } ;
attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ;
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, EA_KRT_FEATURES); } ;
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, EA_KRT_FEATURES); } ;
/* Bits of EA_KRT_FEATURES */
attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ;
attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ;
CF_CODE

View File

@ -26,6 +26,7 @@
#include "lib/socket.h"
#include "lib/string.h"
#include "lib/hash.h"
#include "lib/macro.h"
#include "conf/conf.h"
#include <asm/types.h>
@ -121,6 +122,101 @@ struct nl_parse_state
u32 rta_flow; /* Used during parsing */
};
/*
* Netlink eattr definitions
*/
#define KRT_METRICS_MAX ARRAY_SIZE(ea_krt_metrics)
#define KRT_FEATURES_MAX 4
static void krt_bitfield_format(const eattr *e, byte *buf, uint buflen);
static struct ea_class
ea_krt_prefsrc = {
.name = "krt_prefsrc",
.type = T_IP,
},
ea_krt_realm = {
.name = "krt_realm",
.type = T_INT,
},
ea_krt_scope = {
.name = "krt_scope",
.type = T_INT,
};
static struct ea_class ea_krt_metrics[] = {
[RTAX_LOCK] = {
.name = "krt_lock",
.type = T_INT,
.format = krt_bitfield_format,
},
[RTAX_FEATURES] = {
.name = "krt_features",
.type = T_INT,
.format = krt_bitfield_format,
},
#define KRT_METRIC_INT(_rtax, _name) [_rtax] = { .name = _name, .type = T_INT }
KRT_METRIC_INT(RTAX_MTU, "krt_mtu"),
KRT_METRIC_INT(RTAX_WINDOW, "krt_window"),
KRT_METRIC_INT(RTAX_RTT, "krt_rtt"),
KRT_METRIC_INT(RTAX_RTTVAR, "krt_rttvar"),
KRT_METRIC_INT(RTAX_SSTHRESH, "krt_sstresh"),
KRT_METRIC_INT(RTAX_CWND, "krt_cwnd"),
KRT_METRIC_INT(RTAX_ADVMSS, "krt_advmss"),
KRT_METRIC_INT(RTAX_REORDERING, "krt_reordering"),
KRT_METRIC_INT(RTAX_HOPLIMIT, "krt_hoplimit"),
KRT_METRIC_INT(RTAX_INITCWND, "krt_initcwnd"),
KRT_METRIC_INT(RTAX_RTO_MIN, "krt_rto_min"),
KRT_METRIC_INT(RTAX_INITRWND, "krt_initrwnd"),
KRT_METRIC_INT(RTAX_QUICKACK, "krt_quickack"),
#undef KRT_METRIC_INT
};
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"
};
static void
krt_bitfield_format(const eattr *a, byte *buf, uint buflen)
{
if (a->id == ea_krt_metrics[RTAX_LOCK].id)
ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
else if (a->id == ea_krt_metrics[RTAX_FEATURES].id)
ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
}
static void
nl_ea_register(void)
{
EA_REGISTER_ALL(
&ea_krt_prefsrc,
&ea_krt_realm,
&ea_krt_scope
);
for (uint i = 0; i < KRT_METRICS_MAX; i++)
{
if (!ea_krt_metrics[i].name)
ea_krt_metrics[i] = (struct ea_class) {
.name = mb_sprintf(&root_pool, "krt_metric_%d", i),
.type = T_INT,
};
ea_register_init(&ea_krt_metrics[i]);
}
for (uint i = 1; i < KRT_METRICS_MAX; i++)
ASSERT_DIE(ea_krt_metrics[i].id == ea_krt_metrics[0].id + i);
}
/*
* Synchronous Netlink interface
*/
@ -734,7 +830,7 @@ static void
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs)
{
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
eattr *flow = ea_find(eattrs, EA_KRT_REALM);
eattr *flow = ea_find(eattrs, &ea_krt_realm);
for (; nh; nh = nh->next)
{
@ -1398,7 +1494,7 @@ nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nextho
priority = 0;
else if (KRT_CF->sys.metric)
priority = KRT_CF->sys.metric;
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC)))
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, &ea_krt_metric)))
priority = ea->u.data;
if (priority)
@ -1411,15 +1507,15 @@ nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nextho
/* Default scope is LINK for device routes, UNIVERSE otherwise */
if (p->af == AF_MPLS)
r->r.rtm_scope = RT_SCOPE_UNIVERSE;
else if (ea = ea_find(eattrs, EA_KRT_SCOPE))
else if (ea = ea_find(eattrs, &ea_krt_scope))
r->r.rtm_scope = ea->u.data;
else
r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
if (ea = ea_find(eattrs, &ea_krt_prefsrc))
nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
if (ea = ea_find(eattrs, EA_KRT_REALM))
if (ea = ea_find(eattrs, &ea_krt_realm))
nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
@ -1427,9 +1523,9 @@ nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nextho
metrics[0] = 0;
struct ea_walk_state ews = { .eattrs = eattrs };
while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
while (ea = ea_walk(&ews, ea_krt_metrics[0].id, KRT_METRICS_MAX))
{
int id = ea->id - EA_KRT_METRICS;
int id = ea->id - ea_krt_metrics[0].id;
metrics[0] |= 1 << id;
metrics[id] = ea->u.data;
}
@ -1582,21 +1678,15 @@ nl_announce_route(struct nl_parse_state *s)
.net = s->net,
};
EA_LOCAL_LIST(2) ea0 = {
EA_LOCAL_LIST(2) ea = {
.l = { .count = 2, .next = e0.attrs->eattrs },
.a[0] = (eattr) {
.id = EA_KRT_SOURCE,
.type = T_INT,
.u.data = s->krt_proto,
},
.a[1] = (eattr) {
.id = EA_KRT_METRIC,
.type = T_INT,
.u.data = s->krt_metric,
.a = {
EA_LITERAL_EMBEDDED(&ea_krt_source, 0, s->krt_proto),
EA_LITERAL_EMBEDDED(&ea_krt_metric, 0, s->krt_metric),
},
};
e0.attrs->eattrs = &ea0.l;
e0.attrs->eattrs = &ea.l;
if (s->scan)
krt_got_route(s->proto, &e0, s->krt_src);
@ -1865,20 +1955,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (i->rtm_scope != def_scope)
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(EA_KRT_SCOPE, T_INT, 0, i->rtm_scope));
EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
if (a[RTA_PREFSRC])
{
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
{
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
ea_set_attr(&ra->eattrs,
EA_LITERAL_STORE_ADATA(EA_KRT_PREFSRC, T_IP, 0, &ps, sizeof(ps)));
}
ea_set_attr(&ra->eattrs,
EA_LITERAL_STORE_ADATA(&ea_krt_prefsrc, 0, &ps, sizeof(ps)));
}
/* Can be set per-route or per-nexthop */
if (s->rta_flow)
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(EA_KRT_REALM, T_INT, 0, s->rta_flow));
EA_LITERAL_EMBEDDED(&ea_krt_realm, 0, s->rta_flow));
if (a[RTA_METRICS])
{
@ -1889,11 +1979,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return;
}
for (int t = 1; t < KRT_METRICS_MAX; t++)
for (uint t = 1; t < KRT_METRICS_MAX; t++)
if (metrics[0] & (1 << t))
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t),
T_INT, 0, metrics[t]));
EA_LITERAL_EMBEDDED(&ea_krt_metrics[t], 0, metrics[t]));
}
/*
@ -2133,6 +2222,8 @@ krt_sys_io_init(void)
{
nl_linpool = lp_new_default(krt_pool);
HASH_INIT(nl_table_map, krt_pool, 6);
nl_ea_register();
}
int
@ -2186,56 +2277,6 @@ krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
d->sys.metric = s->sys.metric;
}
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(const 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_SCOPE:
bsprintf(buf, "scope");
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
kif_sys_start(struct kif_proto *p UNUSED)
{

View File

@ -122,9 +122,6 @@ kif_iface:
kif_iface_start iface_patt_list_nopx kif_iface_opt_list;
dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SOURCE); } ;
dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_KRT_METRIC); } ;
CF_CODE
CF_END

View File

@ -232,7 +232,6 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src)
struct protocol proto_unix_iface = {
.name = "Device",
.template = "device%d",
.class = PROTOCOL_DEVICE,
.proto_size = sizeof(struct kif_proto),
.config_size = sizeof(struct kif_config),
.preconfig = kif_preconfig,
@ -287,7 +286,7 @@ static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
static inline u32
krt_metric(rte *a)
{
eattr *ea = ea_find(a->attrs->eattrs, EA_KRT_METRIC);
eattr *ea = ea_find(a->attrs->eattrs, &ea_krt_metric);
return ea ? ea->u.data : 0;
}
@ -1142,24 +1141,15 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
krt_sys_copy_config(d, s);
}
static int
krt_get_attr(const eattr *a, byte *buf, int buflen)
{
switch (a->id)
{
case EA_KRT_SOURCE:
bsprintf(buf, "source");
return GA_NAME;
case EA_KRT_METRIC:
bsprintf(buf, "metric");
return GA_NAME;
default:
return krt_sys_get_attr(a, buf, buflen);
}
}
struct ea_class ea_krt_source = {
.name = "krt_source",
.type = T_INT,
};
struct ea_class ea_krt_metric = {
.name = "krt_metric",
.type = T_INT,
};
#ifdef CONFIG_IP6_SADR_KERNEL
#define MAYBE_IP6_SADR NB_IP6_SADR
@ -1176,7 +1166,6 @@ krt_get_attr(const eattr *a, byte *buf, int buflen)
struct protocol proto_unix_kernel = {
.name = "Kernel",
.template = "kernel%d",
.class = PROTOCOL_KERNEL,
.preference = DEF_PREF_INHERITED,
.channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
.proto_size = sizeof(struct krt_proto),
@ -1188,7 +1177,6 @@ struct protocol proto_unix_kernel = {
.shutdown = krt_shutdown,
.reconfigure = krt_reconfigure,
.copy_config = krt_copy_config,
.get_attr = krt_get_attr,
#ifdef KRT_ALLOW_LEARN
.dump = krt_dump,
#endif
@ -1198,4 +1186,9 @@ void
krt_build(void)
{
proto_build(&proto_unix_kernel);
EA_REGISTER_ALL(
&ea_krt_source,
&ea_krt_metric,
);
}

View File

@ -21,8 +21,12 @@ struct kif_proto;
#define KRT_DEFAULT_ECMP_LIMIT 16
#if 0
#define EA_KRT_SOURCE EA_CODE(PROTOCOL_KERNEL, 0)
#define EA_KRT_METRIC EA_CODE(PROTOCOL_KERNEL, 1)
#endif
extern struct ea_class ea_krt_source, ea_krt_metric;
#define KRT_REF_SEEN 0x1 /* Seen in table */
#define KRT_REF_BEST 0x2 /* Best in table */

View File

@ -881,8 +881,8 @@ main(int argc, char **argv)
resource_init();
timer_init();
olock_init();
io_init();
rt_init();
io_init();
if_init();
// roa_init();
config_init();

View File

@ -62,8 +62,8 @@ bt_bird_init(void)
olock_init();
timer_init();
io_init();
rt_init();
io_init();
if_init();
config_init();
@ -72,9 +72,6 @@ bt_bird_init(void)
void bt_bird_cleanup(void)
{
for (int i = 0; i < PROTOCOL__MAX; i++)
class_to_protocol[i] = NULL;
config = new_config = NULL;
}