mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-12 21:06:22 +00:00
Merge remote-tracking branch 'origin/mq-filter-stack'
This commit is contained in:
commit
cec40a7467
@ -79,11 +79,6 @@ docker_fedora-26-amd64:
|
||||
IMG_NAME: "fedora-26-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_centos-6-amd64:
|
||||
variables:
|
||||
IMG_NAME: "centos-6-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_centos-7-amd64:
|
||||
variables:
|
||||
IMG_NAME: "centos-7-amd64"
|
||||
@ -174,13 +169,6 @@ docker_ubuntu-16_04-amd64:
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.centos-6-amd64: ¢os-6-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:centos-6-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.centos-7-amd64: ¢os-7-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:centos-7-amd64
|
||||
tags:
|
||||
@ -264,10 +252,6 @@ build-fedora-26-amd64:
|
||||
<<: *fedora-26-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-centos-6-amd64:
|
||||
<<: *centos-6-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-centos-7-amd64:
|
||||
<<: *centos-7-amd64_env
|
||||
<<: *build_job
|
||||
|
@ -77,6 +77,8 @@ $(daemon): LIBS += $(DAEMON_LIBS)
|
||||
# Include directories
|
||||
dirs := client conf doc filter lib nest test $(addprefix proto/,$(protocols)) @sysdep_dirs@
|
||||
|
||||
# conf/Makefile declarations needed for all other modules
|
||||
conf-lex-targets := $(addprefix $(objdir)/conf/,cf-lex.o)
|
||||
conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h)
|
||||
cf-local = $(conf-y-targets): $(s)config.Y
|
||||
|
||||
@ -100,6 +102,7 @@ endef
|
||||
|
||||
clean = $(eval $(call clean_in,$(1)))
|
||||
|
||||
# Include main Makefiles of the directories
|
||||
include $(addsuffix /Makefile,$(addprefix $(srcdir)/,$(dirs)))
|
||||
|
||||
# Generic rules
|
||||
|
43
aclocal.m4
vendored
43
aclocal.m4
vendored
@ -1,6 +1,25 @@
|
||||
dnl ** Additional Autoconf tests for BIRD configure script
|
||||
dnl ** (c) 1999 Martin Mares <mj@ucw.cz>
|
||||
|
||||
AC_DEFUN([BIRD_CHECK_THREAD_LOCAL],
|
||||
[
|
||||
AC_CACHE_CHECK(
|
||||
[whether _Thread_local is known],
|
||||
[bird_cv_thread_local],
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
_Thread_local static int x = 42;
|
||||
],
|
||||
[]
|
||||
)
|
||||
],
|
||||
[bird_cv_thread_local=yes],
|
||||
[bird_cv_thread_local=no]
|
||||
)
|
||||
)
|
||||
])
|
||||
|
||||
AC_DEFUN([BIRD_CHECK_PTHREADS],
|
||||
[
|
||||
bird_tmp_cflags="$CFLAGS"
|
||||
@ -131,6 +150,30 @@ AC_DEFUN([BIRD_CHECK_ANDROID_LOG],
|
||||
)
|
||||
])
|
||||
|
||||
AC_DEFUN([BIRD_CHECK_LTO],
|
||||
[
|
||||
bird_tmp_cflags="$CFLAGS"
|
||||
bird_tmp_ldflags="$LDFLAGS"
|
||||
CFLAGS="-flto"
|
||||
LDFLAGS="-flto"
|
||||
|
||||
AC_CACHE_CHECK(
|
||||
[whether link time optimizer is available],
|
||||
[bird_cv_c_lto],
|
||||
[
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM()],
|
||||
[bird_cv_c_lto=yes],
|
||||
[bird_cv_c_lto=no]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
CFLAGS="$bird_tmp_cflags"
|
||||
LDFLAGS="$bird_tmp_ldflags"
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([BIRD_CHECK_GCC_OPTION],
|
||||
[
|
||||
bird_tmp_cflags="$CFLAGS"
|
||||
|
153
bird-gdb.py
Normal file
153
bird-gdb.py
Normal file
@ -0,0 +1,153 @@
|
||||
class BIRDPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
@classmethod
|
||||
def lookup(cls, val):
|
||||
if val.type.code != cls.typeCode:
|
||||
return None
|
||||
if val.type.tag != cls.typeTag:
|
||||
return None
|
||||
|
||||
return cls(val)
|
||||
|
||||
|
||||
class BIRDFValPrinter(BIRDPrinter):
|
||||
"Print BIRD\s struct f_val"
|
||||
typeCode = gdb.TYPE_CODE_STRUCT
|
||||
typeTag = "f_val"
|
||||
|
||||
codemap = {
|
||||
"T_INT": "i",
|
||||
"T_BOOL": "i",
|
||||
"T_PAIR": "i",
|
||||
"T_QUAD": "i",
|
||||
"T_ENUM_RTS": "i",
|
||||
"T_ENUM_BGP_ORIGIN": "i",
|
||||
"T_ENUM_SCOPE": "i",
|
||||
"T_ENUM_RTC": "i",
|
||||
"T_ENUM_RTD": "i",
|
||||
"T_ENUM_ROA": "i",
|
||||
"T_ENUM_NETTYPE": "i",
|
||||
"T_ENUM_RA_PREFERENCE": "i",
|
||||
"T_IP": "ip",
|
||||
"T_NET": "net",
|
||||
"T_STRING": "s",
|
||||
"T_PATH_MASK": "path_mask",
|
||||
"T_PATH": "ad",
|
||||
"T_CLIST": "ad",
|
||||
"T_EC": "ec",
|
||||
"T_ECLIST": "ad",
|
||||
"T_LC": "lc",
|
||||
"T_LCLIST": "ad",
|
||||
"T_RD": "ec",
|
||||
"T_PATH_MASK_ITEM": "pmi",
|
||||
"T_SET": "t",
|
||||
"T_PREFIX_SET": "ti",
|
||||
}
|
||||
|
||||
def to_string(self):
|
||||
code = self.val['type']
|
||||
if code.type.code != gdb.TYPE_CODE_ENUM or code.type.tag != "f_type":
|
||||
raise Exception("Strange 'type' element in f_val")
|
||||
|
||||
if str(code) == "T_VOID":
|
||||
return "T_VOID"
|
||||
else:
|
||||
return "(%(c)s) %(v)s" % { "c": code, "v": self.val['val'][self.codemap[str(code)]] }
|
||||
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
class BIRDFValStackPrinter(BIRDPrinter):
|
||||
"Print BIRD's struct f_val_stack"
|
||||
typeCode = gdb.TYPE_CODE_STRUCT
|
||||
typeTag = "f_val_stack"
|
||||
|
||||
def to_string(self):
|
||||
cnt = self.val['cnt']
|
||||
return ("Value stack (%(cnt)d):\n\t" % { "cnt": cnt }) + \
|
||||
"\n\t".join([ (".val[%(n) 3d] = " % { "n": n}) + str(self.val['val'][n]) for n in range(cnt-1, -1, -1) ])
|
||||
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
class BIRDFInstPrinter(BIRDPrinter):
|
||||
"Print BIRD's struct f_inst"
|
||||
typeCode = gdb.TYPE_CODE_STRUCT
|
||||
typeTag = "f_inst"
|
||||
|
||||
def to_string(self):
|
||||
code = self.val['fi_code']
|
||||
if str(code) == "FI_NOP":
|
||||
return str(code) + ": " + str(self.val.cast(gdb.lookup_type("const char [%(siz)d]" % { "siz": self.val.type.sizeof })))
|
||||
return "%(code)s:\t%(lineno) 6dL\t%(size)6dS\tnext = %(next)s: .i_%(code)s = %(union)s" % {
|
||||
"code": str(code),
|
||||
"lineno": self.val['lineno'],
|
||||
"size": self.val['size'],
|
||||
"next": str(self.val['next']),
|
||||
"union": str(self.val['i_' + str(code)])
|
||||
}
|
||||
|
||||
# def children(self): # children iterator
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
class BIRDFLineItemPrinter(BIRDPrinter):
|
||||
"Print BIRD's struct f_line_item"
|
||||
typeCode = gdb.TYPE_CODE_STRUCT
|
||||
typeTag = "f_line_item"
|
||||
|
||||
def to_string(self):
|
||||
code = self.val['fi_code']
|
||||
if str(code) == "FI_NOP":
|
||||
return str(code) + ": " + str(self.val.cast(gdb.lookup_type("const char [%(siz)d]" % { "siz": self.val.type.sizeof })))
|
||||
return "%(code)s:\t%(lineno) 6dL\t%(flags)2dF: .i_%(code)s = %(union)s" % {
|
||||
"code": str(code),
|
||||
"lineno": self.val['lineno'],
|
||||
"flags": self.val['flags'],
|
||||
"union": str(self.val['i_' + str(code)])
|
||||
}
|
||||
|
||||
class BIRDFLinePrinter(BIRDPrinter):
|
||||
"Print BIRD's struct f_line"
|
||||
typeCode = gdb.TYPE_CODE_STRUCT
|
||||
typeTag = "f_line"
|
||||
|
||||
def to_string(self):
|
||||
cnt = self.val['len']
|
||||
return ("FLine (%(cnt)d, args=%(args)d): " % { "cnt": cnt, "args" : self.val['args'] } + \
|
||||
", ".join([
|
||||
".items[%(n) 3d] = %(code)s" % {
|
||||
"n": n,
|
||||
"code": str(self.val['items'][n]['fi_code']),
|
||||
} if n % 8 == 0 else str(self.val['items'][n]['fi_code']) for n in range(cnt)]))
|
||||
|
||||
|
||||
class BIRDFExecStackPrinter(BIRDPrinter):
|
||||
"Print BIRD's struct f_exec_stack"
|
||||
typeCode = gdb.TYPE_CODE_STRUCT
|
||||
typeTag = "f_exec_stack"
|
||||
|
||||
def to_string(self):
|
||||
cnt = self.val['cnt']
|
||||
return ("Exec stack (%(cnt)d):\n\t" % { "cnt": cnt }) + \
|
||||
"\n\t".join([ ".item[%(n) 3d] = %(retflag)d V%(ventry) 3d P%(pos) 4d %(line)s" % {
|
||||
"retflag": self.val['item'][n]['emask'],
|
||||
"ventry": self.val['item'][n]['ventry'],
|
||||
"pos": self.val['item'][n]['pos'],
|
||||
"line": str(self.val['item'][n]['line'].dereference()),
|
||||
"n": n
|
||||
} for n in range(cnt-1, -1, -1) ])
|
||||
|
||||
def register_printers(objfile):
|
||||
objfile.pretty_printers.append(BIRDFInstPrinter.lookup)
|
||||
objfile.pretty_printers.append(BIRDFValPrinter.lookup)
|
||||
objfile.pretty_printers.append(BIRDFValStackPrinter.lookup)
|
||||
objfile.pretty_printers.append(BIRDFLineItemPrinter.lookup)
|
||||
objfile.pretty_printers.append(BIRDFLinePrinter.lookup)
|
||||
objfile.pretty_printers.append(BIRDFExecStackPrinter.lookup)
|
||||
|
||||
register_printers(gdb.current_objfile())
|
||||
|
||||
print("BIRD pretty printers loaded OK.")
|
@ -2,6 +2,7 @@ src := commands.c util.c client.c
|
||||
obj := $(src-o-files)
|
||||
|
||||
$(all-client)
|
||||
$(conf-y-targets): $(s)cmds.Y
|
||||
|
||||
$(exedir)/birdc: $(o)birdc.o
|
||||
$(exedir)/birdc: LIBS += $(CLIENT_LIBS)
|
||||
|
@ -10,12 +10,12 @@ BISON_DEBUG=-t
|
||||
#FLEX_DEBUG=-d
|
||||
endif
|
||||
|
||||
$(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y
|
||||
$(M4) $(M4FLAGS) -P $| $^ >$@
|
||||
$(o)cf-parse.y: $(s)gen_parser.m4
|
||||
$(o)keywords.h: $(s)gen_keywords.m4
|
||||
$(o)commands.h: $(s)gen_commands.m4
|
||||
|
||||
$(o)cf-parse.y: | $(s)gen_parser.m4
|
||||
$(o)keywords.h: | $(s)gen_keywords.m4
|
||||
$(o)commands.h: | $(s)gen_commands.m4 $(srcdir)/client/cmds.m4
|
||||
$(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y
|
||||
$(M4) $(M4FLAGS) -P $(if $(word 2,$(filter %.m4,$^)),$(error "Too many M4 scripts for one target"),$(filter %.m4,$^)) $(filter %.Y,$^) >$@
|
||||
|
||||
$(o)cf-parse.tab.h: $(o)cf-parse.tab.c
|
||||
|
||||
|
201
conf/cf-lex.l
201
conf/cf-lex.l
@ -45,6 +45,7 @@
|
||||
#include "nest/route.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "filter/filter.h"
|
||||
#include "filter/f-inst.h"
|
||||
#include "conf/conf.h"
|
||||
#include "conf/cf-parse.tab.h"
|
||||
#include "lib/string.h"
|
||||
@ -64,7 +65,7 @@ struct keyword {
|
||||
#endif
|
||||
|
||||
|
||||
static uint cf_hash(byte *c);
|
||||
static uint cf_hash(const byte *c);
|
||||
|
||||
#define KW_KEY(n) n->name
|
||||
#define KW_NEXT(n) n->next
|
||||
@ -95,6 +96,15 @@ int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
|
||||
struct include_file_stack *ifs;
|
||||
static struct include_file_stack *ifs_head;
|
||||
|
||||
#define QUOTED_BUFFER_SIZE 4096
|
||||
static BUFFER_(char) quoted_buffer;
|
||||
static char quoted_buffer_data[QUOTED_BUFFER_SIZE];
|
||||
static inline void quoted_buffer_init(void) {
|
||||
quoted_buffer.used = 0;
|
||||
quoted_buffer.size = QUOTED_BUFFER_SIZE;
|
||||
quoted_buffer.data = quoted_buffer_data;
|
||||
}
|
||||
|
||||
#define MAX_INCLUDE_DEPTH 8
|
||||
|
||||
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd);
|
||||
@ -105,6 +115,8 @@ static struct include_file_stack *ifs_head;
|
||||
static void cf_include(char *arg, int alen);
|
||||
static int check_eof(void);
|
||||
|
||||
static enum yytokentype cf_lex_symbol(const char *data);
|
||||
|
||||
%}
|
||||
|
||||
%option noyywrap
|
||||
@ -112,24 +124,26 @@ static int check_eof(void);
|
||||
%option nounput
|
||||
%option noreject
|
||||
|
||||
%x COMMENT CCOMM CLI
|
||||
%x COMMENT CCOMM CLI QUOTED APOSTROPHED INCLUDE
|
||||
|
||||
ALPHA [a-zA-Z_]
|
||||
DIGIT [0-9]
|
||||
XIGIT [0-9a-fA-F]
|
||||
ALNUM [a-zA-Z_0-9]
|
||||
WHITE [ \t]
|
||||
include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
|
||||
%%
|
||||
{include} {
|
||||
char *start, *end;
|
||||
|
||||
^{WHITE}*include{WHITE}*\" {
|
||||
if (!ifs->depth)
|
||||
cf_error("Include not allowed in CLI");
|
||||
|
||||
start = strchr(yytext, '"');
|
||||
start++;
|
||||
BEGIN(INCLUDE);
|
||||
}
|
||||
|
||||
<INCLUDE>[^"\n]+["]{WHITE}*; {
|
||||
char *start, *end;
|
||||
|
||||
start = yytext;
|
||||
|
||||
end = strchr(start, '"');
|
||||
*end = 0;
|
||||
@ -138,15 +152,23 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
cf_error("Include with empty argument");
|
||||
|
||||
cf_include(start, end-start);
|
||||
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
<INCLUDE>["] cf_error("Include with empty argument");
|
||||
<INCLUDE>. cf_error("Unterminated include");
|
||||
<INCLUDE>\n cf_error("Unterminated include");
|
||||
<INCLUDE><<EOF>> cf_error("Unterminated include");
|
||||
|
||||
|
||||
{DIGIT}+:{DIGIT}+ {
|
||||
uint len1 UNUSED, len2;
|
||||
u64 l;
|
||||
char *e;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(yytext, &e, 10);
|
||||
l = bstrtoul10(yytext, &e);
|
||||
if (e && (*e != ':') || (errno == ERANGE) || (l >> 32))
|
||||
cf_error("ASN out of range");
|
||||
|
||||
@ -164,7 +186,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(e+1, &e, 10);
|
||||
l = bstrtoul10(e+1, &e);
|
||||
if (e && *e || (errno == ERANGE) || (l >> len2))
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i64 |= l;
|
||||
@ -191,13 +213,13 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(yytext+2, &e, 10);
|
||||
l = bstrtoul10(yytext+2, &e);
|
||||
if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
|
||||
cf_error("ASN out of range");
|
||||
cf_lval.i64 |= ((u64) l) << len2;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(e+1, &e, 10);
|
||||
l = bstrtoul10(e+1, &e);
|
||||
if (e && *e || (errno == ERANGE) || (l >> len2))
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i64 |= l;
|
||||
@ -219,7 +241,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(e, &e, 10);
|
||||
l = bstrtoul10(e, &e);
|
||||
if (e && *e || (errno == ERANGE) || (l >> 16))
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i64 |= l;
|
||||
@ -243,7 +265,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
char *e;
|
||||
unsigned long int l;
|
||||
errno = 0;
|
||||
l = strtoul(yytext+2, &e, 16);
|
||||
l = bstrtoul16(yytext+2, &e);
|
||||
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i = l;
|
||||
@ -254,7 +276,7 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
char *e;
|
||||
unsigned long int l;
|
||||
errno = 0;
|
||||
l = strtoul(yytext, &e, 10);
|
||||
l = bstrtoul10(yytext, &e);
|
||||
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i = l;
|
||||
@ -266,26 +288,23 @@ else: {
|
||||
return ELSECOL;
|
||||
}
|
||||
|
||||
({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) {
|
||||
if(*yytext == '\'') {
|
||||
yytext[yyleng-1] = 0;
|
||||
yytext++;
|
||||
}
|
||||
['] {
|
||||
BEGIN(APOSTROPHED);
|
||||
quoted_buffer_init();
|
||||
}
|
||||
|
||||
struct keyword *k = HASH_FIND(kw_hash, KW, yytext);
|
||||
if (k)
|
||||
{
|
||||
if (k->value > 0)
|
||||
return k->value;
|
||||
else
|
||||
{
|
||||
cf_lval.i = -k->value;
|
||||
return ENUM;
|
||||
}
|
||||
}
|
||||
<APOSTROPHED>{ALNUM}|[-]|[.:] BUFFER_PUSH(quoted_buffer) = yytext[0];
|
||||
<APOSTROPHED>\n cf_error("Unterminated symbol");
|
||||
<APOSTROPHED><<EOF>> cf_error("Unterminated symbol");
|
||||
<APOSTROPHED>['] {
|
||||
BEGIN(INITIAL);
|
||||
BUFFER_PUSH(quoted_buffer) = 0;
|
||||
return cf_lex_symbol(quoted_buffer_data);
|
||||
}
|
||||
<APOSTROPHED>. cf_error("Invalid character in apostrophed symbol");
|
||||
|
||||
cf_lval.s = cf_get_symbol(yytext);
|
||||
return SYM;
|
||||
({ALPHA}{ALNUM}*) {
|
||||
return cf_lex_symbol(yytext);
|
||||
}
|
||||
|
||||
<CLI>(.|\n) {
|
||||
@ -301,14 +320,21 @@ else: {
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
["][^"\n]*["] {
|
||||
yytext[yyleng-1] = 0;
|
||||
cf_lval.t = cfg_strdup(yytext+1);
|
||||
yytext[yyleng-1] = '"';
|
||||
["] {
|
||||
BEGIN(QUOTED);
|
||||
quoted_buffer_init();
|
||||
}
|
||||
|
||||
<QUOTED>\n cf_error("Unterminated string");
|
||||
<QUOTED><<EOF>> cf_error("Unterminated string");
|
||||
<QUOTED>["] {
|
||||
BEGIN(INITIAL);
|
||||
BUFFER_PUSH(quoted_buffer) = 0;
|
||||
cf_lval.t = cfg_strdup(quoted_buffer_data);
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
["][^"\n]*\n cf_error("Unterminated string");
|
||||
<QUOTED>. BUFFER_PUSH(quoted_buffer) = yytext[0];
|
||||
|
||||
<INITIAL,COMMENT><<EOF>> { if (check_eof()) return END; }
|
||||
|
||||
@ -349,7 +375,7 @@ else: {
|
||||
%%
|
||||
|
||||
static uint
|
||||
cf_hash(byte *c)
|
||||
cf_hash(const byte *c)
|
||||
{
|
||||
uint h = 13 << 24;
|
||||
|
||||
@ -358,7 +384,6 @@ cf_hash(byte *c)
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IFS stack - it contains structures needed for recursive processing
|
||||
* of include in config files. On the top of the stack is a structure
|
||||
@ -519,7 +544,7 @@ check_eof(void)
|
||||
}
|
||||
|
||||
static struct symbol *
|
||||
cf_new_symbol(byte *c)
|
||||
cf_new_symbol(const byte *c)
|
||||
{
|
||||
struct symbol *s;
|
||||
|
||||
@ -527,11 +552,8 @@ cf_new_symbol(byte *c)
|
||||
if (l > SYM_MAX_LEN)
|
||||
cf_error("Symbol too long");
|
||||
|
||||
s = cfg_alloc(sizeof(struct symbol) + l);
|
||||
s->scope = conf_this_scope;
|
||||
s->class = SYM_VOID;
|
||||
s->def = NULL;
|
||||
s->aux = 0;
|
||||
s = cfg_allocz(sizeof(struct symbol) + l + 1);
|
||||
*s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
|
||||
strcpy(s->name, c);
|
||||
|
||||
if (!new_config->sym_hash.data)
|
||||
@ -539,6 +561,8 @@ cf_new_symbol(byte *c)
|
||||
|
||||
HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
|
||||
|
||||
add_tail(&(new_config->symbols), &(s->n));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -554,7 +578,7 @@ cf_new_symbol(byte *c)
|
||||
* signify no match.
|
||||
*/
|
||||
struct symbol *
|
||||
cf_find_symbol(struct config *cfg, byte *c)
|
||||
cf_find_symbol(const struct config *cfg, const byte *c)
|
||||
{
|
||||
struct symbol *s;
|
||||
|
||||
@ -562,6 +586,7 @@ cf_find_symbol(struct config *cfg, byte *c)
|
||||
(s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
|
||||
return s;
|
||||
|
||||
/* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */
|
||||
if (cfg->fallback &&
|
||||
cfg->fallback->sym_hash.data &&
|
||||
(s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
|
||||
@ -580,11 +605,33 @@ cf_find_symbol(struct config *cfg, byte *c)
|
||||
* existing symbol is found.
|
||||
*/
|
||||
struct symbol *
|
||||
cf_get_symbol(byte *c)
|
||||
cf_get_symbol(const byte *c)
|
||||
{
|
||||
return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* cf_localize_symbol - get the local instance of given symbol
|
||||
* @sym: the symbol to localize
|
||||
*
|
||||
* This functions finds the symbol that is local to current scope
|
||||
* for purposes of cf_define_symbol().
|
||||
*/
|
||||
struct symbol *
|
||||
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");
|
||||
|
||||
/* Not allocated here yet, doing it now. */
|
||||
return cf_new_symbol(sym->name);
|
||||
}
|
||||
|
||||
struct symbol *
|
||||
cf_default_name(char *template, int *counter)
|
||||
{
|
||||
@ -604,33 +651,32 @@ cf_default_name(char *template, int *counter)
|
||||
cf_error("Unable to generate default name");
|
||||
}
|
||||
|
||||
/**
|
||||
* cf_define_symbol - define meaning of a symbol
|
||||
* @sym: symbol to be defined
|
||||
* @type: symbol class to assign
|
||||
* @def: class dependent data
|
||||
*
|
||||
* Defines new meaning of a symbol. If the symbol is an undefined
|
||||
* one (%SYM_VOID), it's just re-defined to the new type. If it's defined
|
||||
* in different scope, a new symbol in current scope is created and the
|
||||
* meaning is assigned to it. If it's already defined in the current scope,
|
||||
* an error is reported via cf_error().
|
||||
*
|
||||
* Result: Pointer to the newly defined symbol. If we are in the top-level
|
||||
* scope, it's the same @sym as passed to the function.
|
||||
*/
|
||||
struct symbol *
|
||||
cf_define_symbol(struct symbol *sym, int type, void *def)
|
||||
static enum yytokentype
|
||||
cf_lex_symbol(const char *data)
|
||||
{
|
||||
if (sym->class)
|
||||
/* Have we defined such a symbol? */
|
||||
struct symbol *sym = cf_get_symbol(data);
|
||||
cf_lval.s = sym;
|
||||
|
||||
if (sym->class != SYM_VOID)
|
||||
return CF_SYM_KNOWN;
|
||||
|
||||
/* Is it a keyword? */
|
||||
struct keyword *k = HASH_FIND(kw_hash, KW, data);
|
||||
if (k)
|
||||
{
|
||||
if (k->value > 0)
|
||||
return k->value;
|
||||
else
|
||||
{
|
||||
if (sym->scope == conf_this_scope)
|
||||
cf_error("Symbol already defined");
|
||||
sym = cf_new_symbol(sym->name);
|
||||
cf_lval.i = -k->value;
|
||||
return ENUM;
|
||||
}
|
||||
sym->class = type;
|
||||
sym->def = def;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* OK, undefined symbol */
|
||||
cf_lval.s = sym;
|
||||
return CF_SYM_UNDEFINED;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -697,6 +743,7 @@ cf_push_scope(struct symbol *sym)
|
||||
conf_this_scope = s;
|
||||
s->active = 1;
|
||||
s->name = sym;
|
||||
s->slots = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -711,6 +758,7 @@ cf_pop_scope(void)
|
||||
{
|
||||
conf_this_scope->active = 0;
|
||||
conf_this_scope = conf_this_scope->next;
|
||||
|
||||
ASSERT(conf_this_scope);
|
||||
}
|
||||
|
||||
@ -724,9 +772,6 @@ cf_pop_scope(void)
|
||||
char *
|
||||
cf_symbol_class_name(struct symbol *sym)
|
||||
{
|
||||
if (cf_symbol_is_constant(sym))
|
||||
return "constant";
|
||||
|
||||
switch (sym->class)
|
||||
{
|
||||
case SYM_VOID:
|
||||
@ -741,6 +786,12 @@ cf_symbol_class_name(struct symbol *sym)
|
||||
return "filter";
|
||||
case SYM_TABLE:
|
||||
return "routing table";
|
||||
case SYM_ATTRIBUTE:
|
||||
return "custom attribute";
|
||||
case SYM_CONSTANT_RANGE:
|
||||
return "constant";
|
||||
case SYM_VARIABLE_RANGE:
|
||||
return "variable";
|
||||
default:
|
||||
return "unknown type";
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ config_alloc(const char *name)
|
||||
memcpy(ndup, name, nlen);
|
||||
|
||||
init_list(&c->tests);
|
||||
init_list(&c->symbols);
|
||||
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
|
||||
c->pool = p;
|
||||
c->mem = l;
|
||||
@ -258,6 +259,8 @@ config_do_commit(struct config *c, int type)
|
||||
if (old_config)
|
||||
old_config->obstacle_count++;
|
||||
|
||||
DBG("filter_commit\n");
|
||||
filter_commit(c, old_config);
|
||||
DBG("sysdep_commit\n");
|
||||
int force_restart = sysdep_commit(c, old_config);
|
||||
DBG("global_commit\n");
|
||||
|
61
conf/conf.h
61
conf/conf.h
@ -24,6 +24,7 @@ struct config {
|
||||
list tables; /* Configured routing tables (struct rtable_config) */
|
||||
list logfiles; /* Configured log files (sysdep) */
|
||||
list tests; /* Configured unit tests (f_bt_test_suite) */
|
||||
list symbols; /* Configured symbols in config order */
|
||||
|
||||
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
|
||||
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
|
||||
@ -107,18 +108,29 @@ void cfg_copy_list(list *dest, list *src, unsigned node_size);
|
||||
extern int (*cf_read_hook)(byte *buf, uint max, int fd);
|
||||
|
||||
struct symbol {
|
||||
node n; /* In list of symbols in config */
|
||||
struct symbol *next;
|
||||
struct sym_scope *scope;
|
||||
int class;
|
||||
int aux;
|
||||
void *aux2;
|
||||
void *def;
|
||||
char name[1];
|
||||
int class; /* SYM_* */
|
||||
uint flags; /* SYM_FLAG_* */
|
||||
|
||||
union {
|
||||
struct proto_config *proto; /* For SYM_PROTO and SYM_TEMPLATE */
|
||||
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 f_val *val; /* For SYM_CONSTANT */
|
||||
uint offset; /* For SYM_VARIABLE */
|
||||
};
|
||||
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct sym_scope {
|
||||
struct sym_scope *next; /* Next on scope stack */
|
||||
struct symbol *name; /* Name of this scope */
|
||||
uint slots; /* Variable slots */
|
||||
int active; /* Currently entered */
|
||||
};
|
||||
|
||||
@ -138,8 +150,11 @@ struct sym_scope {
|
||||
#define SYM_CONSTANT 0x200 /* 0x200-0x2ff are variable types */
|
||||
#define SYM_CONSTANT_RANGE SYM_CONSTANT ... (SYM_CONSTANT | 0xff)
|
||||
|
||||
#define SYM_TYPE(s) (((struct f_val *) (s)->def)->type)
|
||||
#define SYM_VAL(s) (((struct f_val *) (s)->def)->val)
|
||||
#define SYM_TYPE(s) ((s)->val->type)
|
||||
#define SYM_VAL(s) ((s)->val->val)
|
||||
|
||||
/* Symbol flags */
|
||||
#define SYM_FLAG_SAME 0x1 /* For SYM_FUNCTION and SYM_FILTER */
|
||||
|
||||
struct include_file_stack {
|
||||
void *buffer; /* Internal lexer state */
|
||||
@ -162,19 +177,37 @@ int cf_lex(void);
|
||||
void cf_lex_init(int is_cli, struct config *c);
|
||||
void cf_lex_unwind(void);
|
||||
|
||||
struct symbol *cf_find_symbol(struct config *cfg, byte *c);
|
||||
struct symbol *cf_find_symbol(const struct config *cfg, const byte *c);
|
||||
|
||||
struct symbol *cf_get_symbol(byte *c);
|
||||
struct symbol *cf_get_symbol(const byte *c);
|
||||
struct symbol *cf_default_name(char *template, int *counter);
|
||||
struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
|
||||
struct symbol *cf_localize_symbol(struct symbol *sym);
|
||||
|
||||
/**
|
||||
* cf_define_symbol - define meaning of a symbol
|
||||
* @sym: symbol to be defined
|
||||
* @type: symbol class to assign
|
||||
* @def: class dependent data
|
||||
*
|
||||
* Defines new meaning of a symbol. If the symbol is an undefined
|
||||
* one (%SYM_VOID), it's just re-defined to the new type. If it's defined
|
||||
* in different scope, a new symbol in current scope is created and the
|
||||
* meaning is assigned to it. If it's already defined in the current scope,
|
||||
* an error is reported via cf_error().
|
||||
*
|
||||
* Result: Pointer to the newly defined symbol. If we are in the top-level
|
||||
* scope, it's the same @sym as passed to the function.
|
||||
*/
|
||||
#define cf_define_symbol(sym_, type_, var_, def_) ({ \
|
||||
struct symbol *sym = cf_localize_symbol(sym_); \
|
||||
sym->class = type_; \
|
||||
sym->var_ = def_; \
|
||||
sym; })
|
||||
|
||||
void cf_push_scope(struct symbol *);
|
||||
void cf_pop_scope(void);
|
||||
char *cf_symbol_class_name(struct symbol *sym);
|
||||
|
||||
static inline int cf_symbol_is_constant(struct symbol *sym)
|
||||
{ return (sym->class & 0xff00) == SYM_CONSTANT; }
|
||||
|
||||
|
||||
/* Parser */
|
||||
|
||||
extern char *cf_text;
|
||||
|
@ -33,6 +33,21 @@ check_u16(uint val)
|
||||
cf_error("Value %u out of range (0-65535)", val);
|
||||
}
|
||||
|
||||
#define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
|
||||
static inline void cf_assert_symbol(const struct symbol *sym, uint class) {
|
||||
switch (class) {
|
||||
case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break;
|
||||
case SYM_TEMPLATE: cf_assert(sym->class == SYM_TEMPLATE, "Protocol template name required"); break;
|
||||
case SYM_FUNCTION: cf_assert(sym->class == SYM_FUNCTION, "Function name required"); break;
|
||||
case SYM_FILTER: cf_assert(sym->class == SYM_FILTER, "Filter name required"); break;
|
||||
case SYM_TABLE: cf_assert(sym->class == SYM_TABLE, "Table name required"); break;
|
||||
case SYM_ATTRIBUTE: cf_assert(sym->class == SYM_ATTRIBUTE, "Custom attribute name required"); break;
|
||||
case SYM_VARIABLE: cf_assert((sym->class & ~0xff) == SYM_VARIABLE, "Variable name required"); break;
|
||||
case SYM_CONSTANT: cf_assert((sym->class & ~0xff) == SYM_CONSTANT, "Constant name required"); break;
|
||||
default: bug("This shall not happen");
|
||||
}
|
||||
}
|
||||
|
||||
CF_DECLS
|
||||
|
||||
%union {
|
||||
@ -49,13 +64,19 @@ CF_DECLS
|
||||
struct rtable_config *r;
|
||||
struct channel_config *cc;
|
||||
struct f_inst *x;
|
||||
struct {
|
||||
struct f_inst *begin, *end;
|
||||
} xp;
|
||||
enum filter_return fret;
|
||||
enum ec_subtype ecs;
|
||||
struct f_dynamic_attr fda;
|
||||
struct f_static_attr fsa;
|
||||
struct filter *f;
|
||||
struct f_lval flv;
|
||||
struct f_line *fl;
|
||||
const struct filter *f;
|
||||
struct f_tree *e;
|
||||
struct f_trie *trie;
|
||||
struct f_val v;
|
||||
struct f_path_mask *h;
|
||||
struct password_item *p;
|
||||
struct rt_show_data *ra;
|
||||
struct sym_show_data *sd;
|
||||
@ -78,7 +99,7 @@ CF_DECLS
|
||||
%token <ip4> IP4
|
||||
%token <ip6> IP6
|
||||
%token <i64> VPN_RD
|
||||
%token <s> SYM
|
||||
%token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
|
||||
%token <t> TEXT
|
||||
%type <iface> ipa_scope
|
||||
|
||||
@ -88,8 +109,10 @@ CF_DECLS
|
||||
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
|
||||
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
|
||||
%type <mls> label_stack_start label_stack
|
||||
%type <s> CF_SYM_VOID
|
||||
|
||||
%type <t> text opttext
|
||||
%type <s> symbol
|
||||
|
||||
%nonassoc PREFIX_DUMMY
|
||||
%left AND OR
|
||||
@ -99,6 +122,8 @@ CF_DECLS
|
||||
%left '!'
|
||||
%nonassoc '.'
|
||||
|
||||
%start config
|
||||
|
||||
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
|
||||
|
||||
CF_GRAMMAR
|
||||
@ -122,29 +147,31 @@ conf: ';' ;
|
||||
conf: definition ;
|
||||
|
||||
definition:
|
||||
DEFINE SYM '=' term ';' {
|
||||
DEFINE CF_SYM_VOID '=' term ';' {
|
||||
struct f_val *val = cfg_alloc(sizeof(struct f_val));
|
||||
*val = f_eval($4, cfg_mem);
|
||||
if (val->type == T_RETURN) cf_error("Runtime error");
|
||||
cf_define_symbol($2, SYM_CONSTANT | val->type, val);
|
||||
if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
|
||||
cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
|
||||
}
|
||||
;
|
||||
|
||||
expr:
|
||||
NUM
|
||||
| '(' term ')' { $$ = f_eval_int($2); }
|
||||
| SYM {
|
||||
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
|
||||
| '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
|
||||
| CF_SYM_KNOWN {
|
||||
if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
|
||||
$$ = SYM_VAL($1).i; }
|
||||
;
|
||||
|
||||
|
||||
expr_us:
|
||||
expr S { $$ = $1 S_; }
|
||||
| expr MS { $$ = $1 MS_; }
|
||||
| expr US { $$ = $1 US_; }
|
||||
;
|
||||
|
||||
CF_SYM_VOID: CF_SYM_UNDEFINED ;
|
||||
|
||||
symbol: CF_SYM_VOID | CF_SYM_KNOWN ;
|
||||
|
||||
/* Switches */
|
||||
|
||||
bool:
|
||||
@ -162,15 +189,15 @@ bool:
|
||||
ipa:
|
||||
IP4 { $$ = ipa_from_ip4($1); }
|
||||
| IP6 { $$ = ipa_from_ip6($1); }
|
||||
| SYM {
|
||||
if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected");
|
||||
| CF_SYM_KNOWN {
|
||||
if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected");
|
||||
$$ = SYM_VAL($1).ip;
|
||||
}
|
||||
;
|
||||
|
||||
ipa_scope:
|
||||
/* empty */ { $$ = NULL; }
|
||||
| '%' SYM { $$ = if_get_by_name($2->name); }
|
||||
| '%' symbol { $$ = if_get_by_name($2->name); }
|
||||
;
|
||||
|
||||
|
||||
@ -277,27 +304,27 @@ net_:
|
||||
|
||||
net_ip6:
|
||||
net_ip6_
|
||||
| SYM {
|
||||
| CF_SYM_KNOWN {
|
||||
if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
|
||||
cf_error("IPv6 network expected");
|
||||
cf_error("IPv6 network constant expected");
|
||||
$$ = * SYM_VAL($1).net;
|
||||
}
|
||||
;
|
||||
|
||||
net_ip:
|
||||
net_ip_
|
||||
| SYM {
|
||||
| CF_SYM_KNOWN {
|
||||
if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
|
||||
cf_error("IP network expected");
|
||||
cf_error("IP network constant expected");
|
||||
$$ = * SYM_VAL($1).net;
|
||||
}
|
||||
;
|
||||
|
||||
net_any:
|
||||
net_
|
||||
| SYM {
|
||||
| CF_SYM_KNOWN {
|
||||
if ($1->class != (SYM_CONSTANT | T_NET))
|
||||
cf_error("Network expected");
|
||||
cf_error("Network constant expected");
|
||||
$$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
|
||||
}
|
||||
;
|
||||
@ -307,13 +334,13 @@ net_or_ipa:
|
||||
| net_ip6_
|
||||
| IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
|
||||
| IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
|
||||
| SYM {
|
||||
| CF_SYM_KNOWN {
|
||||
if ($1->class == (SYM_CONSTANT | T_IP))
|
||||
net_fill_ip_host(&($$), SYM_VAL($1).ip);
|
||||
else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
|
||||
$$ = * SYM_VAL($1).net;
|
||||
else
|
||||
cf_error("IP address or network expected");
|
||||
cf_error("IP address or network constant expected");
|
||||
}
|
||||
;
|
||||
|
||||
@ -344,8 +371,8 @@ time:
|
||||
|
||||
text:
|
||||
TEXT
|
||||
| SYM {
|
||||
if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected");
|
||||
| CF_SYM_KNOWN {
|
||||
if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
|
||||
$$ = SYM_VAL($1).s;
|
||||
}
|
||||
;
|
||||
|
24
configure.ac
24
configure.ac
@ -18,6 +18,12 @@ AC_ARG_ENABLE([debug],
|
||||
[enable_debug=no]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([debug-generated],
|
||||
[AS_HELP_STRING([--enable-debug-generated], [enable this to abstain from generating #line @<:@no@:>@])],
|
||||
[],
|
||||
[enable_debug_generated=no]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([memcheck],
|
||||
[AS_HELP_STRING([--enable-memcheck], [check memory allocations when debugging @<:@yes@:>@])],
|
||||
[],
|
||||
@ -109,6 +115,11 @@ if test -z "$GCC" ; then
|
||||
AC_MSG_ERROR([This program requires the GNU C Compiler.])
|
||||
fi
|
||||
|
||||
BIRD_CHECK_THREAD_LOCAL
|
||||
if test "$bird_cv_thread_local" = yes ; then
|
||||
AC_DEFINE([HAVE_THREAD_LOCAL], [1], [Define to 1 if _Thread_local is available])
|
||||
fi
|
||||
|
||||
if test "$enable_pthreads" != no ; then
|
||||
BIRD_CHECK_PTHREADS
|
||||
|
||||
@ -141,6 +152,14 @@ fi
|
||||
AC_MSG_CHECKING([CFLAGS])
|
||||
AC_MSG_RESULT([$CFLAGS])
|
||||
|
||||
if test "$enable_debug" = no; then
|
||||
BIRD_CHECK_LTO
|
||||
fi
|
||||
|
||||
if test "$bird_cv_c_lto" = yes; then
|
||||
CFLAGS="$CFLAGS -flto"
|
||||
LDFLAGS="$LDFLAGS -flto"
|
||||
fi
|
||||
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
@ -156,7 +175,7 @@ test -z "$M4" && AC_MSG_ERROR([M4 is missing.])
|
||||
AC_MSG_CHECKING([bison version])
|
||||
BIRD_CHECK_BISON_VERSION(BISON_VERSION)
|
||||
AC_MSG_RESULT([$BISON_VERSION])
|
||||
if test "$bird_bison_synclines" = yes; then
|
||||
if test "$bird_bison_synclines" = yes && test "$enable_debug_generated" = no; then
|
||||
M4FLAGS="$M4FLAGS -s"
|
||||
fi
|
||||
|
||||
@ -364,6 +383,9 @@ if test "$enable_debug" = yes ; then
|
||||
AC_CHECK_LIB([efence], [malloc])
|
||||
fi
|
||||
fi
|
||||
else
|
||||
BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_implicit_fallthrough], [-Wno-implicit-fallthrough])
|
||||
BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_implicit_fallthrough], [-Wno-implicit-fallthrough])
|
||||
fi
|
||||
|
||||
CLIENT=birdcl
|
||||
|
@ -1,8 +1,24 @@
|
||||
src := filter.c f-util.c tree.c trie.c
|
||||
src := filter.c data.c f-util.c tree.c trie.c inst-gen.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
|
||||
#M4FLAGS_FILTERS=$(filter-out -s,$(M4FLAGS))
|
||||
M4FLAGS_FILTERS=$(M4FLAGS)
|
||||
|
||||
$(o)inst-gen.h: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -DTARGET=H -P $^ >$@
|
||||
|
||||
$(o)inst-gen.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -DTARGET=C -P $^ >$@
|
||||
|
||||
$(o)inst-interpret.c: $(s)decl.m4 $(s)f-inst.c $(objdir)/.dir-stamp
|
||||
$(M4) $(M4FLAGS_FILTERS) -DTARGET=I -P $^ >$@
|
||||
|
||||
prepare: $(o)inst-interpret.c $(o)inst-gen.h
|
||||
|
||||
tests_src := tree_test.c filter_test.c trie_test.c
|
||||
tests_targets := $(tests_targets) $(tests-target-files)
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
||||
$(call clean,inst-gen.h inst-gen.c inst-interpret.c)
|
||||
|
752
filter/config.Y
752
filter/config.Y
File diff suppressed because it is too large
Load Diff
537
filter/data.c
Normal file
537
filter/data.c
Normal file
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* Filters: utility functions
|
||||
*
|
||||
* (c) 1998 Pavel Machek <pavel@ucw.cz>
|
||||
* (c) 2019 Maria Matejka <mq@jmq.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/lists.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/socket.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/unaligned.h"
|
||||
#include "lib/net.h"
|
||||
#include "lib/ip.h"
|
||||
#include "nest/route.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/iface.h"
|
||||
#include "nest/attrs.h"
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
#include "filter/f-inst.h"
|
||||
#include "filter/data.h"
|
||||
|
||||
const struct f_val f_const_empty_path = {
|
||||
.type = T_PATH,
|
||||
.val.ad = &null_adata,
|
||||
}, f_const_empty_clist = {
|
||||
.type = T_CLIST,
|
||||
.val.ad = &null_adata,
|
||||
}, f_const_empty_eclist = {
|
||||
.type = T_ECLIST,
|
||||
.val.ad = &null_adata,
|
||||
}, f_const_empty_lclist = {
|
||||
.type = T_LCLIST,
|
||||
.val.ad = &null_adata,
|
||||
};
|
||||
|
||||
static struct adata *
|
||||
adata_empty(struct linpool *pool, int l)
|
||||
{
|
||||
struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
|
||||
res->length = l;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
pm_format(const struct f_path_mask *p, buffer *buf)
|
||||
{
|
||||
buffer_puts(buf, "[= ");
|
||||
|
||||
for (uint i=0; i<p->len; i++)
|
||||
{
|
||||
switch(p->item[i].kind)
|
||||
{
|
||||
case PM_ASN:
|
||||
buffer_print(buf, "%u ", p->item[i].asn);
|
||||
break;
|
||||
|
||||
case PM_QUESTION:
|
||||
buffer_puts(buf, "? ");
|
||||
break;
|
||||
|
||||
case PM_ASTERISK:
|
||||
buffer_puts(buf, "* ");
|
||||
break;
|
||||
|
||||
case PM_ASN_RANGE:
|
||||
buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
|
||||
break;
|
||||
|
||||
case PM_ASN_EXPR:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buffer_puts(buf, "=]");
|
||||
}
|
||||
|
||||
static inline int
|
||||
lcomm_cmp(lcomm v1, lcomm v2)
|
||||
{
|
||||
if (v1.asn != v2.asn)
|
||||
return (v1.asn > v2.asn) ? 1 : -1;
|
||||
if (v1.ldp1 != v2.ldp1)
|
||||
return (v1.ldp1 > v2.ldp1) ? 1 : -1;
|
||||
if (v1.ldp2 != v2.ldp2)
|
||||
return (v1.ldp2 > v2.ldp2) ? 1 : -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* val_compare - compare two values
|
||||
* @v1: first value
|
||||
* @v2: second value
|
||||
*
|
||||
* Compares two values and returns -1, 0, 1 on <, =, > or F_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(const struct f_val *v1, const struct f_val *v2)
|
||||
{
|
||||
if (v1->type != v2->type) {
|
||||
if (v1->type == T_VOID) /* Hack for else */
|
||||
return -1;
|
||||
if (v2->type == T_VOID)
|
||||
return 1;
|
||||
|
||||
/* IP->Quad implicit conversion */
|
||||
if ((v1->type == T_QUAD) && val_is_ip4(v2))
|
||||
return uint_cmp(v1->val.i, ipa_to_u32(v2->val.ip));
|
||||
if (val_is_ip4(v1) && (v2->type == T_QUAD))
|
||||
return uint_cmp(ipa_to_u32(v1->val.ip), v2->val.i);
|
||||
|
||||
debug( "Types do not match in val_compare\n" );
|
||||
return F_CMP_ERROR;
|
||||
}
|
||||
|
||||
switch (v1->type) {
|
||||
case T_VOID:
|
||||
return 0;
|
||||
case T_ENUM:
|
||||
case T_INT:
|
||||
case T_BOOL:
|
||||
case T_PAIR:
|
||||
case T_QUAD:
|
||||
return uint_cmp(v1->val.i, v2->val.i);
|
||||
case T_EC:
|
||||
case T_RD:
|
||||
return u64_cmp(v1->val.ec, v2->val.ec);
|
||||
case T_LC:
|
||||
return lcomm_cmp(v1->val.lc, v2->val.lc);
|
||||
case T_IP:
|
||||
return ipa_compare(v1->val.ip, v2->val.ip);
|
||||
case T_NET:
|
||||
return net_compare(v1->val.net, v2->val.net);
|
||||
case T_STRING:
|
||||
return strcmp(v1->val.s, v2->val.s);
|
||||
default:
|
||||
return F_CMP_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
pmi_same(const struct f_path_mask_item *mi1, const struct f_path_mask_item *mi2)
|
||||
{
|
||||
if (mi1->kind != mi2->kind)
|
||||
return 0;
|
||||
|
||||
switch (mi1->kind) {
|
||||
case PM_ASN:
|
||||
if (mi1->asn != mi2->asn)
|
||||
return 0;
|
||||
break;
|
||||
case PM_ASN_EXPR:
|
||||
if (!f_same(mi1->expr, mi2->expr))
|
||||
return 0;
|
||||
break;
|
||||
case PM_ASN_RANGE:
|
||||
if (mi1->from != mi2->from)
|
||||
return 0;
|
||||
if (mi1->to != mi2->to)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
|
||||
{
|
||||
if (m1->len != m2->len)
|
||||
|
||||
for (uint i=0; i<m1->len; i++)
|
||||
if (!pmi_same(&(m1->item[i]), &(m2->item[i])))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(const struct f_val *v1, const struct f_val *v2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = val_compare(v1, v2);
|
||||
if (rc != F_CMP_ERROR)
|
||||
return !rc;
|
||||
|
||||
if (v1->type != v2->type)
|
||||
return 0;
|
||||
|
||||
switch (v1->type) {
|
||||
case T_PATH_MASK:
|
||||
return pm_same(v1->val.path_mask, v2->val.path_mask);
|
||||
case T_PATH_MASK_ITEM:
|
||||
return pmi_same(&(v1->val.pmi), &(v2->val.pmi));
|
||||
case T_PATH:
|
||||
case T_CLIST:
|
||||
case T_ECLIST:
|
||||
case T_LCLIST:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
clist_set_type(const struct f_tree *set, struct f_val *v)
|
||||
{
|
||||
switch (set->from.type)
|
||||
{
|
||||
case T_PAIR:
|
||||
v->type = T_PAIR;
|
||||
return 1;
|
||||
|
||||
case T_QUAD:
|
||||
v->type = T_QUAD;
|
||||
return 1;
|
||||
|
||||
case T_IP:
|
||||
if (val_is_ip4(&(set->from)) && val_is_ip4(&(set->to)))
|
||||
{
|
||||
v->type = T_QUAD;
|
||||
return 1;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
v->type = T_VOID;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
clist_match_set(const struct adata *clist, const struct f_tree *set)
|
||||
{
|
||||
if (!clist)
|
||||
return 0;
|
||||
|
||||
struct f_val v;
|
||||
if (!clist_set_type(set, &v))
|
||||
return F_CMP_ERROR;
|
||||
|
||||
u32 *l = (u32 *) clist->data;
|
||||
u32 *end = l + clist->length/4;
|
||||
|
||||
while (l < end) {
|
||||
v.val.i = *l++;
|
||||
if (find_tree(set, &v))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
eclist_match_set(const struct adata *list, const struct f_tree *set)
|
||||
{
|
||||
if (!list)
|
||||
return 0;
|
||||
|
||||
if (!eclist_set_type(set))
|
||||
return F_CMP_ERROR;
|
||||
|
||||
struct f_val v;
|
||||
u32 *l = int_set_get_data(list);
|
||||
int len = int_set_get_size(list);
|
||||
int i;
|
||||
|
||||
v.type = T_EC;
|
||||
for (i = 0; i < len; i += 2) {
|
||||
v.val.ec = ec_get(l, i);
|
||||
if (find_tree(set, &v))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lclist_match_set(const struct adata *list, const struct f_tree *set)
|
||||
{
|
||||
if (!list)
|
||||
return 0;
|
||||
|
||||
if (!lclist_set_type(set))
|
||||
return F_CMP_ERROR;
|
||||
|
||||
struct f_val v;
|
||||
u32 *l = int_set_get_data(list);
|
||||
int len = int_set_get_size(list);
|
||||
int i;
|
||||
|
||||
v.type = T_LC;
|
||||
for (i = 0; i < len; i += 3) {
|
||||
v.val.lc = lc_get(l, i);
|
||||
if (find_tree(set, &v |