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

Merge commit 'e7c2380260f20a4a3587b47df97879ef91c69774' into integrated

This commit is contained in:
Ondrej Zajicek 2014-04-29 15:16:32 +02:00
commit 455539ba1b
12 changed files with 241 additions and 151 deletions

View File

@ -1077,6 +1077,8 @@ incompatible with each other (that is to prevent you from shooting in the foot).
no literals of this type. There are three special operators on
clists:
<cf><m/C/.len</cf> returns the length of clist <m/C/.
<cf>add(<m/C/,<m/P/)</cf> adds pair (or quad) <m/P/ to clist
<m/C/ and returns the result. If item <m/P/ is already in
clist <m/C/, it does nothing. <m/P/ may also be a clist,

View File

@ -58,22 +58,6 @@ adata_empty(struct linpool *pool, int l)
return res;
}
static int
pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2)
{
while (1) {
if ((!m1) || (!m2))
return !((!m1) && (!m2));
/* FIXME: buggy, should return -1, 0, 1; but it doesn't matter */
if ((m1->kind != m2->kind) || (m1->val != m2->val)) return 1;
m1 = m1->next;
m2 = m2->next;
}
}
u32 f_eval_asn(struct f_inst *expr);
static void
pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
{
@ -112,25 +96,22 @@ pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
*buf = 0;
}
static inline int int_cmp(int i1, int i2)
static inline int
int_cmp(int i1, int i2)
{
if (i1 == i2) return 0;
if (i1 < i2) return -1;
else return 1;
return (i1 > i2) - (i1 < i2);
}
static inline int uint_cmp(unsigned int i1, unsigned int i2)
static inline int
uint_cmp(unsigned int i1, unsigned int i2)
{
if (i1 == i2) return 0;
if (i1 < i2) return -1;
else return 1;
return (int)(i1 > i2) - (int)(i1 < i2);
}
static inline int u64_cmp(u64 i1, u64 i2)
static inline int
u64_cmp(u64 i1, u64 i2)
{
if (i1 == i2) return 0;
if (i1 < i2) return -1;
else return 1;
return (int)(i1 > i2) - (int)(i1 < i2);
}
/**
@ -138,23 +119,21 @@ static inline int u64_cmp(u64 i1, u64 i2)
* @v1: first value
* @v2: second value
*
* Compares two values and returns -1, 0, 1 on <, =, > or 999 on error.
* Tree module relies on this giving consistent results so that it can
* build balanced trees.
* Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
* error. Tree module relies on this giving consistent results so
* that it can be used for building balanced trees.
*/
int
val_compare(struct f_val v1, struct f_val v2)
{
int rc;
if ((v1.type == T_VOID) && (v2.type == T_VOID))
return 0;
if (v1.type == T_VOID) /* Hack for else */
return -1;
if (v2.type == T_VOID)
return 1;
if (v1.type != v2.type) {
if (v1.type == T_VOID) /* Hack for else */
return -1;
if (v2.type == T_VOID)
return 1;
#ifndef IPV6
/* IP->Quad implicit conversion */
if ((v1.type == T_QUAD) && (v2.type == T_IP))
@ -166,7 +145,10 @@ val_compare(struct f_val v1, struct f_val v2)
debug( "Types do not match in val_compare\n" );
return CMP_ERROR;
}
switch (v1.type) {
case T_VOID:
return 0;
case T_ENUM:
case T_INT:
case T_BOOL:
@ -181,25 +163,63 @@ val_compare(struct f_val v1, struct f_val v2)
case T_PREFIX:
if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
return rc;
if (v1.val.px.len < v2.val.px.len)
return -1;
if (v1.val.px.len > v2.val.px.len)
return 1;
return 0;
case T_PATH_MASK:
return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
return int_cmp(v1.val.px.len, v2.val.px.len);
case T_STRING:
return strcmp(v1.val.s, v2.val.s);
default:
debug( "Compare of unknown entities: %x\n", v1.type );
return CMP_ERROR;
}
}
int
tree_compare(const void *p1, const void *p2)
static int
pm_path_same(struct f_path_mask *m1, struct f_path_mask *m2)
{
return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
while (m1 && m2)
{
if ((m1->kind != m2->kind) || (m1->val != m2->val))
return 0;
m1 = m1->next;
m2 = m2->next;
}
return !m1 && !m2;
}
/**
* val_same - compare two values
* @v1: first value
* @v2: second value
*
* Compares two values and returns 1 if they are same and 0 if not.
* Comparison of values of different types is valid and returns 0.
*/
int
val_same(struct f_val v1, struct f_val v2)
{
int rc;
rc = val_compare(v1, v2);
if (rc != CMP_ERROR)
return !rc;
if (v1.type != v2.type)
return 0;
switch (v1.type) {
case T_PATH_MASK:
return pm_path_same(v1.val.path_mask, v2.val.path_mask);
case T_PATH:
case T_CLIST:
case T_ECLIST:
return adata_same(v1.val.ad, v2.val.ad);
case T_SET:
return same_tree(v1.val.t, v2.val.t);
case T_PREFIX_SET:
return trie_same(v1.val.ti, v2.val.ti);
default:
bug("Invalid type in val_same(): %x", v1.type);
}
}
void
@ -220,39 +240,6 @@ fprefix_get_bounds(struct f_prefix *px, int *l, int *h)
}
}
/*
* val_simple_in_range - check if @v1 ~ @v2 for everything except sets
*/
static int
val_simple_in_range(struct f_val v1, struct f_val v2)
{
if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
return as_path_match(v1.val.ad, v2.val.path_mask);
if ((v1.type == T_INT) && (v2.type == T_PATH))
return as_path_is_member(v2.val.ad, v1.val.i);
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, v1.val.i);
#ifndef IPV6
/* IP->Quad implicit conversion */
if ((v1.type == T_IP) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
#endif
if ((v1.type == T_EC) && (v2.type == T_ECLIST))
return ec_set_contains(v2.val.ad, v1.val.ec);
if ((v1.type == T_STRING) && (v2.type == T_STRING))
return patmatch(v2.val.s, v1.val.s);
if ((v1.type == T_IP) && (v2.type == T_PREFIX))
return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
return CMP_ERROR;
}
static int
clist_set_type(struct f_tree *set, struct f_val *v)
{
@ -396,47 +383,57 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
* @v1: element
* @v2: set
*
* Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see
* |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early).
* Checks if @v1 is element (|~| operator) of @v2.
*/
static int
val_in_range(struct f_val v1, struct f_val v2)
{
int res;
if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
return as_path_match(v1.val.ad, v2.val.path_mask);
res = val_simple_in_range(v1, v2);
if ((v1.type == T_INT) && (v2.type == T_PATH))
return as_path_is_member(v2.val.ad, v1.val.i);
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, v1.val.i);
#ifndef IPV6
/* IP->Quad implicit conversion */
if ((v1.type == T_IP) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
#endif
if ((v1.type == T_EC) && (v2.type == T_ECLIST))
return ec_set_contains(v2.val.ad, v1.val.ec);
if ((v1.type == T_STRING) && (v2.type == T_STRING))
return patmatch(v2.val.s, v1.val.s);
if ((v1.type == T_IP) && (v2.type == T_PREFIX))
return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
if (res != CMP_ERROR)
return res;
if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
return trie_match_fprefix(v2.val.ti, &v1.val.px);
if ((v1.type == T_CLIST) && (v2.type == T_SET))
if (v2.type != T_SET)
return CMP_ERROR;
/* With integrated Quad<->IP implicit conversion */
if ((v1.type == v2.val.t->from.type) ||
((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP)))
return !!find_tree(v2.val.t, v1);
if (v1.type == T_CLIST)
return clist_match_set(v1.val.ad, v2.val.t);
if ((v1.type == T_ECLIST) && (v2.type == T_SET))
if (v1.type == T_ECLIST)
return eclist_match_set(v1.val.ad, v2.val.t);
if ((v1.type == T_PATH) && (v2.type == T_SET))
if (v1.type == T_PATH)
return as_path_match_set(v1.val.ad, v2.val.t);
if (v2.type == T_SET)
switch (v1.type) {
case T_ENUM:
case T_INT:
case T_PAIR:
case T_QUAD:
case T_IP:
case T_EC:
{
struct f_tree *n;
n = find_tree(v2.val.t, v1);
if (!n)
return 0;
return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
}
}
return CMP_ERROR;
}
@ -717,8 +714,15 @@ interpret(struct f_inst *what)
res.val.i = (x); \
break;
case P('!','='): COMPARE(i!=0);
case P('=','='): COMPARE(i==0);
#define SAME(x) \
TWOARGS; \
i = val_same(v1, v2); \
res.type = T_BOOL; \
res.val.i = (x); \
break;
case P('!','='): SAME(!i);
case P('=','='): SAME(i);
case '<': COMPARE(i==-1);
case P('<','='): COMPARE(i!=1);
@ -1063,7 +1067,9 @@ interpret(struct f_inst *what)
switch(v1.type) {
case T_PREFIX: res.val.i = v1.val.px.len; break;
case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
default: runtime( "Prefix or path expected" );
case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
default: runtime( "Prefix, path, clist or eclist expected" );
}
break;
case P('c','p'): /* Convert prefix to ... */
@ -1409,33 +1415,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
A2_SAME;
}
break;
case 'C':
{
struct f_val *v1 = (struct f_val *) f1->a1.p;
struct f_val *v2 = (struct f_val *) f2->a1.p;
/* Handle some cases that are not handled by val_compare()
also T_PATH, T_CLIST and T_ECLIST does not work,
but you cannot easily create such constants */
if ((v1->type == T_SET) && (v2->type == T_SET))
{
if (!same_tree(v1->val.t, v2->val.t))
return 0;
break;
}
if ((v1->type == T_PREFIX_SET) && (v2->type == T_PREFIX_SET))
{
if (!trie_same(v1->val.ti, v2->val.ti))
return 0;
break;
}
if (val_compare(*v1 , *v2))
return 0;
}
case 'C':
if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
return 0;
break;
case 'V':
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0;

View File

@ -119,7 +119,7 @@ int filter_same(struct filter *new, struct filter *old);
int i_same(struct f_inst *f1, struct f_inst *f2);
int val_compare(struct f_val v1, struct f_val v2);
int tree_compare(const void *p1, const void *p2);
int val_same(struct f_val v1, struct f_val v2);
void val_print(struct f_val v);

View File

@ -142,10 +142,10 @@ eclist el2;
l = add( l, (3,5) );
l2 = filter( l, [(3,*)] );
l = delete( l, [(3,2..4)] );
print "Community list (1,2) (3,1) (3,5) ", l;
print "Community list (1,2) (3,1) (3,5) ", l, " len: ", l.len;
l = add( l, (3,2) );
l = add( l, (4,5) );
print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l;
print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l, " len: ", l.len;
print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)];
print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))];
l = delete( l, [(*,(one+onef(3)))] );
@ -168,6 +168,7 @@ eclist el2;
el = add(el, (ro, 11.21.31.41.mask(16), 200));
print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):";
print el;
print "EC len: ", el.len;
el = delete(el, (rt, 10, 20));
el = delete(el, (rt, 10, 30));
el = add(el, (unknown 2, ten, 1));
@ -282,6 +283,12 @@ string s;
# if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; }
if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok";
is = [ 2, 3, 4, 7..11 ];
print "must be true: ", 1 = 1, " ", 1 != (0,1), " ", 1 != "a", " ", +empty+ = +empty+, " ", -empty- = -empty-, " ", --empty-- = --empty-- ,
" ", [1,4..10,20] = [1,4..10,20] , " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ];
print "must be false: ", 1 != 1, " ", 1 = (0,1), " ", 1 = "a", " ", +empty+ = -empty-, " ", -empty- = --empty--, " ", --empty-- = +empty+ ,
" ", [1,2] = [1,3], " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 11.0.0.0/8{ 15 , 17 } ];
print " must be true: ", 1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ];
print " data types; must be true: ", 1.2.3.4 = 1.2.3.4, ",", 1 ~ [1,2,3], ",", 5 ~ [1..20], ",", 10 ~ is, ",", 2 ~ [ 1, 2, 3 ], ",", 5 ~ [ 4 .. 7 ], ",", 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ], ",", 1.2.3.4 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ [ 1.0.0.0/8+ ];
print " must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a");

View File

@ -53,6 +53,11 @@ build_tree_rec(struct f_tree **buf, int l, int h)
return n;
}
static int
tree_compare(const void *p1, const void *p2)
{
return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
}
/**
* build_tree

View File

@ -293,7 +293,7 @@ trie_print(struct f_trie *t)
logn("[");
if (t->zero)
{
logn("0.0.0.0/0");
logn("%I/%d", IPA_NONE, 0);
sep = ", ";
}
trie_node_print(&t->root, &sep);

View File

@ -34,6 +34,12 @@
#define NULL ((void *) 0)
#endif
#ifndef IPV6
#define IP_VERSION 4
#else
#define IP_VERSION 6
#endif
/* Macros for gcc attributes */
#define NORET __attribute__((noreturn))

View File

@ -69,6 +69,9 @@ int as_path_match(struct adata *path, struct f_path_mask *mask);
static inline int int_set_get_size(struct adata *list)
{ return list->length / 4; }
static inline int ec_set_get_size(struct adata *list)
{ return list->length / 8; }
static inline u32 *int_set_get_data(struct adata *list)
{ return (u32 *) list->data; }

View File

@ -376,6 +376,7 @@ int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hoo
static int
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
{
struct announce_hook *ah = p->main_ahook;
/* If the protocol is DOWN, we just restart it */
if (p->proto_state == PS_DOWN)
return 0;
@ -407,14 +408,31 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
/* Update filters and limits in the main announce hook
Note that this also resets limit state */
if (p->main_ahook)
if (ah)
{
p->main_ahook->in_filter = nc->in_filter;
p->main_ahook->out_filter = nc->out_filter;
p->main_ahook->rx_limit = nc->rx_limit;
p->main_ahook->in_limit = nc->in_limit;
p->main_ahook->out_limit = nc->out_limit;
p->main_ahook->in_keep_filtered = nc->in_keep_filtered;
ah->in_filter = nc->in_filter;
ah->out_filter = nc->out_filter;
ah->rx_limit = nc->rx_limit;
ah->in_limit = nc->in_limit;
ah->out_limit = nc->out_limit;
ah->in_keep_filtered = nc->in_keep_filtered;
if (p->proto_state == PS_UP) /* Recheck export/import/receive limit */
{
struct proto_stats *stats = ah->stats;
struct proto_limit *l = ah->in_limit;
u32 all_routes = stats->imp_routes + stats->filt_routes;
if (l && (stats->imp_routes >= l->limit)) proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
l = ah->rx_limit;
if (l && ( all_routes >= l->limit)) proto_notify_limit(ah, l, PLD_RX, all_routes );
l = ah->out_limit;
if (l && ( stats->exp_routes >= l->limit)) proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
}
}
/* Update routes when filters changed. If the protocol in not UP,

View File

@ -450,6 +450,10 @@ struct adata {
byte data[0];
};
static inline int adata_same(struct adata *a, struct adata *b)
{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); }
typedef struct ea_list {
struct ea_list *next; /* In case we have an override list */
byte flags; /* Flags: EALF_... */

View File

@ -366,8 +366,7 @@ ea_same(ea_list *x, ea_list *y)
if (a->id != b->id ||
a->flags != b->flags ||
a->type != b->type ||
((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data :
(a->u.ptr->length != b->u.ptr->length || memcmp(a->u.ptr->data, b->u.ptr->data, a->u.ptr->length))))
((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr)))
return 0;
}
return 1;

View File

@ -472,6 +472,58 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
die("chmod: %m");
}
/*
* PID file
*/
static char *pid_file;
static int pid_fd;
static inline void
open_pid_file(void)
{
if (!pid_file)
return;
pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
if (pid_fd < 0)
die("Cannot create PID file %s: %m", pid_file);
}
static inline void
write_pid_file(void)
{
int pl, rv;
char ps[24];
if (!pid_file)
return;
/* We don't use PID file for uniqueness, so no need for locking */
pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
if (pl < 0)
bug("PID buffer too small");
rv = ftruncate(pid_fd, 0);
if (rv < 0)
die("fruncate: %m");
rv = write(pid_fd, ps, pl);
if(rv < 0)
die("write: %m");
close(pid_fd);
}
static inline void
unlink_pid_file(void)
{
if (pid_file)
unlink(pid_file);
}
/*
* Shutdown
*/
@ -496,6 +548,7 @@ async_shutdown(void)
void
sysdep_shutdown_done(void)
{
unlink_pid_file();
unlink(path_control_socket);
log_msg(L_FATAL "Shutdown completed");
exit(0);
@ -548,7 +601,7 @@ signal_init(void)
* Parsing of command-line arguments
*/
static char *opt_list = "c:dD:ps:u:g:";
static char *opt_list = "c:dD:ps:P:u:g:";
static int parse_and_exit;
char *bird_name;
static char *use_user;
@ -557,7 +610,7 @@ static char *use_group;
static void
usage(void)
{
fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>]\n", bird_name);
exit(1);
}
@ -656,6 +709,9 @@ parse_args(int argc, char **argv)
case 's':
path_control_socket = optarg;
break;
case 'P':
pid_file = optarg;
break;
case 'u':
use_user = optarg;
break;
@ -709,6 +765,9 @@ main(int argc, char **argv)
if (use_uid)
drop_uid(use_uid);
if (!parse_and_exit)
open_pid_file();
protos_build();
proto_build(&proto_unix_kernel);
proto_build(&proto_unix_iface);
@ -733,6 +792,8 @@ main(int argc, char **argv)
dup2(0, 2);
}
write_pid_file();
signal_init();
#ifdef LOCAL_DEBUG