diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2010-03-11 18:55:59 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2010-03-11 18:55:59 +0100 |
commit | 54305181f6ee3af57dd3d15d53ea2e851b36ed23 (patch) | |
tree | a5aed631b68df033cba372f841d47a0cba5d7021 | |
parent | e7b76b976084006e430543f4b872f624326dbfe6 (diff) | |
parent | afa9f66c27e2f96b92059131def53cc7b2497705 (diff) | |
download | bird-54305181f6ee3af57dd3d15d53ea2e851b36ed23.tar bird-54305181f6ee3af57dd3d15d53ea2e851b36ed23.zip |
Merge branch 'new' into socket2
64 files changed, 936 insertions, 798 deletions
@@ -5,6 +5,7 @@ Version 1.2.1 (2010-02-11) o Adds router ID of advertising router as OSPF route attribute. o 'show route' command indicates primary route and shows OSPF Router ID. o Configurable date/time formats. + o Symbol names can be enclosed by '' and so include hyphen and start with number. o Several minor bugfixes. Version 1.2.0 (2010-01-05) diff --git a/client/client.c b/client/client.c index 88a6095..9acabf2 100644 --- a/client/client.c +++ b/client/client.c @@ -25,8 +25,10 @@ #include "client/client.h" #include "sysdep/unix/unix.h" -static char *opt_list = "s:v"; +static char *opt_list = "s:vr"; static int verbose; +static char *init_cmd; +static int once; static char *server_path = PATH_CONTROL_SOCKET; static int server_fd; @@ -49,7 +51,7 @@ static int num_lines, skip_input, interactive; static void usage(void) { - fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v]\n"); + fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v] [-r]\n"); exit(1); } @@ -67,11 +69,36 @@ parse_args(int argc, char **argv) case 'v': verbose++; break; + case 'r': + init_cmd = "restrict"; + break; default: usage(); } + + /* If some arguments are not options, we take it as commands */ if (optind < argc) - usage(); + { + char *tmp; + int i; + int len = 0; + + if (init_cmd) + usage(); + + for (i = optind; i < argc; i++) + len += strlen(argv[i]) + 1; + + tmp = init_cmd = malloc(len); + for (i = optind; i < argc; i++) + { + strcpy(tmp, argv[i]); + tmp += strlen(tmp); + *tmp++ = ' '; + } + + once = 1; + } } /*** Input ***/ @@ -267,11 +294,29 @@ update_state(void) if (nstate == cstate) return; + if (init_cmd) + { + /* First transition - client received hello from BIRD + and there is waiting initial command */ + submit_server_command(init_cmd); + init_cmd = NULL; + return; + } + + if (!init_cmd && once) + { + /* Initial command is finished and we want to exit */ + cleanup(); + exit(0); + } + if (nstate == STATE_PROMPT) - if (input_initialized) - input_reveal(); - else - input_init(); + { + if (input_initialized) + input_reveal(); + else + input_init(); + } if (nstate != STATE_PROMPT) input_hide(); @@ -329,6 +374,8 @@ server_connect(void) die("fcntl: %m"); } +#define PRINTF(LEN, PARGS...) do { if (!skip_input) len = printf(PARGS); } while(0) + static void server_got_reply(char *x) { @@ -336,15 +383,15 @@ server_got_reply(char *x) int len = 0; if (*x == '+') /* Async reply */ - skip_input || (len = printf(">>> %s\n", x+1)); + PRINTF(len, ">>> %s\n", x+1); else if (x[0] == ' ') /* Continuation */ - skip_input || (len = printf("%s%s\n", verbose ? " " : "", x+1)); + PRINTF(len, "%s%s\n", verbose ? " " : "", x+1); else if (strlen(x) > 4 && sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 && (x[4] == ' ' || x[4] == '-')) { if (code) - skip_input || (len = printf("%s\n", verbose ? x : x+5)); + PRINTF(len, "%s\n", verbose ? x : x+5); if (x[4] == ' ') { nstate = STATE_PROMPT; @@ -353,7 +400,7 @@ server_got_reply(char *x) } } else - skip_input || (len = printf("??? <%s>\n", x)); + PRINTF(len, "??? <%s>\n", x); if (skip_input) return; diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 04b0c60..3fe3c2e 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -33,6 +33,7 @@ #include "nest/bird.h" #include "nest/route.h" +#include "nest/protocol.h" #include "filter/filter.h" #include "conf/conf.h" #include "conf/cf-parse.tab.h" diff --git a/conf/confbase.Y b/conf/confbase.Y index b65d608..2d95a0d 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -42,6 +42,7 @@ CF_DECLS void *g; bird_clock_t time; struct prefix px; + struct proto_spec ps; struct timeformat *tf; } diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 34a0011..cf3fb58 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -23,7 +23,7 @@ m4_define(CF_DECLS, `m4_divert(-1)') m4_define(CF_DEFINES, `m4_divert(-1)') # Keywords are translated to C initializers -m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1 }, +m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, NULL }, m4_divert(-1)') m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($1)]])') m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks @@ -34,7 +34,7 @@ m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) ') # Enums are translated to C initializers: use CF_ENUM(typename, prefix, values) -m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix[[]]$1) }, +m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix[[]]$1), NULL }, m4_divert(-1)') m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL') @@ -42,7 +42,7 @@ m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix]],$ m4_m4wrap(` m4_divert(0) static struct keyword keyword_list[] = { -m4_undivert(1){ NULL, -1 } }; +m4_undivert(1){ NULL, -1, NULL } }; ') # As we are processing C source, we must access all M4 primitives via diff --git a/configure.in b/configure.in index ec2417b..c931c18 100644 --- a/configure.in +++ b/configure.in @@ -8,7 +8,6 @@ AC_CONFIG_AUX_DIR(tools) AC_ARG_ENABLE(debug,[ --enable-debug enable internal debugging routines (default: disabled)],,enable_debug=no) AC_ARG_ENABLE(memcheck,[ --enable-memcheck check memory allocations when debugging (default: enabled)],,enable_memcheck=yes) -AC_ARG_ENABLE(warnings,[ --enable-warnings enable extra warnings (default: disabled)],,enable_warnings=no) AC_ARG_ENABLE(client,[ --enable-client enable building of BIRD client (default: enabled)],,enable_client=yes) AC_ARG_ENABLE(ipv6,[ --enable-ipv6 enable building of IPv6 version (default: disabled)],,enable_ipv6=no) AC_ARG_WITH(sysconfig,[ --with-sysconfig=FILE use specified BIRD system configuration file]) @@ -56,24 +55,17 @@ AC_SEARCH_LIBS(clock_gettime,[c rt posix4]) AC_CANONICAL_HOST -AC_PROG_CC -if test -z "$GCC" ; then - AC_MSG_ERROR([This program requires the GNU C Compiler.]) - fi AC_MSG_CHECKING([what CFLAGS should we use]) if test "$ac_test_CFLAGS" != set ; then - if test "$enable_warnings" = yes ; then - WARNS=" -Wmissing-prototypes -Wundef" - else - WARNS=" -Wno-unused" - fi - CFLAGS="$CFLAGS -Wall -W -Wstrict-prototypes -Wno-pointer-sign -Wno-parentheses$WARNS" -fi -if test "$with_sysinclude" != no -a -n "$with_sysinclude"; then - CPPFLAGS="$CPPFLAGS -I$with_sysinclude" + CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -Wno-pointer-sign -Wno-parentheses" fi AC_MSG_RESULT($CFLAGS) +AC_PROG_CC +if test -z "$GCC" ; then + AC_MSG_ERROR([This program requires the GNU C Compiler.]) +fi + AC_PROG_CPP AC_PROG_INSTALL AC_PROG_RANLIB diff --git a/doc/bird.conf.example b/doc/bird.conf.example index 51b2c0e..c710512 100644 --- a/doc/bird.conf.example +++ b/doc/bird.conf.example @@ -96,9 +96,9 @@ protocol static { # honor neighbor; # To whom do we agree to send the routing table # honor always; # honor never; -# passwords { password "ahoj" from 0 to 10; -# password "nazdar" from 10; -# } +# passwords { +# password "nazdar"; +# }; # authentication none; # import filter { print "importing"; accept; }; # export filter { print "exporting"; accept; }; @@ -143,6 +143,7 @@ protocol static { # generate from "22-04-2003 11:00:07"; # accept from "17-01-2003 12:01:05"; # }; +# }; # authentication cryptographic; # }; # }; @@ -163,7 +164,7 @@ protocol static { #protocol bgp { # disabled; -# description "My BGP uplink" +# description "My BGP uplink"; # local as 65000; # neighbor 62.168.0.130 as 5588; # multihop 20 via 62.168.0.13; @@ -181,17 +182,17 @@ protocol static { # default bgp_med 0; # MED value we use for comparison when none is defined # default bgp_local_pref 0; # The same for local preference # source address 62.168.0.14; # What local address we use for the TCP connection -# password "secret" # Password used for MD5 authentication +# password "secret"; # Password used for MD5 authentication # rr client; # I am a route reflector and the neighor is my client -# rr cluster id 1.0.0.1 # Use this value for cluster id instead of my router id +# rr cluster id 1.0.0.1; # Use this value for cluster id instead of my router id # export where source=RTS_STATIC; # export filter { # if source = RTS_STATIC then { -## bgp_community = -empty-; bgp_community = add(bgp_community,(65000,5678)); -## bgp_origin = 0; +# bgp_community = -empty-; bgp_community = add(bgp_community,(65000,5678)); +# bgp_origin = 0; # bgp_community = -empty-; bgp_community.add((65000,5678)); -## if (65000,5678) ~ bgp_community then -## bgp_community.add((0, 1)); +# if (65000,5678) ~ bgp_community then +# bgp_community.add((0, 1)); # if bgp_path ~ [= 65000 =] then # bgp_path.prepend(65000); # accept; diff --git a/doc/bird.sgml b/doc/bird.sgml index 3d82e45..b70f034 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -824,7 +824,14 @@ defined by using the <cf>defined( <m>attribute</m> )</cf> operator. Network the route is talking about. Read-only. (See the chapter about routing tables.) <tag><m/enum/ scope</tag> - Address scope of the network (<cf/SCOPE_HOST/ for addresses local to this host, <cf/SCOPE_LINK/ for those specific for a physical link, <cf/SCOPE_SITE/ and <cf/SCOPE_ORGANIZATION/ for private addresses, <cf/SCOPE_UNIVERSE/ for globally visible addresses). + The scope of the route. Possible values: <cf/SCOPE_HOST/ for + routes local to this host, <cf/SCOPE_LINK/ for those specific + for a physical link, <cf/SCOPE_SITE/ and + <cf/SCOPE_ORGANIZATION/ for private routes and + <cf/SCOPE_UNIVERSE/ for globally visible routes. This + attribute is not interpreted by BIRD and can be used to mark + routes in filters. The default value for new routes is + <cf/SCOPE_UNIVERSE/. <tag><m/int/ preference</tag> Preference of the route. Valid values are 0-65535. (See the chapter about routing tables.) @@ -842,7 +849,11 @@ defined by using the <cf>defined( <m>attribute</m> )</cf> operator. what protocol has told me about this route. Possible values: <cf/RTS_DUMMY/, <cf/RTS_STATIC/, <cf/RTS_INHERIT/, <cf/RTS_DEVICE/, <cf/RTS_STATIC_DEVICE/, <cf/RTS_REDIRECT/, <cf/RTS_RIP/, <cf/RTS_OSPF/, <cf/RTS_OSPF_IA/, <cf/RTS_OSPF_EXT/, <cf/RTS_BGP/, <cf/RTS_PIPE/. <tag><m/enum/ cast</tag> - Route type (<cf/RTC_UNICAST/ for normal routes, <cf/RTC_BROADCAST/, <cf/RTC_MULTICAST/, <cf/RTC_ANYCAST/ for broadcast, multicast and anycast routes). Read-only. + + Route type (Currently <cf/RTC_UNICAST/ for normal routes, + <cf/RTC_BROADCAST/, <cf/RTC_MULTICAST/, <cf/RTC_ANYCAST/ will + be used in the future for broadcast, multicast and anycast + routes). Read-only. <tag><m/enum/ dest</tag> Type of destination the packets should be sent to (<cf/RTD_ROUTER/ for forwarding to a neighboring router, <cf/RTD_NETWORK/ for routing to a directly-connected network, <cf/RTD_BLACKHOLE/ for packets to be silently discarded, <cf/RTD_UNREACHABLE/, <cf/RTD_PROHIBIT/ for packets that should be returned with ICMP host unreachable / ICMP administratively prohibited messages). Read-only. diff --git a/doc/reply_codes b/doc/reply_codes index db760fb..22e0fd2 100644 --- a/doc/reply_codes +++ b/doc/reply_codes @@ -24,6 +24,7 @@ Reply codes of BIRD command-line interface 0013 Status report 0014 Route count 0015 Reloading +0016 Access restricted 1000 BIRD version 1001 Interface list @@ -51,6 +52,7 @@ Reply codes of BIRD command-line interface 8004 Stopped due to reconfiguration 8005 Protocol is down => cannot dump 8006 Reload failed +8007 Access denied 9000 Command too long 9001 Parse error diff --git a/filter/config.Y b/filter/config.Y index f8674e5..fcbee71 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -273,16 +273,17 @@ fprefix_set: ; switch_body: /* EMPTY */ { $$ = NULL; } - | set_item ':' cmds switch_body { - $$ = $1; - $$->data = $3; - $$->left = $4; + | switch_body set_item ':' cmds { + $$ = $2; + $$->data = $4; + $$->left = $1; } - | ELSE ':' cmds { + | switch_body ELSE ':' cmds { $$ = f_new_tree(); $$->from.type = T_VOID; $$->to.type = T_VOID; - $$->data = $3; + $$->data = $4; + $$->left = $1; } ; diff --git a/filter/filter.c b/filter/filter.c index b88039f..ec155ee 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -164,6 +164,11 @@ val_compare(struct f_val v1, struct f_val v2) } } +int +tree_compare(const void *p1, const void *p2) +{ + return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from); +} void f_prefix_get_bounds(struct f_prefix *px, int *l, int *h) diff --git a/filter/filter.h b/filter/filter.h index e526a79..11e0623 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -91,6 +91,7 @@ void f_prefix_get_bounds(struct f_prefix *px, int *l, int *h); void f_prefix_get_bounds(struct f_prefix *px, int *l, int *h); int val_compare(struct f_val v1, struct f_val v2); +int tree_compare(const void *p1, const void *p2); void val_print(struct f_val v); #define F_NOP 0 diff --git a/filter/test.conf b/filter/test.conf index fb35afb..395699b 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -131,6 +131,9 @@ prefix px; ip p; pair pp; int set is; +int set is1; +int set is2; +int set is3; prefix set pxs; string s; { @@ -156,6 +159,18 @@ string s; print " must be true: ", defined(1), ",", defined(1.2.3.4), ",", 1 != 2, ",", 1 <= 2; print " data types: must be false: ", 1 ~ [ 2, 3, 4 ], ",", 5 ~ is, ",", 1.2.3.4 ~ [ 1.2.3.3, 1.2.3.5 ], ",", (1,2) > (2,2), ",", (1,1) > (1,1), ",", 1.0.0.0/9 ~ [ 1.0.0.0/8- ], ",", 1.2.0.0/17 ~ [ 1.0.0.0/8{ 15 , 16 } ], ",", true && false; + is1 = [2, 3, 5, 8, 11, 15, 17, 19]; + is2 = [19, 17, 15, 11, 8, 5, 3, 2]; + is3 = [5, 17, 2, 11, 8, 15, 3, 19]; + + print " must be true: ", 2 ~ is1, " ", 2 ~ is2, " ", 2 ~ is3; + print " must be false: ", 4 ~ is1, " ", 4 ~ is2, " ", 4 ~ is3; + print " must be false: ", 10 ~ is1, " ", 10 ~ is2, " ", 10 ~ is3; + print " must be true: ", 15 ~ is1, " ", 15 ~ is2, " ", 15 ~ is3; + print " must be false: ", 18 ~ is1, " ", 18 ~ is2, " ", 18 ~ is3; + print " must be true: ", 19 ~ is1, " ", 19 ~ is2, " ", 19 ~ is3; + print " must be false: ", 20 ~ is1, " ", 20 ~ is2, " ", 20 ~ is3; + px = 1.2.0.0/18; print "Testing prefixes: 1.2.0.0/18 = ", px; print " must be true: ", 192.168.0.0/16 ~ 192.168.0.0/16, " ", 192.168.0.0/17 ~ 192.168.0.0/16, " ", 192.168.254.0/24 ~ 192.168.0.0/16; diff --git a/filter/tree.c b/filter/tree.c index a67ddd0..f6ab75b 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -6,61 +6,11 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#include "lib/alloca.h" #include "nest/bird.h" #include "conf/conf.h" #include "filter/filter.h" -/* - * find_nth - finds n-th element in linked list. Don't be confused by types, it is really a linked list. - */ -static struct f_tree * -find_nth(struct f_tree *from, int nth) -{ - struct f_tree *pivot; - int lcount = 0, rcount = 0; - struct f_tree *left, *right, *next; - - pivot = from; - - left = right = NULL; - next = from->right; - while (from = next) { - next = from->right; - if (val_compare(pivot->from, from->from)==1) { - from->right = left; - left = from; - lcount++; - } else { - from->right = right; - right = from; - rcount++; - } - } - if (lcount == nth) - return pivot; - if (lcount < nth) - return find_nth(right, nth-lcount-1); - return find_nth(left, nth); -} - -/* - * find_median - Gets list linked by @left, finds its median, trashes pointers in @right. - */ -static struct f_tree * -find_median(struct f_tree *from) -{ - struct f_tree *t = from; - int cnt = 0; - - if (!from) - return NULL; - do { - t->right = t->left; - cnt++; - } while (t = t->left); - return find_nth(from, cnt/2); -} - /** * find_tree * @t: tree to search in @@ -87,6 +37,23 @@ find_tree(struct f_tree *t, struct f_val val) return find_tree(t->left, val); } +static struct f_tree * +build_tree_rec(struct f_tree **buf, int l, int h) +{ + struct f_tree *n; + int pos; + + if (l >= h) + return NULL; + + pos = (l+h)/2; + n = buf[pos]; + n->left = build_tree_rec(buf, l, pos); + n->right = build_tree_rec(buf, pos+1, h); + return n; +} + + /** * build_tree * @from: degenerated tree (linked by @tree->left) to be transformed into form suitable for find_tree() @@ -96,29 +63,35 @@ find_tree(struct f_tree *t, struct f_val val) struct f_tree * build_tree(struct f_tree *from) { - struct f_tree *median, *t = from, *next, *left = NULL, *right = NULL; + struct f_tree *tmp, *root; + struct f_tree **buf; + int len, i; - median = find_median(from); - if (!median) + if (from == NULL) return NULL; - do { - next = t->left; - if (t == median) - continue; - - if (val_compare(median->from, t->from)==1) { - t->left = left; - left = t; - } else { - t->left = right; - right = t; - } - } while(t = next); - - median->left = build_tree(left); - median->right = build_tree(right); - return median; + len = 0; + for (tmp = from; tmp != NULL; tmp = tmp->left) + len++; + + if (len <= 1024) + buf = alloca(len * sizeof(struct f_tree *)); + else + buf = malloc(len * sizeof(struct f_tree *)); + + /* Convert a degenerated tree into an sorted array */ + i = 0; + for (tmp = from; tmp != NULL; tmp = tmp->left) + buf[i++] = tmp; + + qsort(buf, len, sizeof(struct f_tree *), tree_compare); + + root = build_tree_rec(buf, 0, len); + + if (len > 1024) + free(buf); + + return root; } struct f_tree * diff --git a/lib/event.c b/lib/event.c index d556cd0..ce5e81c 100644 --- a/lib/event.c +++ b/lib/event.c @@ -49,7 +49,8 @@ static struct resclass ev_class = { "Event", sizeof(event), (void (*)(resource *)) ev_postpone, - ev_dump + ev_dump, + NULL }; /** @@ -46,10 +46,14 @@ char *ip_scope_text(unsigned); struct prefix { ip_addr addr; - int len; + unsigned int len; }; #define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) +#define ipa_zero(x) (!ipa_nonzero(x)) + +static inline int ipa_classify_net(ip_addr a) +{ return ipa_zero(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } /* * Conversions between internal and string representation @@ -72,7 +72,7 @@ int ipv4_classify(u32); u32 ipv4_class_mask(u32); byte *ipv4_skip_header(byte *, int *); -static inline int ipv4_has_link_scope(u32 a) +static inline int ipv4_has_link_scope(u32 a UNUSED) { return 0; } diff --git a/lib/socket.h b/lib/socket.h index a21075e..e6ce125 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -9,6 +9,8 @@ #ifndef _BIRD_SOCKET_H_ #define _BIRD_SOCKET_H_ +#include <errno.h> + #include "lib/resource.h" typedef struct birdsock { @@ -67,6 +69,8 @@ int sk_leave_group(sock *s, ip_addr maddr); int sk_set_ipv6_checksum(sock *s, int offset); #endif +int sk_set_broadcast(sock *s, int enable); + static inline int sk_send_buffer_empty(sock *sk) { diff --git a/nest/a-path.c b/nest/a-path.c index 396d463..058b434 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -385,7 +385,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask) struct pm_pos pos[2048 + 1]; int plen = parse_path(path, pos); int l, h, i, nh, nl; - u32 val; + u32 val = 0; /* l and h are bound of interval of positions where are marked states */ @@ -417,7 +417,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask) goto step; case PM_QUESTION: step: - nh = -1; + nh = nl = -1; for (i = h; i >= l; i--) if (pos[i].mark) { @@ -357,8 +357,8 @@ cli_echo(unsigned int class, byte *msg) free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1); else free = c->ring_read - c->ring_write - 1; - if (len > free || - free < c->log_threshold && class < (unsigned) L_INFO[0]) + if ((len > free) || + (free < c->log_threshold && class < (unsigned) L_INFO[0])) { c->ring_overflow++; continue; @@ -33,6 +33,7 @@ typedef struct cli { void (*cleanup)(struct cli *c); void *rover; /* Private to continuation routine */ int last_reply; + int restricted; /* CLI is restricted to read-only commands */ struct linpool *parser_pool; /* Pool used during parsing */ byte *ring_buf; /* Ring buffer for asynchronous messages */ byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */ @@ -60,6 +61,14 @@ void cli_kick(cli *); void cli_written(cli *); void cli_echo(unsigned int class, byte *msg); +static inline int cli_access_restricted(void) +{ + if (this_cli && this_cli->restricted) + return (cli_printf(this_cli, 8007, "Access denied"), 1); + else + return 0; +} + /* Functions provided by sysdep layer */ void cli_write_trigger(cli *); diff --git a/nest/config.Y b/nest/config.Y index f9e88d5..792012e 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -45,7 +45,7 @@ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILT CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION) -CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES) +CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -59,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT) %type <s> optsym %type <ra> r_args %type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport -%type <t> proto_patt +%type <ps> proto_patt proto_patt2 CF_GRAMMAR @@ -324,11 +324,11 @@ CF_CLI_HELP(SHOW, ..., [[Show status information]]) CF_CLI(SHOW STATUS,,, [[Show router status]]) { cmd_show_status(); } ; -CF_CLI(SHOW PROTOCOLS, optsym, [<name>], [[Show routing protocols]]) -{ proto_show($3, 0); } ; +CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]]) +{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ; -CF_CLI(SHOW PROTOCOLS ALL, optsym, [<name>], [[Show routing protocol details]]) -{ proto_show($4, 1); } ; +CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]]) +{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ; optsym: SYM @@ -459,34 +459,42 @@ echo_size: ; CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]]) -{ proto_xxable($2, XX_DISABLE); } ; +{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ; CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]]) -{ proto_xxable($2, XX_ENABLE); } ; +{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ; CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]]) -{ proto_xxable($2, XX_RESTART); } ; +{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ; CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]]) -{ proto_xxable($2, XX_RELOAD); } ; +{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ; CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]]) -{ proto_xxable($3, XX_RELOAD_IN); } ; +{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ; CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]]) -{ proto_xxable($3, XX_RELOAD_OUT); } ; +{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ; CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]]) CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | interfaces | events | packets }), [[Control protocol debugging via BIRD logs]]) -{ proto_debug($2, 0, $3); } - ; +{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ; CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]]) CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) -{ proto_debug($2, 1, $3); } - ; +{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ; + +CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]]) +{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ; proto_patt: - SYM { $$ = $1->name; } - | ALL { $$ = "*"; } - | TEXT + SYM { $$.ptr = $1; $$.patt = 0; } + | ALL { $$.ptr = NULL; $$.patt = 1; } + | TEXT { $$.ptr = $1; $$.patt = 1; } ; +proto_patt2: + SYM { $$.ptr = $1; $$.patt = 0; } + | { $$.ptr = NULL; $$.patt = 1; } + | TEXT { $$.ptr = $1; $$.patt = 1; } + ; + + CF_CODE CF_END diff --git a/nest/iface.c b/nest/iface.c index 5e88b21..82dead3 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -336,6 +336,15 @@ if_end_update(void) } } +void +if_flush_ifaces(struct proto *p) +{ + if (p->debug & D_EVENTS) + log(L_TRACE "%s: Flushing interfaces", p->name); + if_start_update(); + if_end_update(); +} + /** * if_feed_baby - advertise interfaces to a new protocol * @p: protocol to feed diff --git a/nest/iface.h b/nest/iface.h index b7c3c19..873734d 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -75,8 +75,9 @@ struct iface *if_update(struct iface *); struct ifa *ifa_update(struct ifa *); void ifa_delete(struct ifa *); void if_start_update(void); -void if_end_update(void); void if_end_partial_update(struct iface *); +void if_end_update(void); +void if_flush_ifaces(struct proto *p); void if_feed_baby(struct proto *); struct iface *if_find_by_index(unsigned); struct iface *if_find_by_name(char *); @@ -106,6 +107,7 @@ typedef struct neighbor { } neighbor; #define NEF_STICKY 1 +#define NEF_ONLINK 2 neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags); neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags); diff --git a/nest/locks.c b/nest/locks.c index 1cdbbc9..7044d6a 100644 --- a/nest/locks.c +++ b/nest/locks.c @@ -97,7 +97,8 @@ static struct resclass olock_class = { "ObjLock", sizeof(struct object_lock), olock_free, - olock_dump + olock_dump, + NULL }; /** diff --git a/nest/neighbor.c b/nest/neighbor.c index a44667f..25b98db 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -112,12 +112,12 @@ neighbor * neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) { neighbor *n; - int class, scope = SCOPE_HOST; + int class, scope = -1; ; unsigned int h = neigh_hash(p, a); struct iface *i; WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ - if (n->proto == p && ipa_equal(*a, n->addr)) + if (n->proto == p && ipa_equal(*a, n->addr) && (!ifa || (ifa == n->iface))) return n; class = ipa_classify(*a); @@ -129,7 +129,12 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) return NULL; /* Bad scope or a somecast */ if (ifa) - scope = if_connected(a, ifa); + { + scope = if_connected(a, ifa); + + if ((scope < 0) && (flags & NEF_ONLINK)) + scope = class & IADDR_SCOPE_MASK; + } else WALK_LIST(i, iface_list) if ((scope = if_connected(a, i)) >= 0) @@ -138,22 +143,28 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) break; } - if (!ifa && !(flags & NEF_STICKY)) + /* scope < 0 means i don't know neighbor */ + /* scope >= 0 implies ifa != NULL */ + + if ((scope < 0) && !(flags & NEF_STICKY)) return NULL; n = sl_alloc(neigh_slab); n->addr = *a; - n->iface = ifa; - if (ifa) + if (scope >= 0) { add_tail(&neigh_hash_table[h], &n->n); add_tail(&ifa->neighbors, &n->if_n); } else { + /* sticky flag does not work for link-local neighbors; + fortunately, we don't use this combination */ add_tail(&sticky_neigh_list, &n->n); + ifa = NULL; scope = 0; } + n->iface = ifa; n->proto = p; n->data = NULL; n->aux = 0; diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c index c30b107..3d19e3f 100644 --- a/nest/proto-hooks.c +++ b/nest/proto-hooks.c @@ -178,13 +178,14 @@ void ifa_notify(struct proto *p, unsigned flags, struct ifa *a) /** * rt_notify - notify instance about routing table change * @p: protocol instance + * @table: a routing table * @net: a network entry * @new: new route for the network * @old: old route for the network * @attrs: extended attributes associated with the @new entry * * The rt_notify() hook is called to inform the protocol instance about - * changes in the routing table it's connected to, that is a route @old + * changes in the connected routing table @table, that is a route @old * belonging to network @net being replaced by a new route @new with * extended attributes @attrs. Either @new or @old or both can be %NULL * if the corresponding route doesn't exist. diff --git a/nest/proto.c b/nest/proto.c index 870eddd..78fca99 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -25,12 +25,6 @@ static pool *proto_pool; static list protocol_list; static list proto_list; -#define WALK_PROTO_LIST(p) do { \ - node *nn; \ - WALK_LIST(nn, proto_list) { \ - struct proto *p = SKIP_BACK(struct proto, glob_node, nn); -#define WALK_PROTO_LIST_END } } while(0) - #define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0) list active_proto_list; @@ -57,7 +51,7 @@ proto_enqueue(list *l, struct proto *p) static void proto_relink(struct proto *p) { - list *l; + list *l = NULL; if (p->debug & D_STATES) { @@ -119,7 +113,6 @@ proto_new(struct proto_config *c, unsigned size) p->table = c->table->table; p->in_filter = c->in_filter; p->out_filter = c->out_filter; - p->min_scope = SCOPE_SITE; p->hash_key = random_u32(); c->proto = p; return p; @@ -583,6 +576,12 @@ proto_fell_down(struct proto *p) bzero(&p->stats, sizeof(struct proto_stats)); rt_unlock_table(p->table); + +#ifdef CONFIG_PIPE + if (proto_is_pipe(p)) + rt_unlock_table(pipe_get_peer_table(p)); +#endif + proto_rethink_goal(p); } @@ -741,6 +740,8 @@ proto_notify_state(struct proto *p, unsigned ps) } } +extern struct protocol proto_unix_iface; + static void proto_flush_all(void *unused UNUSED) { @@ -749,6 +750,11 @@ proto_flush_all(void *unused UNUSED) rt_prune_all(); while ((p = HEAD(flush_proto_list))->n.next) { + /* This will flush interfaces in the same manner + like rt_prune_all() flushes routes */ + if (p->proto == &proto_unix_iface) + if_flush_ifaces(p); + DBG("Flushing protocol %s\n", p->name); p->core_state = FS_HUNGRY; proto_relink(p); @@ -781,10 +787,75 @@ proto_state_name(struct proto *p) } static void -proto_do_show(struct proto *p, int verbose) +proto_do_show_stats(struct proto *p) +{ + struct proto_stats *s = &p->stats; + cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", + s->imp_routes, s->exp_routes, s->pref_routes); + cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); + cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", + s->imp_updates_received, s->imp_updates_invalid, + s->imp_updates_filtered, s->imp_updates_ignored, + s->imp_updates_accepted); + cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", + s->imp_withdraws_received, s->imp_withdraws_invalid, + s->imp_withdraws_ignored, s->imp_withdraws_accepted); + cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u", + s->exp_updates_received, s->exp_updates_rejected, + s->exp_updates_filtered, s->exp_updates_accepted); + cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u", + s->exp_withdraws_received, s->exp_withdraws_accepted); +} + +static void +proto_do_show_pipe_stats(struct proto *p) +{ + struct proto_stats *s1 = &p->stats; + struct proto_stats *s2 = pipe_get_peer_stats(p); + + /* + * Pipe stats (as anything related to pipes) are a bit tricky. There + * are two sets of stats - s1 for routes going from the primary + * routing table to the secondary routing table ('exported' from the + * user point of view) and s2 for routes going in the other + * direction ('imported' from the user point of view). + * + * Each route going through a pipe is, technically, first exported + * to the pipe and then imported from that pipe and such operations + * are counted in one set of stats according to the direction of the + * route propagation. Filtering is done just in the first part + * (export). Therefore, we compose stats for one directon for one + * user direction from both import and export stats, skipping + * immediate and irrelevant steps (exp_updates_accepted, + * imp_updates_received, imp_updates_filtered, ...) + */ + + cli_msg(-1006, " Routes: %u imported, %u exported", + s2->imp_routes, s1->imp_routes); + cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); + cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", + s2->exp_updates_received, s2->exp_updates_rejected + s2->imp_updates_invalid, + s2->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted); + cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", + s2->exp_withdraws_received, s2->imp_withdraws_invalid, + s2->imp_withdraws_ignored, s2->imp_withdraws_accepted); + cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u", + s1->exp_updates_received, s1->exp_updates_rejected + s1->imp_updates_invalid, + s1->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted); + cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u", + s1->exp_withdraws_received, s1->imp_withdraws_invalid, + s1->imp_withdraws_ignored, s1->imp_withdraws_accepted); +} + +void +proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) { byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE]; + /* First protocol - show header */ + if (!cnt) + cli_msg(-2002, "name proto table state since info"); + buf[0] = 0; if (p->proto->get_status) p->proto->get_status(p, buf); @@ -806,21 +877,12 @@ proto_do_show(struct proto *p, int verbose) if (p->proto_state != PS_DOWN) { - cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", - p->stats.imp_routes, p->stats.exp_routes, p->stats.pref_routes); - cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); - cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", - p->stats.imp_updates_received, p->stats.imp_updates_invalid, - p->stats.imp_updates_filtered, p->stats.imp_updates_ignored, - p->stats.imp_updates_accepted); - cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", - p->stats.imp_withdraws_received, p->stats.imp_withdraws_invalid, - p->stats.imp_withdraws_ignored, p->stats.imp_withdraws_accepted); - cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u", - p->stats.exp_updates_received, p->stats.exp_updates_rejected, - p->stats.exp_updates_filtered, p->stats.exp_updates_accepted); - cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u", - p->stats.exp_withdraws_received, p->stats.exp_withdraws_accepted); +#ifdef CONFIG_PIPE + if (proto_is_pipe(p)) + proto_do_show_pipe_stats(p); + else +#endif + proto_do_show_stats(p); } cli_msg(-1006, ""); @@ -828,25 +890,140 @@ proto_do_show(struct proto *p, int verbose) } void -proto_show(struct symbol *s, int verbose) +proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) { - if (s && s->class != SYM_PROTO) + if (p->disabled) { - cli_msg(9002, "%s is not a protocol", s->name); + cli_msg(-8, "%s: already disabled", p->name); return; } - cli_msg(-2002, "name proto table state since info"); - if (s) - proto_do_show(((struct proto_config *)s->def)->proto, verbose); - else + + log(L_INFO "Disabling protocol %s", p->name); + p->disabled = 1; + proto_rethink_goal(p); + cli_msg(-9, "%s: disabled", p->name); +} + +void +proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +{ + if (!p->disabled) + { + cli_msg(-10, "%s: already enabled", p->name); + return; + } + + log(L_INFO "Enabling protocol %s", p->name); + p->disabled = 0; + proto_rethink_goal(p); + cli_msg(-11, "%s: enabled", p->name); +} + +void +proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +{ + if (p->disabled) + { + cli_msg(-8, "%s: already disabled", p->name); + return; + } + + log(L_INFO "Restarting protocol %s", p->name); + p->disabled = 1; + proto_rethink_goal(p); + p->disabled = 0; + proto_rethink_goal(p); + cli_msg(-12, "%s: restarted", p->name); +} + +void +proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED) +{ + if (p->disabled) { - WALK_PROTO_LIST(p) - proto_do_show(p, verbose); - WALK_PROTO_LIST_END; + cli_msg(-8, "%s: already disabled", p->name); + return; } + + /* If the protocol in not UP, it has no routes */ + if (p->proto_state != PS_UP) + return; + + log(L_INFO "Reloading protocol %s", p->name); + + /* re-importing routes */ + if (dir != CMD_RELOAD_OUT) + if (! (p->reload_routes && p->reload_routes(p))) + { + cli_msg(-8006, "%s: reload failed", p->name); + return; + } + + /* re-exporting routes */ + if (dir != CMD_RELOAD_IN) + proto_request_feeding(p); + + cli_msg(-15, "%s: reloading", p->name); +} + +void +proto_cmd_debug(struct proto *p, unsigned int mask, int cnt UNUSED) +{ + p->debug = mask; +} + +void +proto_cmd_mrtdump(struct proto *p, unsigned int mask, int cnt UNUSED) +{ + p->mrtdump = mask; +} + +static void +proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +{ + if (s->class != SYM_PROTO) + { + cli_msg(9002, "%s is not a protocol", s->name); + return; + } + + cmd(((struct proto_config *)s->def)->proto, arg, 0); cli_msg(0, ""); } +static void +proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +{ + int cnt = 0; + + node *nn; + WALK_LIST(nn, proto_list) + { + struct proto *p = SKIP_BACK(struct proto, glob_node, nn); + + if (!patt || patmatch(patt, p->name)) + cmd(p, arg, cnt++); + } + + if (!cnt) + cli_msg(8003, "No protocols match"); + else + cli_msg(0, ""); +} + +void +proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), + int restricted, unsigned int arg) +{ + if (restricted && cli_access_restricted()) + return; + + if (ps.patt) + proto_apply_cmd_patt(ps.ptr, cmd, arg); + else + proto_apply_cmd_symbol(ps.ptr, cmd, arg); +} + struct proto * proto_get_named(struct symbol *sym, struct protocol *pr) { @@ -875,112 +1052,3 @@ proto_get_named(struct symbol *sym, struct protocol *pr) } return p; } - -void -proto_xxable(char *pattern, int xx) -{ - int cnt = 0; - WALK_PROTO_LIST(p) - if (patmatch(pattern, p->name)) - { - cnt++; - switch (xx) - { - case XX_DISABLE: - if (p->disabled) - cli_msg(-8, "%s: already disabled", p->name); - else - { - log(L_INFO "Disabling protocol %s", p->name); - p->disabled = 1; - proto_rethink_goal(p); - cli_msg(-9, "%s: disabled", p->name); - } - break; - - case XX_ENABLE: - if (!p->disabled) - cli_msg(-10, "%s: already enabled", p->name); - else - { - log(L_INFO "Enabling protocol %s", p->name); - p->disabled = 0; - proto_rethink_goal(p); - cli_msg(-11, "%s: enabled", p->name); - } - break; - - case XX_RESTART: - if (p->disabled) - cli_msg(-8, "%s: already disabled", p->name); - else - { - log(L_INFO "Restarting protocol %s", p->name); - p->disabled = 1; - proto_rethink_goal(p); - p->disabled = 0; - proto_rethink_goal(p); - cli_msg(-12, "%s: restarted", p->name); - } - break; - - case XX_RELOAD: - case XX_RELOAD_IN: - case XX_RELOAD_OUT: - if (p->disabled) - { - cli_msg(-8, "%s: already disabled", p->name); - break; - } - - /* If the protocol in not UP, it has no routes */ - if (p->proto_state != PS_UP) - break; - - log(L_INFO "Reloading protocol %s", p->name); - - /* re-importing routes */ - if (xx != XX_RELOAD_OUT) - if (! (p->reload_routes && p->reload_routes(p))) - { - cli_msg(-8006, "%s: reload failed", p->name); - break; - } - - /* re-exporting routes */ - if (xx != XX_RELOAD_IN) - proto_request_feeding(p); - - cli_msg(-15, "%s: reloading", p->name); - break; - - default: - ASSERT(0); - } - } - WALK_PROTO_LIST_END; - if (!cnt) - cli_msg(8003, "No protocols match"); - else - cli_msg(0, ""); -} - -void -proto_debug(char *pattern, int which, unsigned int mask) -{ - int cnt = 0; - WALK_PROTO_LIST(p) - if (patmatch(pattern, p->name)) - { - cnt++; - if (which == 0) - p->debug = mask; - else - p->mrtdump = mask; - } - WALK_PROTO_LIST_END; - if (!cnt) - cli_msg(8003, "No protocols match"); - else - cli_msg(0, ""); -} diff --git a/nest/protocol.h b/nest/protocol.h index 5a69b33..d94873e 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -16,6 +16,7 @@ struct iface; struct ifa; +struct rtable; struct rte; struct neighbor; struct rta; @@ -129,7 +130,6 @@ struct proto { u32 debug; /* Debugging flags */ u32 mrtdump; /* MRTDump flags */ unsigned preference; /* Default route preference */ - int min_scope; /* Minimal route scope accepted */ unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */ unsigned disabled; /* Manually disabled */ unsigned proto_state; /* Protocol state machine (see below) */ @@ -162,7 +162,7 @@ struct proto { void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); - void (*rt_notify)(struct proto *, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs); + void (*rt_notify)(struct proto *, struct rtable *table, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs); void (*neigh_notify)(struct neighbor *neigh); struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs); @@ -194,21 +194,30 @@ struct proto { /* Hic sunt protocol-specific data */ }; +struct proto_spec { + void *ptr; + int patt; +}; + + void *proto_new(struct proto_config *, unsigned size); void *proto_config_new(struct protocol *, unsigned size); - void proto_request_feeding(struct proto *p); -void proto_show(struct symbol *, int); + +void proto_cmd_show(struct proto *, unsigned int, int); +void proto_cmd_disable(struct proto *, unsigned int, int); +void proto_cmd_enable(struct proto *, unsigned int, int); +void proto_cmd_restart(struct proto *, unsigned int, int); +void proto_cmd_reload(struct proto *, unsigned int, int); +void proto_cmd_debug(struct proto *, unsigned int, int); +void proto_cmd_mrtdump(struct proto *, unsigned int, int); + +void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), int restricted, unsigned int arg); struct proto *proto_get_named(struct symbol *, struct protocol *); -void proto_xxable(char *, int); -void proto_debug(char *, int, unsigned int); -#define XX_DISABLE 0 -#define XX_ENABLE 1 -#define XX_RESTART 2 -#define XX_RELOAD 3 -#define XX_RELOAD_IN 4 -#define XX_RELOAD_OUT 5 +#define CMD_RELOAD 0 +#define CMD_RELOAD_IN 1 +#define CMD_RELOAD_OUT 2 static inline u32 proto_get_router_id(struct proto_config *pc) @@ -334,4 +343,13 @@ struct announce_hook { struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); +/* + * Some pipe-specific nest hacks + */ + +#ifdef CONFIG_PIPE +#include "proto/pipe/pipe.h" +#endif + + #endif diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 9d78ce0..94b105d 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -400,7 +400,7 @@ ea_format(eattr *e, byte *buf) switch (e->type & EAF_TYPE_MASK) { case EAF_TYPE_INT: - bsprintf(buf, "%d", e->u.data); + bsprintf(buf, "%u", e->u.data); break; case EAF_TYPE_OPAQUE: for(i=0; i<ad->length; i++) diff --git a/nest/rt-dev.c b/nest/rt-dev.c index b86015d..bb8eb8e 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -33,6 +33,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) !iface_patt_find(&P->iface_list, ad->iface)) /* Empty list is automagically treated as "*" */ return; + + if (ad->scope <= SCOPE_LINK) + return; + if (c & IF_CHANGE_DOWN) { net *n; @@ -56,7 +60,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) bzero(&A, sizeof(A)); A.proto = p; A.source = RTS_DEVICE; - A.scope = ad->scope; + A.scope = SCOPE_UNIVERSE; A.cast = RTC_UNICAST; A.dest = RTD_DEVICE; A.iface = ad->iface; @@ -76,7 +80,6 @@ dev_init(struct proto_config *c) struct proto *p = proto_new(c, sizeof(struct proto)); p->ifa_notify = dev_ifa_notify; - p->min_scope = SCOPE_HOST; return p; } diff --git a/nest/rt-table.c b/nest/rt-table.c index 413675c..1860b1a 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -158,37 +158,42 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) } static inline void -do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed) +do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int refeed) { struct proto *p = a->proto; + struct filter *filter = p->out_filter; + struct proto_stats *stats = &p->stats; rte *new0 = new; rte *old0 = old; int ok; int fast_exit_hack = 0; +#ifdef CONFIG_PIPE + /* The secondary direction of the pipe */ + if (proto_is_pipe(p) && (p->table != a->table)) + { + filter = p->in_filter; + stats = pipe_get_peer_stats(p); + } +#endif + if (new) { - p->stats.exp_updates_received++; + stats->exp_updates_received++; char *drop_reason = NULL; - if ((class & IADDR_SCOPE_MASK) < p->min_scope) - { - p->stats.exp_updates_rejected++; - drop_reason = "out of scope"; - fast_exit_hack = 1; - } - else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) + if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) { - p->stats.exp_updates_rejected++; + stats->exp_updates_rejected++; drop_reason = "rejected by protocol"; } else if (ok) rte_trace_out(D_FILTERS, p, new, "forced accept by protocol"); - else if (p->out_filter == FILTER_REJECT || - p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) + else if ((filter == FILTER_REJECT) || + (filter && f_run(filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) { - p->stats.exp_updates_filtered++; + stats->exp_updates_filtered++; drop_reason = "filtered out"; } if (drop_reason) @@ -200,7 +205,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, } } else - p->stats.exp_withdraws_received++; + stats->exp_withdraws_received++; /* Hack: This is here to prevent 'spurious withdraws' for loopback addresses during reload. */ @@ -229,13 +234,13 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, if (old && !refeed) { - if (p->out_filter == FILTER_REJECT) + if (filter == FILTER_REJECT) old = NULL; else { ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL; ok = p->import_control ? p->import_control(p, &old, &tmpb, rte_update_pool) : 0; - if (ok < 0 || (!ok && p->out_filter && f_run(p->out_filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) + if (ok < 0 || (!ok && filter && f_run(filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) { if (old != old0) rte_free(old); @@ -249,16 +254,16 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, return; if (new) - p->stats.exp_updates_accepted++; + stats->exp_updates_accepted++; else - p->stats.exp_withdraws_accepted++; + stats->exp_withdraws_accepted++; /* Hack: We do not decrease exp_routes during refeed, we instead reset exp_routes at the start of refeed. */ if (new) - p->stats.exp_routes++; + stats->exp_routes++; if (old && !refeed) - p->stats.exp_routes--; + stats->exp_routes--; if (p->debug & D_ROUTES) { @@ -270,18 +275,18 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, rte_trace_out(D_ROUTES, p, old, "removed"); } if (!new) - p->rt_notify(p, net, NULL, old, NULL); + p->rt_notify(p, a->table, net, NULL, old, NULL); else if (tmpa) { ea_list *t = tmpa; while (t->next) t = t->next; t->next = new->attrs->eattrs; - p->rt_notify(p, net, new, old, tmpa); + p->rt_notify(p, a->table, net, new, old, tmpa); t->next = NULL; } else - p->rt_notify(p, net, new, old, new->attrs->eattrs); + p->rt_notify(p, a->table, net, new, old, new->attrs->eattrs); if (new && new != new0) /* Discard temporary rte's */ rte_free(new); if (old && old != old0) @@ -318,10 +323,9 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, * the protocol gets called. */ static void -rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa) +rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list *tmpa) { struct announce_hook *a; - int class = ipa_classify(net->n.prefix); if (type == RA_OPTIMAL) { @@ -335,7 +339,7 @@ rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa) { ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); if (a->proto->accept_ra_types == type) - do_rte_announce(a, type, net, new, old, tmpa, class, 0); + do_rte_announce(a, type, net, new, old, tmpa, 0); } } @@ -351,33 +355,15 @@ rte_validate(rte *e) n->n.prefix, n->n.pxlen, e->sender->name); return 0; } - if (n->n.pxlen) + + c = ipa_classify_net(n->n.prefix); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) { - c = ipa_classify(n->n.prefix); - if (c < 0 || !(c & IADDR_HOST)) - { - if (!ipa_nonzero(n->n.prefix)) - { - /* Various default routes */ -#ifdef IPV6 - if (n->n.pxlen == 96) -#else - if (n->n.pxlen <= 1) -#endif - return 1; - } - log(L_WARN "Ignoring bogus route %I/%d received via %s", - n->n.prefix, n->n.pxlen, e->sender->name); - return 0; - } - if ((c & IADDR_SCOPE_MASK) < e->sender->min_scope) - { - log(L_WARN "Ignoring %s scope route %I/%d received from %I via %s", - ip_scope_text(c & IADDR_SCOPE_MASK), - n->n.prefix, n->n.pxlen, e->attrs->from, e->sender->name); - return 0; - } + log(L_WARN "Ignoring bogus route %I/%d received via %s", + n->n.prefix, n->n.pxlen, e->sender->name); + return 0; } + return 1; } @@ -416,10 +402,16 @@ rte_same(rte *x, rte *y) static void rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa) { + struct proto_stats *stats = &p->stats; rte *old_best = net->routes; rte *old = NULL; rte **k, *r, *s; +#ifdef CONFIG_PIPE + if (proto_is_pipe(p) && (p->table == table)) + stats = pipe_get_peer_stats(p); +#endif + k = &net->routes; /* Find and remove original route from the same protocol */ while (old = *k) { @@ -448,7 +440,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte if (new && rte_same(old, new)) { /* No changes, ignore the new route */ - p->stats.imp_updates_ignored++; + stats->imp_updates_ignored++; rte_trace_in(D_ROUTES, p, new, "ignored"); rte_free_quick(new); old->lastmod = now; @@ -462,19 +454,19 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte if (!old && !new) { - p->stats.imp_withdraws_ignored++; + stats->imp_withdraws_ignored++; return; } if (new) - p->stats.imp_updates_accepted++; + stats->imp_updates_accepted++; else - p->stats.imp_withdraws_accepted++; + stats->imp_withdraws_accepted++; if (new) - p->stats.imp_routes++; + stats->imp_routes++; if (old) - p->stats.imp_routes--; + stats->imp_routes--; rte_announce(table, RA_ANY, net, new, old, tmpa); @@ -632,6 +624,12 @@ void rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new) { ea_list *tmpa = NULL; + struct proto_stats *stats = &p->stats; + +#ifdef CONFIG_PIPE + if (proto_is_pipe(p) && (p->table == table)) + stats = pipe_get_peer_stats(p); +#endif rte_update_lock(); if (new) @@ -642,20 +640,20 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new /* Do not filter routes going through the pipe, they are filtered in the export filter only. */ #ifdef CONFIG_PIPE - if (p->proto == &proto_pipe) + if (proto_is_pipe(p)) filter = FILTER_ACCEPT; #endif - p->stats.imp_updates_received++; + stats->imp_updates_received++; if (!rte_validate(new)) { rte_trace_in(D_FILTERS, p, new, "invalid"); - p->stats.imp_updates_invalid++; + stats->imp_updates_invalid++; goto drop; } if (filter == FILTER_REJECT) { - p->stats.imp_updates_filtered++; + stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); goto drop; } @@ -667,7 +665,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); if (fr > F_ACCEPT) { - p->stats.imp_updates_filtered++; + stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); goto drop; } @@ -679,7 +677,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new new->flags |= REF_COW; } else - p->stats.imp_withdraws_received++; + stats->imp_withdraws_received++; rte_recalculate(table, net, p, src, new, tmpa); rte_update_unlock(); @@ -995,7 +993,7 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e) rte_update_lock(); tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; - do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding); + do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, p->refeeding); rte_update_unlock(); } @@ -1167,11 +1165,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (p2 && p2 != p0) ok = 0; if (ok && d->export_mode) { - int class = ipa_classify(n->n.prefix); int ic; - if ((class & IADDR_SCOPE_MASK) < p1->min_scope) - ok = 0; - else if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) + if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) ok = 0; else if (!ic && d->export_mode > 1) { @@ -1180,8 +1175,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) 'configure soft' command may change the export filter and do not update routes */ - if (p1->out_filter == FILTER_REJECT || - p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) + if ((p1->out_filter == FILTER_REJECT) || + (p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) ok = 0; } } diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 4cfabf1..9bcd4f8 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -47,7 +47,7 @@ bgp_check_origin(struct bgp_proto *p UNUSED, byte *a, int len UNUSED) } static void -bgp_format_origin(eattr *a, byte *buf, int buflen) +bgp_format_origin(eattr *a, byte *buf, int buflen UNUSED) { static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" }; @@ -257,14 +257,14 @@ static struct attr_desc bgp_attr_table[] = { NULL, NULL }, { "cluster_list", -1, BAF_OPTIONAL, EAF_TYPE_INT_SET, 0, /* BA_CLUSTER_LIST */ bgp_check_cluster_list, bgp_format_cluster_list }, - { NULL, }, /* BA_DPA */ - { NULL, }, /* BA_ADVERTISER */ - { NULL, }, /* BA_RCID_PATH */ + { .name = NULL }, /* BA_DPA */ + { .name = NULL }, /* BA_ADVERTISER */ + { .name = NULL }, /* BA_RCID_PATH */ { "mp_reach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_REACH_NLRI */ bgp_check_reach_nlri, NULL }, { "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_UNREACH_NLRI */ bgp_check_unreach_nlri, NULL }, - { NULL, }, /* BA_EXTENDED_COMM */ + { .name = NULL }, /* BA_EXTENDED_COMM */ { "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */ NULL, NULL }, { "as4_aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */ @@ -772,7 +772,7 @@ bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck) } void -bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old UNUSED, ea_list *attrs) +bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs) { struct bgp_proto *p = (struct bgp_proto *) P; struct bgp_bucket *buck; @@ -1070,16 +1070,6 @@ bgp_rte_better(rte *new, rte *old) /* Skipping RFC 4271 9.1.2.2. e) */ /* We don't have interior distances */ - /* RFC 4456 9. b) Compare cluster list lengths */ - x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); - y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, 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) - return 1; - if (n > o) - return 0; - /* RFC 4271 9.1.2.2. f) Compare BGP identifiers */ /* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighor ID */ x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); @@ -1099,6 +1089,16 @@ bgp_rte_better(rte *new, rte *old) if (n > o) return 0; + /* RFC 4456 9. b) Compare cluster list lengths */ + x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); + y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, 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) + return 1; + if (n > o) + return 0; + /* RFC 4271 9.1.2.2. g) Compare peer IP adresses */ return (ipa_compare(new_bgp->cf->remote_ip, old_bgp->cf->remote_ip) < 0); } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 215dc81..4410c04 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -203,7 +203,7 @@ bgp_start_timer(timer *t, int value) void bgp_close_conn(struct bgp_conn *conn) { - struct bgp_proto *p = conn->bgp; + // struct bgp_proto *p = conn->bgp; DBG("BGP: Closing connection\n"); conn->packets_to_send = 0; @@ -237,7 +237,7 @@ bgp_update_startup_delay(struct bgp_proto *p) DBG("BGP: Updating startup delay\n"); - if (p->last_proto_error && ((now - p->last_proto_error) >= cf->error_amnesia_time)) + if (p->last_proto_error && ((now - p->last_proto_error) >= (int) cf->error_amnesia_time)) p->startup_delay = 0; p->last_proto_error = now; @@ -492,7 +492,7 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn) } static void -bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s) +bgp_setup_sk(struct bgp_conn *conn, sock *s) { s->data = conn; s->err_hook = bgp_sock_err; @@ -555,7 +555,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->tx_hook = bgp_connected; BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr); bgp_setup_conn(p, conn); - bgp_setup_sk(p, conn, s); + bgp_setup_sk(conn, s); bgp_conn_set_state(conn, BS_CONNECT); if (sk_open(s)) { @@ -601,7 +601,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) goto err; bgp_setup_conn(p, &p->incoming_conn); - bgp_setup_sk(p, &p->incoming_conn, sk); + bgp_setup_sk(&p->incoming_conn, sk); sk_set_ttl(sk, p->cf->multihop ? : 1); bgp_send_open(&p->incoming_conn); return 0; @@ -614,6 +614,15 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) return 0; } +static void +bgp_listen_sock_err(sock *sk UNUSED, int err) +{ + if (err == ECONNABORTED) + log(L_WARN "BGP: Incoming connection aborted"); + else + log(L_ERR "BGP: Error on incoming socket: %M", err); +} + static sock * bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags) { @@ -627,9 +636,10 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags) s->rbsize = BGP_RX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE; s->rx_hook = bgp_incoming_connection; + s->err_hook = bgp_listen_sock_err; if (sk_open(s)) { - log(L_ERR "Unable to open incoming BGP socket"); + log(L_ERR "BGP: Unable to open incoming socket"); rfree(s); return NULL; } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 7f574ed..1a29195 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -179,7 +179,7 @@ byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned att struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory); int bgp_get_attr(struct eattr *e, byte *buf, int buflen); int bgp_rte_better(struct rte *, struct rte *); -void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *); +void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *); void bgp_attr_init(struct bgp_proto *); unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 095e1ce..f882aaa 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -59,7 +59,7 @@ bgp_proto: BGP_CFG->remote_ip = $3; BGP_CFG->remote_as = $5; } - | bgp_proto RR CLUSTER ID expr ';' { BGP_CFG->rr_cluster_id = $5; } + | bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; } | bgp_proto RR CLIENT ';' { BGP_CFG->rr_client = 1; } | bgp_proto RS CLIENT ';' { BGP_CFG->rs_client = 1; } | bgp_proto HOLD TIME expr ';' { BGP_CFG->hold_time = $4; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 329efb3..2baa6e3 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -44,7 +44,6 @@ static byte * mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) { struct bgp_proto *p = conn->bgp; - ip_addr local_addr; if (as4) { @@ -614,7 +613,7 @@ bgp_tx(sock *sk) void bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len) { - struct bgp_proto *p = conn->bgp; + // struct bgp_proto *p = conn->bgp; int cl; while (len > 0) @@ -915,7 +914,6 @@ bgp_do_rx_update(struct bgp_conn *conn, rta *a = NULL; ip_addr prefix; net *n; - rte e; int err = 0, pxlen; p->mp_reach_len = 0; @@ -937,8 +935,6 @@ bgp_do_rx_update(struct bgp_conn *conn, DO_NLRI(mp_reach) { - int i; - /* Create fake NEXT_HOP attribute */ if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2) goto bad; diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index 9f174df..7fe8280 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -48,8 +48,8 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, struct proto_ospf *po = ifa->oa->po; struct proto *p = &po->proto; char *beg = "OSPF: Bad HELLO packet from "; - unsigned int size, i, twoway, oldpriority, eligible, peers; - u32 olddr, oldbdr, oldiface_id, tmp; + unsigned int size, i, twoway, eligible, peers; + u32 tmp; u32 *pnrid; size = ntohs(ps_i->length); @@ -169,11 +169,11 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, if (!twoway) ospf_neigh_sm(n, INM_1WAYREC); - olddr = n->dr; - oldbdr = n->bdr; - oldpriority = n->priority; + u32 olddr = n->dr; + u32 oldbdr = n->bdr; + u32 oldpriority = n->priority; #ifdef OSPFv3 - oldiface_id = n->iface_id; + u32 oldiface_id = n->iface_id; #endif n->dr = ntohl(ps->dr); diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index ab63398..35f02dc 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -122,22 +122,22 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) } void -htonlsab(void *h, void *n, u16 type, u16 len) +htonlsab(void *h, void *n, u16 len) { u32 *hid = h; u32 *nid = n; - int i; + unsigned i; for (i = 0; i < (len / sizeof(u32)); i++) nid[i] = htonl(hid[i]); } void -ntohlsab(void *n, void *h, u16 type, u16 len) +ntohlsab(void *n, void *h, u16 len) { u32 *nid = n; u32 *hid = h; - int i; + unsigned i; for (i = 0; i < (len / sizeof(u32)); i++) hid[i] = ntohl(nid[i]); @@ -185,11 +185,10 @@ void lsasum_calculate(struct ospf_lsa_header *h, void *body) { u16 length = h->length; - u16 type = h->type; // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); htonlsah(h, h); - htonlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); + htonlsab(body, body, length - sizeof(struct ospf_lsa_header)); /* char buf[1024]; @@ -203,7 +202,7 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body) // log(L_WARN "Checksum result %4x", h->checksum); ntohlsah(h, h); - ntohlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); + ntohlsab(body, body, length - sizeof(struct ospf_lsa_header)); } /* @@ -325,7 +324,7 @@ lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) } static int -lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body) +lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED) { if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net))) return 0; diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h index ed929be..a799de3 100644 --- a/proto/ospf/lsalib.h +++ b/proto/ospf/lsalib.h @@ -12,8 +12,8 @@ void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n); void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h); -void htonlsab(void *h, void *n, u16 type, u16 len); -void ntohlsab(void *n, void *h, u16 type, u16 len); +void htonlsab(void *h, void *n, u16 len); +void ntohlsab(void *n, void *h, u16 len); void lsasum_calculate(struct ospf_lsa_header *header, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body); #define CMP_NEWER 1 diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 39d91b9..7d5d89d 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -290,8 +290,7 @@ ospf_lsupd_flood(struct proto_ospf *po, htonlsah(hh, lh); help = (u8 *) (lh + 1); en = ospf_hash_find_header(po->gr, domain, hh); - htonlsab(en->lsa_body, help, hh->type, hh->length - - sizeof(struct ospf_lsa_header)); + htonlsab(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header)); } len = sizeof(struct ospf_lsupd_packet) + ntohs(lh->length); @@ -384,8 +383,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) } htonlsah(&(en->lsa), pktpos); pktpos = pktpos + sizeof(struct ospf_lsa_header); - htonlsab(en->lsa_body, pktpos, en->lsa.type, en->lsa.length - - sizeof(struct ospf_lsa_header)); + htonlsab(en->lsa_body, pktpos, en->lsa.length - sizeof(struct ospf_lsa_header)); pktpos = pktpos + en->lsa.length - sizeof(struct ospf_lsa_header); len += en->lsa.length; lsano++; @@ -627,8 +625,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, /* pg 144 (5d) */ void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header)); - ntohlsab(lsa + 1, body, lsatmp.type, - lsatmp.length - sizeof(struct ospf_lsa_header)); + ntohlsab(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header)); /* We will do validation check after flooding and acknowledging given LSA to minimize problems diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 89acf54..69c5880 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -440,7 +440,6 @@ void bdr_election(struct ospf_iface *ifa) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; u32 myid = po->router_id; struct ospf_neighbor *neigh, *ndr, *nbdr, me; int doadj; @@ -631,7 +630,7 @@ static void rxmt_timer_hook(timer * timer) { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; - struct proto *p = &n->ifa->oa->po->proto; + // struct proto *p = &n->ifa->oa->po->proto; struct top_hash_entry *en; DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n", diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index ff010cb..e2a3aed 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -78,7 +78,7 @@ static int ospf_reload_routes(struct proto *p); -static void ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ea_list * attrs); +static void ospf_rt_notify(struct proto *p, struct rtable *table UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs); static void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a); static int ospf_rte_better(struct rte *new, struct rte *old); static int ospf_rte_same(struct rte *new, struct rte *old); @@ -224,9 +224,11 @@ ospf_dump(struct proto *p) } } + /* OSPF_TRACE(D_EVENTS, "LSA graph dump start:"); ospf_top_dump(po->gr, p); OSPF_TRACE(D_EVENTS, "LSA graph dump finished"); + */ neigh_dump_all(); } @@ -486,8 +488,7 @@ ospf_shutdown(struct proto *p) } static void -ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, - ea_list * attrs) +ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs) { struct proto_ospf *po = (struct proto_ospf *) p; @@ -503,7 +504,7 @@ ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, } static void -ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a) +ospf_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a) { struct proto_ospf *po = (struct proto_ospf *) p; struct ospf_iface *ifa; @@ -918,7 +919,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) void ospf_sh_neigh(struct proto *p, char *iff) { - struct ospf_iface *ifa = NULL, *f; + struct ospf_iface *ifa = NULL; struct ospf_neighbor *n; struct proto_ospf *po = (struct proto_ospf *) p; @@ -1009,7 +1010,7 @@ void ospf_sh_iface(struct proto *p, char *iff) { struct proto_ospf *po = (struct proto_ospf *) p; - struct ospf_iface *ifa = NULL, *f; + struct ospf_iface *ifa = NULL; if (p->proto_state != PS_UP) { @@ -1196,7 +1197,6 @@ show_lsa_network(struct top_hash_entry *he) static inline void show_lsa_sum_net(struct top_hash_entry *he) { - struct ospf_lsa_header *lsa = &(he->lsa); ip_addr ip; int pxlen; @@ -1236,9 +1236,7 @@ show_lsa_sum_rt(struct top_hash_entry *he) static inline void show_lsa_external(struct top_hash_entry *he) { - struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_ext *ext = he->lsa_body; - struct ospf_lsa_ext_tos *et = (struct ospf_lsa_ext_tos *) (ext + 1); char str_via[STD_ADDRESS_P_LENGTH + 8] = ""; char str_tag[16] = ""; ip_addr ip, rt_fwaddr; @@ -1248,7 +1246,7 @@ show_lsa_external(struct top_hash_entry *he) rt_metric = ext->metric & METRIC_MASK; ebit = ext->metric & LSA_EXT_EBIT; #ifdef OSPFv2 - ip = ipa_and(ipa_from_u32(lsa->id), ext->netmask); + ip = ipa_and(ipa_from_u32(he->lsa.id), ext->netmask); pxlen = ipa_mklen(ext->netmask); rt_fwaddr = ext->fwaddr; rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); @@ -1285,10 +1283,7 @@ show_lsa_external(struct top_hash_entry *he) static inline void show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *olsa) { - struct ospf_lsa_header *lsa = &(he->lsa); struct ospf_lsa_prefix *px = he->lsa_body; - struct ospf_lsa_ext *ext = he->lsa_body; - char *msg; ip_addr pxa; int pxlen; u8 pxopts; @@ -1496,8 +1491,6 @@ ospf_sh_lsadb(struct proto *p) if ((dscope != last_dscope) || (hea[i]->domain != last_domain)) { - struct iface *ifa; - cli_msg(-1017, ""); switch (dscope) { @@ -1509,8 +1502,10 @@ ospf_sh_lsadb(struct proto *p) break; #ifdef OSPFv3 case LSA_SCOPE_LINK: - ifa = if_find_by_index(hea[i]->domain); - cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?"); + { + struct iface *ifa = if_find_by_index(hea[i]->domain); + cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?"); + } break; #endif } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 7d5ae28..cb4f53c 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -705,7 +705,7 @@ struct ospf_area struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */ list cand; /* List of candidates for RT calc. */ struct fib net_fib; /* Networks to advertise or not */ - int stub; + unsigned stub; int trcap; /* Transit capability? */ u32 options; /* Optional features */ struct proto_ospf *po; @@ -782,13 +782,14 @@ void schedule_net_lsa(struct ospf_iface *ifa); #ifdef OSPFv3 void schedule_link_lsa(struct ospf_iface *ifa); #else -static inline void schedule_link_lsa(struct ospf_iface *ifa) {} +static inline void schedule_link_lsa(struct ospf_iface *ifa UNUSED) {} #endif void ospf_sh_neigh(struct proto *p, char *iff); void ospf_sh(struct proto *p); void ospf_sh_iface(struct proto *p, char *iff); void ospf_sh_state(struct proto *p, int verbose); +void ospf_sh_lsadb(struct proto *p); #define EA_OSPF_METRIC1 EA_CODE(EAP_OSPF, 0) diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 6697057..95f7653 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -14,7 +14,6 @@ void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) { struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; struct ospf_packet *pkt; pkt = (struct ospf_packet *) buf; @@ -282,7 +281,7 @@ ospf_rx_hook(sock *sk, int size) /* Initially, the packet is associated with the 'master' iface */ struct ospf_iface *ifa = sk->data; struct proto_ospf *po = ifa->oa->po; - struct proto *p = &po->proto; + // struct proto *p = &po->proto; int src_local = ifa_match_addr(ifa->addr, sk->faddr); int dst_local = ipa_equal(sk->laddr, ifa->addr->ip); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 18dc3bb..9a330a8 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -170,7 +170,7 @@ static void process_prefixes(struct ospf_area *oa) { struct proto_ospf *po = oa->po; - struct proto *p = &po->proto; + // struct proto *p = &po->proto; struct top_hash_entry *en, *src; struct ospf_lsa_prefix *px; ip_addr pxa; @@ -226,9 +226,8 @@ process_prefixes(struct ospf_area *oa) static void ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en) { - struct proto *p = &oa->po->proto; + // struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; - orta nf; u32 i; struct ospf_lsa_rt *rt = en->lsa_body; @@ -249,6 +248,7 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to */ DBG("\n"); + orta nf; nf.type = RTS_OSPF; nf.options = 0; nf.metric1 = act->dist + rtl->metric; @@ -521,7 +521,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry static void ospf_rt_sum_tr(struct ospf_area *oa) { - struct proto *p = &oa->po->proto; + // struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; struct ospf_area *bb = po->backbone; ip_addr ip, abrip; @@ -573,7 +573,7 @@ ospf_rt_sum_tr(struct ospf_area *oa) type = ORT_NET; re = fib_find(&po->rtf, &ip, pxlen); } - else if (en->lsa.type == LSA_T_SUM_RT) + else // en->lsa.type == LSA_T_SUM_RT { #ifdef OSPFv2 struct ospf_lsa_sum *ls = en->lsa_body; @@ -1081,8 +1081,8 @@ static int calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par) { + // struct proto *p = &oa->po->proto; struct ospf_neighbor *neigh; - struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; struct ospf_iface *ifa; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index b09d13f..bff9b2e 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -741,7 +741,7 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) } void -originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options) +originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED) { struct proto_ospf *po = oa->po; struct proto *p = &po->proto; @@ -897,7 +897,6 @@ originate_ext_lsa_body(net *n, rte *e, u16 *length, struct proto_ospf *po, u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0); int gw = 0; int size = sizeof(struct ospf_lsa_ext); - u32 *buf; if ((e->attrs->dest == RTD_ROUTER) && !ipa_equal(e->attrs->gw, IPA_NONE) && @@ -925,7 +924,7 @@ originate_ext_lsa_body(net *n, rte *e, u16 *length, struct proto_ospf *po, ext->fwaddr = gw ? e->attrs->gw : IPA_NONE; ext->tag = tag; #else /* OSPFv3 */ - buf = ext->rest; + u32 *buf = ext->rest; buf = put_ipv6_prefix(buf, n->n.prefix, n->n.pxlen, 0, 0); if (gw) @@ -1015,7 +1014,6 @@ flush_ext_lsa(net *n, struct proto_ospf *po) { struct proto *p = &po->proto; struct fib_node *fn = &n->n; - struct ospf_area *oa; struct top_hash_entry *en; OSPF_TRACE(D_EVENTS, "Flushing AS-external-LSA for %I/%d", @@ -1649,10 +1647,11 @@ ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e) bug("ospf_hash_delete() called for invalid node"); } +/* static void ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) { - /* + struct ospf_lsa_rt *rt = NULL; struct ospf_lsa_rt_link *rr = NULL; struct ospf_lsa_net *ln = NULL; @@ -1686,7 +1685,6 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) default: break; } - */ } void @@ -1702,6 +1700,7 @@ ospf_top_dump(struct top_graph *f, struct proto *p) ospf_dump_lsa(e, p); } } +*/ /* This is very inefficient, please don't call it often */ diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index aa76a15..7fdf273 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -31,9 +31,12 @@ #include "pipe.h" static void -pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs) +pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs) { + struct pipe_proto *p = (struct pipe_proto *) P; + rtable *dest = (src_table == P->table) ? p->peer : P->table; /* The other side of the pipe */ struct proto *src; + net *nn; rte *e; rta a; @@ -85,30 +88,12 @@ pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *ne src_table->pipe_busy = 0; } -static void -pipe_rt_notify_pri(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs) -{ - struct pipe_proto *p = (struct pipe_proto *) P; - - DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen); - pipe_send(p, p->p.table, p->peer, net, new, old, attrs); -} - -static void -pipe_rt_notify_sec(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs) -{ - struct pipe_proto *p = ((struct pipe_proto *) P)->phantom; - - DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen); - pipe_send(p, p->peer, p->p.table, net, new, old, attrs); -} - static int pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED) { struct proto *pp = (*ee)->sender; - if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p) + if (pp == P) return -1; /* Avoid local loops automatically */ return 0; } @@ -130,60 +115,20 @@ static int pipe_start(struct proto *P) { struct pipe_proto *p = (struct pipe_proto *) P; - struct pipe_proto *ph; struct announce_hook *a; - /* - * Create a phantom protocol which will represent the remote - * end of the pipe (we need to do this in order to get different - * filters and announce functions and it unfortunately involves - * a couple of magic trickery). - */ - ph = mb_alloc(P->pool, sizeof(struct pipe_proto)); - memcpy(ph, p, sizeof(struct pipe_proto)); - p->phantom = ph; - ph->phantom = p; - ph->p.accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY; - ph->p.rt_notify = pipe_rt_notify_sec; - ph->p.proto_state = PS_UP; - ph->p.core_state = ph->p.core_goal = FS_HAPPY; + /* Clean up the secondary stats */ + bzero(&p->peer_stats, sizeof(struct proto_stats)); - /* - * Routes should be filtered in the do_rte_announce() (export - * filter for protocols). Reverse direction is handled by putting - * specified import filter to out_filter field of the phantom - * protocol. - * - * in_filter fields are not important, there is an exception in - * rte_update() to ignore it for pipes. We cannot just set - * P->in_filter to FILTER_ACCEPT, because that would break other - * things (reconfiguration, show-protocols command). - */ - ph->p.in_filter = FILTER_ACCEPT; - ph->p.out_filter = P->in_filter; + /* Lock the peer table, unlock is handled in proto_fell_down() */ + rt_lock_table(p->peer); - /* - * Connect the phantom protocol to the peer routing table, but - * keep it in the list of connections of the primary protocol, - * so that it gets disconnected at the right time and we also - * get all routes from both sides during the feeding phase. - */ + /* Connect the protocol also to the peer routing table. */ a = proto_add_announce_hook(P, p->peer); - a->proto = &ph->p; - rt_lock_table(p->peer); return PS_UP; } -static int -pipe_shutdown(struct proto *P) -{ - struct pipe_proto *p = (struct pipe_proto *) P; - - rt_unlock_table(p->peer); - return PS_DOWN; -} - static struct proto * pipe_init(struct proto_config *C) { @@ -194,9 +139,10 @@ pipe_init(struct proto_config *C) p->peer = c->peer->table; p->mode = c->mode; P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY; - P->rt_notify = pipe_rt_notify_pri; + P->rt_notify = pipe_rt_notify; P->import_control = pipe_import_control; P->reload_routes = pipe_reload_routes; + return P; } @@ -222,25 +168,23 @@ pipe_get_status(struct proto *P, byte *buf) static int pipe_reconfigure(struct proto *P, struct proto_config *new) { - struct pipe_proto *p = (struct pipe_proto *) P; + // struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_config *o = (struct pipe_config *) P->cf; struct pipe_config *n = (struct pipe_config *) new; if ((o->peer->table != n->peer->table) || (o->mode != n->mode)) return 0; - /* Update also the filter in the phantom protocol */ - p->phantom->p.out_filter = new->in_filter; return 1; } + struct protocol proto_pipe = { name: "Pipe", template: "pipe%d", postconfig: pipe_postconfig, init: pipe_init, start: pipe_start, - shutdown: pipe_shutdown, reconfigure: pipe_reconfigure, get_status: pipe_get_status, }; diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h index 368ba41..fbd2129 100644 --- a/proto/pipe/pipe.h +++ b/proto/pipe/pipe.h @@ -21,8 +21,20 @@ struct pipe_config { struct pipe_proto { struct proto p; struct rtable *peer; + struct proto_stats peer_stats; /* Statistics for the direction peer->primary */ int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */ - struct pipe_proto *phantom; }; + +extern struct protocol proto_pipe; + +static inline int proto_is_pipe(struct proto *p) +{ return p->proto == &proto_pipe; } + +static inline struct rtable * pipe_get_peer_table(struct proto *P) +{ return ((struct pipe_proto *) P)->peer; } + +static inline struct proto_stats * pipe_get_peer_stats(struct proto *P) +{ return &((struct pipe_proto *) P)->peer_stats; } + #endif diff --git a/proto/rip/rip.c b/proto/rip/rip.c index f9a160e..3b95a3e 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -752,6 +752,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ return NULL; } /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */ + return rif; } static void @@ -864,7 +865,8 @@ rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) * own), so store it into our data structures. */ static void -rip_rt_notify(struct proto *p, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs) +rip_rt_notify(struct proto *p, struct rtable *table UNUSED, struct network *net, + struct rte *new, struct rte *old, struct ea_list *attrs) { CHK_MAGIC; @@ -955,7 +957,7 @@ rip_rte_insert(net *net UNUSED, rte *rte) static void rip_rte_remove(net *net UNUSED, rte *rte) { - struct proto *p = rte->attrs->proto; + // struct proto *p = rte->attrs->proto; CHK_MAGIC; DBG( "rip_rte_remove: %p\n", rte ); rem_node( &rte->u.rip.garbage ); diff --git a/proto/static/static.c b/proto/static/static.c index c71d1da..9308c59 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -125,11 +125,12 @@ static_shutdown(struct proto *p) struct static_config *c = (void *) p->cf; struct static_route *r; - DBG("Static: prepare for landing!\n"); + /* Just reset the flag, the routes will be flushed by the nest */ WALK_LIST(r, c->iface_routes) - static_remove(p, r); + r->installed = 0; WALK_LIST(r, c->other_routes) - static_remove(p, r); + r->installed = 0; + return PS_DOWN; } @@ -294,7 +295,7 @@ static_show_rt(struct static_route *r) switch (r->dest) { case RTD_ROUTER: bsprintf(via, "via %I", r->via); break; - case RTD_DEVICE: bsprintf(via, "to %s", r->if_name); break; + case RTD_DEVICE: bsprintf(via, "dev %s", r->if_name); break; case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break; case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index a527965..1dd09ae 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -33,39 +33,8 @@ #include "lib/string.h" #include "lib/socket.h" -#ifdef IPV6 -#define HOST_MASK 128 -#else -#define HOST_MASK 32 -#endif - int rt_sock = 0; -#define CHECK_FAMILY(sa) \ - ((((struct sockaddr *)sa)->sa_family) == BIRD_AF) - -static struct iface * -krt_temp_iface_index(struct krt_proto *p, unsigned index) -{ - struct iface *i, *j; - - WALK_LIST(i, p->scan.temp_ifs) - if (i->index == index) - return i; - i = mb_allocz(p->p.pool, sizeof(struct iface)); - if (j = if_find_by_index(index)) - { - strcpy(i->name, j->name); - i->addr = j->addr; - } - else - strcpy(i->name, "?"); - i->index = index; - add_tail(&p->scan.temp_ifs, &i->n); - return i; -} - - int krt_capable(rte *e) { @@ -83,7 +52,7 @@ krt_capable(rte *e) || a->dest == RTD_UNREACHABLE #endif #ifdef RTF_BLACKHOLE - || a->dest == RTD_BLACKHOLE /* FIXME Prohibited? */ + || a->dest == RTD_BLACKHOLE #endif ); } @@ -96,6 +65,13 @@ krt_capable(rte *e) l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\ memmove(body, &(u), l); body += l;} +#define GETADDR(p, F) \ + bzero(p, sizeof(*p));\ + if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\ + unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ + memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\ + body += l;} + static void krt_sock_send(int cmd, rte *e) { @@ -108,7 +84,7 @@ krt_sock_send(int cmd, rte *e) char *body = (char *)msg.buf; sockaddr gate, mask, dst; - DBG("krt-sock: send %I/%d via %I", net->n.prefix, net->n.pxlen, a->gw); + DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw); fill_in_sockaddr(&dst, net->n.prefix, 0); fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), 0); @@ -119,9 +95,9 @@ krt_sock_send(int cmd, rte *e) msg.rtm.rtm_type = cmd; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; - msg.rtm.rtm_flags = RTF_UP; + msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1; - if (net->n.pxlen == HOST_MASK) + if (net->n.pxlen == MAX_PREFIX_LENGTH) { msg.rtm.rtm_flags |= RTF_HOST; } @@ -200,12 +176,12 @@ krt_sock_send(int cmd, rte *e) msg.rtm.rtm_msglen = l; if ((l = write(rt_sock, (char *)&msg, l)) < 0) { - log(L_ERR "KIF: error writting route to socket (%I/%d)", net->n.prefix, net->n.pxlen); + log(L_ERR "KIF: Error sending route %I/%d to kernel", net->n.prefix, net->n.pxlen); } } void -krt_set_notify(struct krt_proto *p UNUSED, net *net UNUSED, rte *new, rte *old) +krt_set_notify(struct krt_proto *p UNUSED, net *net, rte *new, rte *old) { if (old) { @@ -258,68 +234,87 @@ krt_set_start(struct krt_proto *x, int first UNUSED) bug("krt-sock: sk_open failed"); } +#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0) + static void krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) { - sockaddr gate, mask, dst; rta a; rte *e; net *net; + sockaddr dst, gate, mask; ip_addr idst, igate, imask; void *body = (char *)msg->buf; int new = (msg->rtm.rtm_type == RTM_ADD); int src; + char *errmsg = "KRT: Invalid route received"; int flags = msg->rtm.rtm_flags; int addrs = msg->rtm.rtm_addrs; - int masklen = -1; - if (!(flags & RTF_UP)) - { - DBG("Down.\n"); - return; - } + if (!(flags & RTF_UP) && scan) + SKIP("not up in scan\n"); - if (flags & RTF_HOST) - masklen = HOST_MASK; + if (!(flags & RTF_DONE) && !scan) + SKIP("not done in async\n"); - if(!CHECK_FAMILY(body)) return; + if (flags & RTF_LLINFO) + SKIP("link-local\n"); - if(msg->rtm.rtm_flags & RTF_LLINFO) return; /* ARPs etc. */ + GETADDR(&dst, RTA_DST); + GETADDR(&gate, RTA_GATEWAY); + GETADDR(&mask, RTA_NETMASK); -#define GETADDR(p, F) \ - bzero(p, sizeof(*p));\ - if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\ - unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ - memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\ - body += l;} - - GETADDR (&dst, RTA_DST); - GETADDR (&gate, RTA_GATEWAY); - GETADDR (&mask, RTA_NETMASK); + if (sa_family_check(&dst)) + get_sockaddr(&dst, &idst, NULL, 0); + else + SKIP("invalid DST"); - idst = IPA_NONE; - igate = IPA_NONE; - imask = IPA_NONE; + /* We will check later whether we have valid gateway addr */ + if (sa_family_check(&gate)) + get_sockaddr(&gate, &igate, NULL, 0); + else + igate = IPA_NONE; - get_sockaddr(&dst, &idst, NULL, 0); - if(CHECK_FAMILY(&gate)) get_sockaddr(&gate, &igate, NULL, 0); + /* We do not test family for RTA_NETMASK, because BSD sends us + some strange values, but interpreting them as IPv4/IPv6 works */ get_sockaddr(&mask, &imask, NULL, 0); - if (masklen < 0) masklen = ipa_mklen(imask); + int c = ipa_classify_net(idst); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) + SKIP("strange class/scope\n"); - if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) - { - log(L_WARN "krt: Ignoring redirect to %I/%d via %I", idst, masklen, igate); - return; - } + int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask); + if (pxlen < 0) + { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; } - if (masklen < 0) - { - log(L_WARN "krt: Got invalid route from kernel!"); - return; - } + if ((flags & RTF_GATEWAY) && ipa_zero(igate)) + { log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; } - net = net_get(p->p.table, idst, masklen); + u32 self_mask = RTF_PROTO1; + u32 alien_mask = RTF_STATIC | RTF_PROTO1; + +#ifdef RTF_PROTO2 + alien_mask |= RTF_PROTO2; +#endif + +#ifdef RTF_PROTO3 + alien_mask |= RTF_PROTO3; +#endif + + if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) + src = KRT_SRC_REDIRECT; + else if (flags & self_mask) + { + if (!scan) + SKIP("echo\n"); + src = KRT_SRC_BIRD; + } + else if (flags & alien_mask) + src = KRT_SRC_ALIEN; + else + src = KRT_SRC_KERNEL; + + net = net_get(p->p.table, idst, pxlen); bzero(&a, sizeof(a)); @@ -333,56 +328,56 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) a.iface = NULL; a.eattrs = NULL; - a.dest = RTD_NONE; - - if (flags & RTF_GATEWAY) - { - neighbor *ng = neigh_find(&p->p, &igate, 0); - if (ng && ng->scope) - a.iface = ng->iface; - else - { - log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", igate, net->n.prefix, net->n.pxlen); - return; - } - - a.dest = RTD_ROUTER; - a.gw = igate; - } - else - { - a.dest = RTD_DEVICE; - a.gw = IPA_NONE; - a.iface = krt_temp_iface_index(p, msg->rtm.rtm_index); - } + /* reject/blackhole routes have also set RTF_GATEWAY, + we wil check them first. */ #ifdef RTF_REJECT if(flags & RTF_REJECT) { a.dest = RTD_UNREACHABLE; - a.gw = IPA_NONE; + goto done; } #endif #ifdef RTF_BLACKHOLE if(flags & RTF_BLACKHOLE) { a.dest = RTD_BLACKHOLE; - a.gw = IPA_NONE; + goto done; } #endif - if (a.dest == RTD_NONE) + a.iface = if_find_by_index(msg->rtm.rtm_index); + if (!a.iface) + { + log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u", + net->n.prefix, net->n.pxlen, msg->rtm.rtm_index); + return; + } + + if (flags & RTF_GATEWAY) { - log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen); - return; - } + neighbor *ng; + a.dest = RTD_ROUTER; + a.gw = igate; - src = KRT_SRC_UNKNOWN; /* FIXME */ + ng = neigh_find2(&p->p, &a.gw, a.iface, 0); + if (!ng || (ng->scope == SCOPE_HOST)) + { + log(L_ERR "KRT: Received route %I/%d with strange next-hop %I", + net->n.prefix, net->n.pxlen, a.gw); + return; + } + } + else + a.dest = RTD_DEVICE; + done: e = rte_get_temp(&a); e->net = net; e->u.krt.src = src; - //e->u.krt.proto = i->rtm_protocol; - //e->u.krt.type = i->rtm_type; + + /* These are probably too Linux-specific */ + e->u.krt.proto = 0; + e->u.krt.type = 0; e->u.krt.metric = 0; if (scan) @@ -471,6 +466,10 @@ krt_read_addr(struct ks_msg *msg) int scope, masklen = -1; int new = (ifam->ifam_type == RTM_NEWADDR); + /* Strange messages with zero (invalid) ifindex appear on OpenBSD */ + if (ifam->ifam_index == 0) + return; + if(!(iface = if_find_by_index(ifam->ifam_index))) { log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index); @@ -486,7 +485,9 @@ krt_read_addr(struct ks_msg *msg) GETADDR (&null, RTA_AUTHOR); GETADDR (&brd, RTA_BRD); - if(!CHECK_FAMILY(&addr)) return; /* Some other family address */ + /* Some other family address */ + if (!sa_family_check(&addr)) + return; get_sockaddr(&addr, &iaddr, NULL, 0); get_sockaddr(&mask, &imask, NULL, 0); @@ -507,9 +508,6 @@ krt_read_addr(struct ks_msg *msg) memcpy(&ifa.brd, &ibrd, sizeof(ip_addr)); scope = ipa_classify(ifa.ip); - - ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen)); - if (scope < 0) { log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name); @@ -517,6 +515,14 @@ krt_read_addr(struct ks_msg *msg) } ifa.scope = scope & IADDR_SCOPE_MASK; + if (iface->flags & IF_MULTIACCESS) + ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen)); + else /* PtP iface */ + { + ifa.flags |= IA_UNNUMBERED; + ifa.prefix = ifa.opposite = ifa.brd; + } + if (new) ifa_update(&ifa); else @@ -593,27 +599,27 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd) mib[4] = cmd; mib[5] = 0; - if( sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0) + if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0) { die("RT scan..."); } obl = *bl; - while(needed > *bl) *bl *= 2; - while(needed < (*bl/2)) *bl /= 2; + while (needed > *bl) *bl *= 2; + while (needed < (*bl/2)) *bl /= 2; - if( (obl!=*bl) || !*buf) + if ((obl!=*bl) || !*buf) { - if(*buf) mb_free(*buf); - if( (*buf = mb_alloc(pool, *bl)) == NULL ) die("RT scan buf alloc"); + if (*buf) mb_free(*buf); + if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc"); } on = needed; - if( sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0) + if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0) { - if(on != needed) return; /* The buffer size changed since last sysctl */ + if (on != needed) return; /* The buffer size changed since last sysctl */ die("RT scan 2"); } @@ -624,22 +630,23 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd) } } +static byte *krt_buffer = NULL; +static byte *kif_buffer = NULL; +static size_t krt_buflen = 32768; +static size_t kif_buflen = 4096; + void krt_scan_fire(struct krt_proto *p) { - static byte *buf = NULL; - static size_t bl = 32768; - krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP); + krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP); } void krt_if_scan(struct kif_proto *p) { - static byte *buf = NULL; - static size_t bl = 4096; struct proto *P = (struct proto *)p; if_start_update(); - krt_sysctl_scan(P, P->pool, &buf, &bl, NET_RT_IFLIST); + krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST); if_end_update(); } @@ -652,7 +659,9 @@ krt_set_construct(struct krt_config *c UNUSED) void krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED) { -} + mb_free(krt_buffer); + krt_buffer = NULL; +} void krt_if_io_init(void) @@ -672,5 +681,7 @@ krt_if_start(struct kif_proto *p UNUSED) void krt_if_shutdown(struct kif_proto *p UNUSED) { + mb_free(kif_buffer); + kif_buffer = NULL; } diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h index f3aefeb..66985ab 100644 --- a/sysdep/cf/bsd-v6.h +++ b/sysdep/cf/bsd-v6.h @@ -9,7 +9,7 @@ #define IPV6 #define CONFIG_AUTO_ROUTES -#undef CONFIG_SELF_CONSCIOUS +#define CONFIG_SELF_CONSCIOUS #undef CONFIG_MULTIPLE_TABLES #undef CONFIG_UNIX_IFACE diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h index 72b2472..acd1b58 100644 --- a/sysdep/cf/bsd.h +++ b/sysdep/cf/bsd.h @@ -7,7 +7,7 @@ */ #define CONFIG_AUTO_ROUTES -#undef CONFIG_SELF_CONSCIOUS +#define CONFIG_SELF_CONSCIOUS #undef CONFIG_MULTIPLE_TABLES #undef CONFIG_UNIX_IFACE diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index f45fe15..b59b32f 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -52,7 +52,6 @@ struct nl_sock static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */ static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */ - static void nl_open_sock(struct nl_sock *nl) { @@ -555,23 +554,7 @@ krt_set_notify(struct krt_proto *p, net *n UNUSED, rte *new, rte *old) nl_send_route(p, new, 1); } -static struct iface * -krt_temp_iface(struct krt_proto *p, unsigned index) -{ - struct iface *i, *j; - - WALK_LIST(i, p->scan.temp_ifs) - if (i->index == index) - return i; - i = mb_allocz(p->p.pool, sizeof(struct iface)); - if (j = if_find_by_index(index)) - strcpy(i->name, j->name); - else - strcpy(i->name, "?"); - i->index = index; - add_tail(&p->scan.temp_ifs, &i->n); - return i; -} +#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0) static void nl_parse_route(struct nlmsghdr *h, int scan) @@ -599,31 +582,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) #endif (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr))) { - log(L_ERR "nl_parse_route: Malformed message received"); - return; - } - - p = nl_table_map[i->rtm_table]; /* Do we know this table? */ - if (!p) - return; - -#ifdef IPV6 - if (a[RTA_IIF]) - { - DBG("KRT: Ignoring route with IIF set\n"); - return; - } -#else - if (i->rtm_tos != 0) /* We don't support TOS */ - { - DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos); - return; - } -#endif - - if (scan && !new) - { - DBG("KRT: Ignoring route deletion\n"); + log(L_ERR "KRT: Malformed message received"); return; } @@ -634,33 +593,57 @@ nl_parse_route(struct nlmsghdr *h, int scan) } else dst = IPA_NONE; + if (a[RTA_OIF]) memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif)); else oif = ~0; - DBG("Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name); + DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name); + + p = nl_table_map[i->rtm_table]; /* Do we know this table? */ + if (!p) + SKIP("unknown table %d", i->rtm_table); + +#ifdef IPV6 + if (a[RTA_IIF]) + SKIP("IIF set\n"); +#else + if (i->rtm_tos != 0) /* We don't support TOS */ + SKIP("TOS %02x\n", i->rtm_tos); +#endif + + if (scan && !new) + SKIP("RTM_DELROUTE in scan\n"); + + int c = ipa_classify_net(dst); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) + SKIP("strange class/scope\n"); + + // ignore rtm_scope, it is not a real scope + // if (i->rtm_scope != RT_SCOPE_UNIVERSE) + // SKIP("scope %u\n", i->rtm_scope); switch (i->rtm_protocol) { + case RTPROT_UNSPEC: + SKIP("proto unspec\n"); + case RTPROT_REDIRECT: src = KRT_SRC_REDIRECT; break; + case RTPROT_KERNEL: - DBG("Route originated in kernel, ignoring\n"); + src = KRT_SRC_KERNEL; return; + case RTPROT_BIRD: -#ifdef IPV6 - case RTPROT_BOOT: - /* Current Linux kernels don't remember rtm_protocol for IPv6 routes and supply RTPROT_BOOT instead */ -#endif if (!scan) - { - DBG("Echo of our own route, ignoring\n"); - return; - } + SKIP("echo\n"); src = KRT_SRC_BIRD; break; + + case RTPROT_BOOT: default: src = KRT_SRC_ALIEN; } @@ -679,52 +662,48 @@ nl_parse_route(struct nlmsghdr *h, int scan) switch (i->rtm_type) { case RTN_UNICAST: - if (oif == ~0U) + ra.iface = if_find_by_index(oif); + if (!ra.iface) { - log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen); + log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u", + net->n.prefix, net->n.pxlen, oif); return; } + if (a[RTA_GATEWAY]) { - struct iface *ifa = if_find_by_index(oif); neighbor *ng; ra.dest = RTD_ROUTER; memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw)); ipa_ntoh(ra.gw); - if (i->rtm_flags & RTNH_F_ONLINK) - { - /* route with 'onlink' attribute */ - ra.iface = if_find_by_index(oif); - if (ra.iface == NULL) - { - log(L_WARN "Kernel told us to use unknown interface %u for %I/%d", - oif, net->n.prefix, net->n.pxlen); - return; - } - } - else + ng = neigh_find2(&p->p, &ra.gw, ra.iface, + (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); + if (!ng || (ng->scope == SCOPE_HOST)) { - ng = neigh_find2(&p->p, &ra.gw, ifa, 0); - if (ng && ng->scope) - { - if (ng->iface != ifa) - log(L_WARN "KRT: Route with unexpected iface for %I/%d", net->n.prefix, net->n.pxlen); - ra.iface = ng->iface; - } - else - { - log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen); - return; - } - + log(L_ERR "KRT: Received route %I/%d with strange next-hop %I", + net->n.prefix, net->n.pxlen, ra.gw); + return; } } else { ra.dest = RTD_DEVICE; - ra.iface = krt_temp_iface(p, oif); + + /* + * In Linux IPv6, 'native' device routes have proto + * RTPROT_BOOT and not RTPROT_KERNEL (which they have in + * IPv4 and which is expected). We cannot distinguish + * 'native' and user defined device routes, so we ignore all + * such device routes and for consistency, we have the same + * behavior in IPv4. Anyway, users should use RTPROT_STATIC + * for their 'alien' routes. + */ + + if (i->rtm_protocol == RTPROT_BOOT) + src = KRT_SRC_KERNEL; } + break; case RTN_BLACKHOLE: ra.dest = RTD_BLACKHOLE; @@ -737,13 +716,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) break; /* FIXME: What about RTN_THROW? */ default: - DBG("KRT: Ignoring route with type=%d\n", i->rtm_type); - return; - } - - if (i->rtm_scope != RT_SCOPE_UNIVERSE) - { - DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope); + SKIP("type %d\n", i->rtm_type); return; } diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 07f2cb1..94be002 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -101,7 +101,7 @@ struct ip_mreqn #define fill_mreq_ifa fill_mreq #define fill_mreq_grp fill_mreq -static inline fill_mreq(struct ip_mreqn *m, struct iface *ifa, ip_addr maddr) +static inline void fill_mreq(struct ip_mreqn *m, struct iface *ifa, ip_addr maddr) { bzero(m, sizeof(*m)); m->imr_ifindex = ifa->index; diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 8c2b690..ac5be7e 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -107,7 +107,7 @@ CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore { cmd_reconfig($3, RECONFIG_SOFT); } ; CF_CLI(DOWN,,, [[Shut the daemon down]]) -{ cli_msg(7, "Shutdown requested"); order_shutdown(); } ; +{ cmd_shutdown(); } ; cfg_name: /* empty */ { $$ = NULL; } diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 316244d..c7527c9 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -70,7 +70,8 @@ static struct resclass rf_class = { "FILE", sizeof(struct rfile), rf_free, - rf_dump + rf_dump, + NULL }; void * @@ -195,7 +196,8 @@ static struct resclass tm_class = { "Timer", sizeof(timer), tm_free, - tm_dump + tm_dump, + NULL }; /** @@ -564,7 +566,8 @@ static struct resclass sk_class = { "Socket", sizeof(sock), sk_free, - sk_dump + sk_dump, + NULL }; /** @@ -640,7 +643,7 @@ fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port) } static inline void -fill_in_sockifa(sockaddr *sa, struct iface *ifa) +fill_in_sockifa(sockaddr *sa UNUSED, struct iface *ifa UNUSED) { } @@ -660,7 +663,6 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check) static char * sk_set_ttl_int(sock *s) { - int one = 1; #ifdef IPV6 if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) return "IPV6_UNICAST_HOPS"; @@ -668,6 +670,7 @@ sk_set_ttl_int(sock *s) if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) return "IP_TTL"; #ifdef CONFIG_UNIX_DONTROUTE + int one = 1; if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) return "SO_DONTROUTE"; #endif @@ -1012,7 +1015,6 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type) } else if (errno != EINTR && errno != EAGAIN) { - log(L_ERR "accept: %m"); s->err_hook(s, errno); } return 0; @@ -1602,7 +1604,6 @@ io_loop(void) { sock *s = current_sock; int e; - int steps; if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook) { diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 488447b..c8887b7 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -139,15 +139,6 @@ kif_shutdown(struct proto *P) krt_if_shutdown(p); kif_proto = NULL; - if_start_update(); /* Remove all interfaces */ - if_end_update(); - /* - * FIXME: Is it really a good idea? It causes routes to be flushed, - * but at the same time it avoids sending of these deletions to the kernel, - * because krt thinks the kernel itself has already removed the route - * when downing the interface. Sad. - */ - return PS_DOWN; } @@ -558,32 +549,30 @@ krt_got_route(struct krt_proto *p, rte *e) rte *old; net *net = e->net; int verdict; -#ifdef KRT_ALLOW_LEARN - int src = e->u.krt.src; -#endif -#ifdef CONFIG_AUTO_ROUTES - if (e->attrs->dest == RTD_DEVICE) +#ifdef KRT_ALLOW_LEARN + switch (e->u.krt.src) { - /* It's a device route. Probably a kernel-generated one. */ + case KRT_SRC_KERNEL: verdict = KRF_IGNORE; goto sentenced; - } -#endif -#ifdef KRT_ALLOW_LEARN - if (src == KRT_SRC_ALIEN) - { + case KRT_SRC_REDIRECT: + verdict = KRF_DELETE; + goto sentenced; + + case KRT_SRC_ALIEN: if (KRT_CF->learn) krt_learn_scan(p, e); else { - krt_trace_in_rl(&rl_alien_ignored, p, e, "alien route, ignored"); + krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored"); rte_free(e); } return; } #endif + /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ if (net->n.flags & KRF_VERDICT_MASK) { @@ -605,7 +594,7 @@ krt_got_route(struct krt_proto *p, rte *e) else verdict = KRF_DELETE; -sentenced: + sentenced: krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]); net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict; if (verdict == KRF_UPDATE || verdict == KRF_DELETE) @@ -680,19 +669,24 @@ krt_prune(struct krt_proto *p) } void -krt_got_route_async(struct krt_proto *p, rte *e, int new UNUSED) +krt_got_route_async(struct krt_proto *p, rte *e, int new) { net *net = e->net; - int src = e->u.krt.src; - switch (src) + switch (e->u.krt.src) { case KRT_SRC_BIRD: ASSERT(0); /* Should be filtered by the back end */ + case KRT_SRC_REDIRECT: - DBG("It's a redirect, kill him! Kill! Kill!\n"); - krt_set_notify(p, net, NULL, e); + if (new) + { + krt_trace_in(p, e, "[redirect] deleting"); + krt_set_notify(p, net, NULL, e); + } + /* If !new, it is probably echo of our deletion */ break; + #ifdef KRT_ALLOW_LEARN case KRT_SRC_ALIEN: if (KRT_CF->learn) @@ -742,7 +736,8 @@ krt_scan(timer *t UNUSED) */ static void -krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs UNUSED) +krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, + rte *new, rte *old, struct ea_list *attrs UNUSED) { struct krt_proto *p = (struct krt_proto *) P; @@ -877,7 +872,6 @@ krt_init(struct proto_config *c) p->p.accept_ra_types = RA_OPTIMAL; p->p.rt_notify = krt_notify; - p->p.min_scope = SCOPE_HOST; return &p->p; } diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 607e699..1d9e144 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -83,6 +83,7 @@ void krt_got_route_async(struct krt_proto *p, struct rte *e, int new); #define KRT_SRC_BIRD 0 /* Our route (not passed in async mode) */ #define KRT_SRC_REDIRECT 1 /* Redirect route, delete it */ #define KRT_SRC_ALIEN 2 /* Route installed by someone else */ +#define KRT_SRC_KERNEL 3 /* Kernel routes, are ignored by krt syncer */ extern struct protocol proto_unix_iface; diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index f227549..3d3b433 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include <stdarg.h> #include <time.h> +#include <unistd.h> #include "nest/bird.h" #include "nest/cli.h" diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 7a1ef28..2245692 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -141,6 +141,9 @@ cmd_reconfig(char *name, int type) { struct config *conf; + if (cli_access_restricted()) + return; + if (!name) name = config_name; cli_msg(-2, "Reading configuration from %s", name); @@ -304,6 +307,16 @@ cli_init_unix(void) */ void +cmd_shutdown(void) +{ + if (cli_access_restricted()) + return; + + cli_msg(7, "Shutdown requested"); + order_shutdown(); +} + +void async_shutdown(void) { DBG("Shutting down...\n"); diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 83f61af..0b179e0 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -9,6 +9,8 @@ #ifndef _BIRD_UNIX_H_ #define _BIRD_UNIX_H_ +#include <sys/socket.h> + struct pool; /* main.c */ @@ -17,6 +19,7 @@ void async_config(void); void async_dump(void); void async_shutdown(void); void cmd_reconfig(char *name, int type); +void cmd_shutdown(void); /* io.c */ @@ -28,10 +31,12 @@ volatile int async_shutdown_flag; #define BIRD_PF PF_INET6 #define BIRD_AF AF_INET6 typedef struct sockaddr_in6 sockaddr; +static inline int sa_family_check(sockaddr *sa) { return sa->sin6_family == AF_INET6; } #else #define BIRD_PF PF_INET #define BIRD_AF AF_INET typedef struct sockaddr_in sockaddr; +static inline int sa_family_check(sockaddr *sa) { return sa->sin_family == AF_INET; } #endif #ifndef SUN_LEN diff --git a/tools/Makefile.in b/tools/Makefile.in index daa753c..99ae225 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -55,7 +55,7 @@ tags: cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) -name *.[chY]` install: all - $(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/$(localstatedir) + $(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/$(localstatedir)/run $(INSTALL_PROGRAM) -s $(exedir)/bird $(DESTDIR)/$(sbindir)/bird@SUFFIX6@ if test -n "@CLIENT@" ; then \ $(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc@SUFFIX6@ ; \ |