Add bitfield route attribute type
This commit is contained in:
parent
77edab6409
commit
315f23a047
3 changed files with 90 additions and 26 deletions
|
@ -462,7 +462,7 @@ static int f_flags;
|
|||
|
||||
static inline void f_rte_cow(void)
|
||||
{
|
||||
*f_rte = rte_cow(*f_rte);
|
||||
*f_rte = rte_cow(*f_rte);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -479,7 +479,7 @@ f_rta_cow(void)
|
|||
/* Store old rta to free it later */
|
||||
f_old_rta = (*f_rte)->attrs;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Alloc new rta, do shallow copy and update rte. Fields eattrs
|
||||
* and nexthops of rta are shared with f_old_rta (they will be
|
||||
* copied when the cached rta will be obtained at the end of
|
||||
|
@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
|||
#define ACCESS_RTE \
|
||||
do { if (!f_rte) runtime("No route to access"); } while (0)
|
||||
|
||||
#define BITFIELD_MASK(what) \
|
||||
(1u << (what->a2.i >> 24))
|
||||
|
||||
/**
|
||||
* interpret
|
||||
* @what: filter to interpret
|
||||
|
@ -526,7 +529,7 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
|||
* Each instruction has 4 fields: code (which is instruction code),
|
||||
* aux (which is extension to instruction code, typically type),
|
||||
* arg1 and arg2 - arguments. Depending on instruction, arguments
|
||||
* are either integers, or pointers to instruction trees. Common
|
||||
* are either integers, or pointers to instruction trees. Common
|
||||
* instructions like +, that have two expressions as arguments use
|
||||
* TWOARGS macro to get both of them evaluated.
|
||||
*
|
||||
|
@ -585,7 +588,7 @@ interpret(struct f_inst *what)
|
|||
default: runtime( "Usage of unknown type" );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case '&':
|
||||
case '|':
|
||||
ARG(v1, a1.p);
|
||||
|
@ -625,7 +628,7 @@ interpret(struct f_inst *what)
|
|||
|
||||
if (v1.type == T_INT) {
|
||||
ipv4_used = 0; key = v1.val.i;
|
||||
}
|
||||
}
|
||||
else if (v1.type == T_QUAD) {
|
||||
ipv4_used = 1; key = v1.val.i;
|
||||
}
|
||||
|
@ -724,7 +727,7 @@ interpret(struct f_inst *what)
|
|||
#endif
|
||||
runtime( "Assigning to variable of incompatible type" );
|
||||
}
|
||||
*vp = v2;
|
||||
*vp = v2;
|
||||
break;
|
||||
|
||||
/* some constants have value in a2, some in *a1.p, strange. */
|
||||
|
@ -864,12 +867,14 @@ interpret(struct f_inst *what)
|
|||
ACCESS_RTE;
|
||||
{
|
||||
eattr *e = NULL;
|
||||
u16 code = what->a2.i;
|
||||
|
||||
if (!(f_flags & FF_FORCE_TMPATTR))
|
||||
e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
|
||||
if (!e)
|
||||
e = ea_find( (*f_tmp_attrs), what->a2.i );
|
||||
e = ea_find((*f_rte)->attrs->eattrs, code);
|
||||
if (!e)
|
||||
e = ea_find((*f_tmp_attrs), code);
|
||||
if ((!e) && (f_flags & FF_FORCE_TMPATTR))
|
||||
e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
|
||||
e = ea_find((*f_rte)->attrs->eattrs, code);
|
||||
|
||||
if (!e) {
|
||||
/* A special case: undefined int_set looks like empty int_set */
|
||||
|
@ -878,8 +883,9 @@ interpret(struct f_inst *what)
|
|||
res.val.ad = adata_empty(f_pool, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* The same special case for ec_set */
|
||||
else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
|
||||
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
|
||||
res.type = T_ECLIST;
|
||||
res.val.ad = adata_empty(f_pool, 0);
|
||||
break;
|
||||
|
@ -912,6 +918,10 @@ interpret(struct f_inst *what)
|
|||
res.type = T_PATH;
|
||||
res.val.ad = e->u.ptr;
|
||||
break;
|
||||
case EAF_TYPE_BITFIELD:
|
||||
res.type = T_BOOL;
|
||||
res.val.i = !!(e->u.data & BITFIELD_MASK(what));
|
||||
break;
|
||||
case EAF_TYPE_INT_SET:
|
||||
res.type = T_CLIST;
|
||||
res.val.ad = e->u.ptr;
|
||||
|
@ -933,13 +943,15 @@ interpret(struct f_inst *what)
|
|||
ONEARG;
|
||||
{
|
||||
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
|
||||
u16 code = what->a2.i;
|
||||
|
||||
l->next = NULL;
|
||||
l->flags = EALF_SORTED;
|
||||
l->count = 1;
|
||||
l->attrs[0].id = what->a2.i;
|
||||
l->attrs[0].id = code;
|
||||
l->attrs[0].flags = 0;
|
||||
l->attrs[0].type = what->aux | EAF_ORIGINATED;
|
||||
|
||||
switch (what->aux & EAF_TYPE_MASK) {
|
||||
case EAF_TYPE_INT:
|
||||
if (v1.type != T_INT)
|
||||
|
@ -978,6 +990,26 @@ interpret(struct f_inst *what)
|
|||
runtime( "Setting path attribute to non-path value" );
|
||||
l->attrs[0].u.ptr = v1.val.ad;
|
||||
break;
|
||||
case EAF_TYPE_BITFIELD:
|
||||
if (v1.type != T_BOOL)
|
||||
runtime( "Setting bit in bitfield attribute to non-bool value" );
|
||||
{
|
||||
/* First, we have to find the old value */
|
||||
eattr *e = NULL;
|
||||
if (!(f_flags & FF_FORCE_TMPATTR))
|
||||
e = ea_find((*f_rte)->attrs->eattrs, code);
|
||||
if (!e)
|
||||
e = ea_find((*f_tmp_attrs), code);
|
||||
if ((!e) && (f_flags & FF_FORCE_TMPATTR))
|
||||
e = ea_find((*f_rte)->attrs->eattrs, code);
|
||||
u32 data = e ? e->u.data : 0;
|
||||
|
||||
if (v1.val.i)
|
||||
l->attrs[0].u.data = data | BITFIELD_MASK(what);
|
||||
else
|
||||
l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
|
||||
}
|
||||
break;
|
||||
case EAF_TYPE_INT_SET:
|
||||
if (v1.type != T_CLIST)
|
||||
runtime( "Setting clist attribute to non-clist value" );
|
||||
|
@ -1073,7 +1105,7 @@ interpret(struct f_inst *what)
|
|||
res = interpret(what->a2.p);
|
||||
if (res.type == T_RETURN)
|
||||
return res;
|
||||
res.type &= ~T_RETURN;
|
||||
res.type &= ~T_RETURN;
|
||||
break;
|
||||
case P('c','v'): /* Clear local variables */
|
||||
for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
|
||||
|
@ -1090,7 +1122,7 @@ interpret(struct f_inst *what)
|
|||
debug( "No else statement?\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* It is actually possible to have t->data NULL */
|
||||
|
||||
res = interpret(t->data);
|
||||
|
@ -1184,10 +1216,10 @@ interpret(struct f_inst *what)
|
|||
runtime("Can't add set");
|
||||
else if (!arg_set)
|
||||
res.val.ad = int_set_add(f_pool, v1.val.ad, n);
|
||||
else
|
||||
else
|
||||
res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
|
||||
break;
|
||||
|
||||
|
||||
case 'd':
|
||||
if (!arg_set)
|
||||
res.val.ad = int_set_del(f_pool, v1.val.ad, n);
|
||||
|
@ -1209,7 +1241,7 @@ interpret(struct f_inst *what)
|
|||
{
|
||||
/* Extended community list */
|
||||
int arg_set = 0;
|
||||
|
||||
|
||||
/* v2.val is either EC or EC-set */
|
||||
if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
|
||||
arg_set = 1;
|
||||
|
@ -1226,10 +1258,10 @@ interpret(struct f_inst *what)
|
|||
runtime("Can't add set");
|
||||
else if (!arg_set)
|
||||
res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
|
||||
else
|
||||
else
|
||||
res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
|
||||
break;
|
||||
|
||||
|
||||
case 'd':
|
||||
if (!arg_set)
|
||||
res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
|
||||
|
@ -1353,7 +1385,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
|||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'c':
|
||||
switch (f1->aux) {
|
||||
|
||||
case T_PREFIX_SET:
|
||||
|
@ -1381,7 +1413,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
|||
return 0;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
case 'V':
|
||||
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
|
||||
return 0;
|
||||
break;
|
||||
|
@ -1399,12 +1431,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
|||
case 'r': ONEARG; break;
|
||||
case P('c','p'): ONEARG; break;
|
||||
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
|
||||
ONEARG;
|
||||
ONEARG;
|
||||
if (!i_same(f1->a2.p, f2->a2.p))
|
||||
return 0;
|
||||
return 0;
|
||||
f2->a2.p = f1->a2.p;
|
||||
break;
|
||||
case P('c','v'): break; /* internal instruction */
|
||||
case P('c','v'): break; /* internal instruction */
|
||||
case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
|
||||
case P('i','M'): TWOARGS; break;
|
||||
case P('A','p'): TWOARGS; break;
|
||||
|
@ -1414,7 +1446,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
|||
case P('R','C'):
|
||||
TWOARGS;
|
||||
/* Does not really make sense - ROA check resuls may change anyway */
|
||||
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
|
||||
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
|
||||
((struct f_inst_roa_check *) f2)->rtc->name))
|
||||
return 0;
|
||||
break;
|
||||
|
|
|
@ -417,13 +417,15 @@ typedef struct eattr {
|
|||
|
||||
#define EA_CODE_MASK 0xffff
|
||||
#define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */
|
||||
#define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */
|
||||
|
||||
#define EAF_TYPE_MASK 0x0f /* Mask with this to get type */
|
||||
#define EAF_TYPE_INT 0x01 /* 32-bit signed integer number */
|
||||
#define EAF_TYPE_INT 0x01 /* 32-bit unsigned integer number */
|
||||
#define EAF_TYPE_OPAQUE 0x02 /* Opaque byte string (not filterable) */
|
||||
#define EAF_TYPE_IP_ADDRESS 0x04 /* IP address */
|
||||
#define EAF_TYPE_ROUTER_ID 0x05 /* Router ID (IPv4 address) */
|
||||
#define EAF_TYPE_AS_PATH 0x06 /* BGP AS path (encoding per RFC 1771:4.3) */
|
||||
#define EAF_TYPE_BITFIELD 0x09 /* 32-bit embedded bitfield */
|
||||
#define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */
|
||||
#define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */
|
||||
#define EAF_TYPE_UNDEF 0x0f /* `force undefined' entry */
|
||||
|
@ -469,6 +471,7 @@ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffe
|
|||
int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */
|
||||
unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */
|
||||
ea_list *ea_append(ea_list *to, ea_list *what);
|
||||
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
|
||||
|
||||
int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */
|
||||
static inline int mpnh_same(struct mpnh *x, struct mpnh *y)
|
||||
|
|
|
@ -563,6 +563,32 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
|
|||
return GA_UNKNOWN;
|
||||
}
|
||||
|
||||
void
|
||||
ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
|
||||
{
|
||||
byte *bound = buf + bufsize - 32;
|
||||
u32 data = a->u.data;
|
||||
int i;
|
||||
|
||||
for (i = min; i < max; i++)
|
||||
if ((data & (1u << i)) && names[i])
|
||||
{
|
||||
if (buf > bound)
|
||||
{
|
||||
strcpy(buf, " ...");
|
||||
return;
|
||||
}
|
||||
|
||||
buf += bsprintf(buf, " %s", names[i]);
|
||||
data &= ~(1u << i);
|
||||
}
|
||||
|
||||
if (data)
|
||||
bsprintf(buf, " %08x", data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
opaque_format(struct adata *ad, byte *buf, unsigned int size)
|
||||
{
|
||||
|
@ -665,6 +691,9 @@ ea_show(struct cli *c, eattr *e)
|
|||
case EAF_TYPE_AS_PATH:
|
||||
as_path_format(ad, pos, end - pos);
|
||||
break;
|
||||
case EAF_TYPE_BITFIELD:
|
||||
bsprintf(pos, "%08x", e->u.data);
|
||||
break;
|
||||
case EAF_TYPE_INT_SET:
|
||||
ea_show_int_set(c, ad, 1, pos, buf, end);
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue