1
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-03 18:37:48 +01:00

Merge branch 'new' into socket2

This commit is contained in:
Ondrej Zajicek 2010-03-11 18:55:59 +01:00
commit 54305181f6
64 changed files with 937 additions and 799 deletions

1
NEWS
View File

@ -5,6 +5,7 @@ Version 1.2.1 (2010-02-11)
o Adds router ID of advertising router as OSPF route attribute. o Adds router ID of advertising router as OSPF route attribute.
o 'show route' command indicates primary route and shows OSPF Router ID. o 'show route' command indicates primary route and shows OSPF Router ID.
o Configurable date/time formats. o Configurable date/time formats.
o Symbol names can be enclosed by '' and so include hyphen and start with number.
o Several minor bugfixes. o Several minor bugfixes.
Version 1.2.0 (2010-01-05) Version 1.2.0 (2010-01-05)

View File

@ -25,8 +25,10 @@
#include "client/client.h" #include "client/client.h"
#include "sysdep/unix/unix.h" #include "sysdep/unix/unix.h"
static char *opt_list = "s:v"; static char *opt_list = "s:vr";
static int verbose; static int verbose;
static char *init_cmd;
static int once;
static char *server_path = PATH_CONTROL_SOCKET; static char *server_path = PATH_CONTROL_SOCKET;
static int server_fd; static int server_fd;
@ -49,7 +51,7 @@ static int num_lines, skip_input, interactive;
static void static void
usage(void) usage(void)
{ {
fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v]\n"); fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v] [-r]\n");
exit(1); exit(1);
} }
@ -67,11 +69,36 @@ parse_args(int argc, char **argv)
case 'v': case 'v':
verbose++; verbose++;
break; break;
case 'r':
init_cmd = "restrict";
break;
default: default:
usage(); usage();
} }
/* If some arguments are not options, we take it as commands */
if (optind < argc) 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 ***/ /*** Input ***/
@ -267,11 +294,29 @@ update_state(void)
if (nstate == cstate) if (nstate == cstate)
return; 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 (nstate == STATE_PROMPT)
if (input_initialized) {
input_reveal(); if (input_initialized)
else input_reveal();
input_init(); else
input_init();
}
if (nstate != STATE_PROMPT) if (nstate != STATE_PROMPT)
input_hide(); input_hide();
@ -329,6 +374,8 @@ server_connect(void)
die("fcntl: %m"); die("fcntl: %m");
} }
#define PRINTF(LEN, PARGS...) do { if (!skip_input) len = printf(PARGS); } while(0)
static void static void
server_got_reply(char *x) server_got_reply(char *x)
{ {
@ -336,15 +383,15 @@ server_got_reply(char *x)
int len = 0; int len = 0;
if (*x == '+') /* Async reply */ if (*x == '+') /* Async reply */
skip_input || (len = printf(">>> %s\n", x+1)); PRINTF(len, ">>> %s\n", x+1);
else if (x[0] == ' ') /* Continuation */ 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 && else if (strlen(x) > 4 &&
sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 && sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
(x[4] == ' ' || x[4] == '-')) (x[4] == ' ' || x[4] == '-'))
{ {
if (code) if (code)
skip_input || (len = printf("%s\n", verbose ? x : x+5)); PRINTF(len, "%s\n", verbose ? x : x+5);
if (x[4] == ' ') if (x[4] == ' ')
{ {
nstate = STATE_PROMPT; nstate = STATE_PROMPT;
@ -353,7 +400,7 @@ server_got_reply(char *x)
} }
} }
else else
skip_input || (len = printf("??? <%s>\n", x)); PRINTF(len, "??? <%s>\n", x);
if (skip_input) if (skip_input)
return; return;

View File

@ -33,6 +33,7 @@
#include "nest/bird.h" #include "nest/bird.h"
#include "nest/route.h" #include "nest/route.h"
#include "nest/protocol.h"
#include "filter/filter.h" #include "filter/filter.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "conf/cf-parse.tab.h" #include "conf/cf-parse.tab.h"

View File

@ -42,6 +42,7 @@ CF_DECLS
void *g; void *g;
bird_clock_t time; bird_clock_t time;
struct prefix px; struct prefix px;
struct proto_spec ps;
struct timeformat *tf; struct timeformat *tf;
} }

View File

@ -23,7 +23,7 @@ m4_define(CF_DECLS, `m4_divert(-1)')
m4_define(CF_DEFINES, `m4_divert(-1)') m4_define(CF_DEFINES, `m4_divert(-1)')
# Keywords are translated to C initializers # 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_divert(-1)')
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($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 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) # 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_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') 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_m4wrap(`
m4_divert(0) m4_divert(0)
static struct keyword keyword_list[] = { 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 # As we are processing C source, we must access all M4 primitives via

View File

@ -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(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(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(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_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]) AC_ARG_WITH(sysconfig,[ --with-sysconfig=FILE use specified BIRD system configuration file])
@ -56,23 +55,16 @@ AC_SEARCH_LIBS(clock_gettime,[c rt posix4])
AC_CANONICAL_HOST AC_CANONICAL_HOST
AC_MSG_CHECKING([what CFLAGS should we use])
if test "$ac_test_CFLAGS" != set ; then
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -Wno-pointer-sign -Wno-parentheses"
fi
AC_MSG_RESULT($CFLAGS)
AC_PROG_CC AC_PROG_CC
if test -z "$GCC" ; then if test -z "$GCC" ; then
AC_MSG_ERROR([This program requires the GNU C Compiler.]) 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 fi
if test "$with_sysinclude" != no -a -n "$with_sysinclude"; then
CPPFLAGS="$CPPFLAGS -I$with_sysinclude"
fi
AC_MSG_RESULT($CFLAGS)
AC_PROG_CPP AC_PROG_CPP
AC_PROG_INSTALL AC_PROG_INSTALL

View File

@ -96,9 +96,9 @@ protocol static {
# honor neighbor; # To whom do we agree to send the routing table # honor neighbor; # To whom do we agree to send the routing table
# honor always; # honor always;
# honor never; # honor never;
# passwords { password "ahoj" from 0 to 10; # passwords {
# password "nazdar" from 10; # password "nazdar";
# } # };
# authentication none; # authentication none;
# import filter { print "importing"; accept; }; # import filter { print "importing"; accept; };
# export filter { print "exporting"; accept; }; # export filter { print "exporting"; accept; };
@ -143,6 +143,7 @@ protocol static {
# generate from "22-04-2003 11:00:07"; # generate from "22-04-2003 11:00:07";
# accept from "17-01-2003 12:01:05"; # accept from "17-01-2003 12:01:05";
# }; # };
# };
# authentication cryptographic; # authentication cryptographic;
# }; # };
# }; # };
@ -163,7 +164,7 @@ protocol static {
#protocol bgp { #protocol bgp {
# disabled; # disabled;
# description "My BGP uplink" # description "My BGP uplink";
# local as 65000; # local as 65000;
# neighbor 62.168.0.130 as 5588; # neighbor 62.168.0.130 as 5588;
# multihop 20 via 62.168.0.13; # 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_med 0; # MED value we use for comparison when none is defined
# default bgp_local_pref 0; # The same for local preference # 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 # 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 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 where source=RTS_STATIC;
# export filter { # export filter {
# if source = RTS_STATIC then { # if source = RTS_STATIC then {
## bgp_community = -empty-; bgp_community = add(bgp_community,(65000,5678)); # bgp_community = -empty-; bgp_community = add(bgp_community,(65000,5678));
## bgp_origin = 0; # bgp_origin = 0;
# bgp_community = -empty-; bgp_community.add((65000,5678)); # bgp_community = -empty-; bgp_community.add((65000,5678));
## if (65000,5678) ~ bgp_community then # if (65000,5678) ~ bgp_community then
## bgp_community.add((0, 1)); # bgp_community.add((0, 1));
# if bgp_path ~ [= 65000 =] then # if bgp_path ~ [= 65000 =] then
# bgp_path.prepend(65000); # bgp_path.prepend(65000);
# accept; # accept;

View File

@ -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.) Network the route is talking about. Read-only. (See the chapter about routing tables.)
<tag><m/enum/ scope</tag> <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> <tag><m/int/ preference</tag>
Preference of the route. Valid values are 0-65535. (See the chapter about routing tables.) 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/. 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> <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> <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. 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.

View File

@ -24,6 +24,7 @@ Reply codes of BIRD command-line interface
0013 Status report 0013 Status report
0014 Route count 0014 Route count
0015 Reloading 0015 Reloading
0016 Access restricted
1000 BIRD version 1000 BIRD version
1001 Interface list 1001 Interface list
@ -51,6 +52,7 @@ Reply codes of BIRD command-line interface
8004 Stopped due to reconfiguration 8004 Stopped due to reconfiguration
8005 Protocol is down => cannot dump 8005 Protocol is down => cannot dump
8006 Reload failed 8006 Reload failed
8007 Access denied
9000 Command too long 9000 Command too long
9001 Parse error 9001 Parse error

View File

@ -273,16 +273,17 @@ fprefix_set:
; ;
switch_body: /* EMPTY */ { $$ = NULL; } switch_body: /* EMPTY */ { $$ = NULL; }
| set_item ':' cmds switch_body { | switch_body set_item ':' cmds {
$$ = $1; $$ = $2;
$$->data = $3; $$->data = $4;
$$->left = $4; $$->left = $1;
} }
| ELSE ':' cmds { | switch_body ELSE ':' cmds {
$$ = f_new_tree(); $$ = f_new_tree();
$$->from.type = T_VOID; $$->from.type = T_VOID;
$$->to.type = T_VOID; $$->to.type = T_VOID;
$$->data = $3; $$->data = $4;
$$->left = $1;
} }
; ;

View File

@ -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 void
f_prefix_get_bounds(struct f_prefix *px, int *l, int *h) f_prefix_get_bounds(struct f_prefix *px, int *l, int *h)

View File

@ -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); 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 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); void val_print(struct f_val v);
#define F_NOP 0 #define F_NOP 0

View File

@ -131,6 +131,9 @@ prefix px;
ip p; ip p;
pair pp; pair pp;
int set is; int set is;
int set is1;
int set is2;
int set is3;
prefix set pxs; prefix set pxs;
string s; string s;
{ {
@ -156,6 +159,18 @@ string s;
print " must be true: ", defined(1), ",", defined(1.2.3.4), ",", 1 != 2, ",", 1 <= 2; 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; 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; px = 1.2.0.0/18;
print "Testing prefixes: 1.2.0.0/18 = ", px; 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; 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;

View File

@ -6,61 +6,11 @@
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
#include "lib/alloca.h"
#include "nest/bird.h" #include "nest/bird.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.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 * find_tree
* @t: tree to search in * @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); 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 * build_tree
* @from: degenerated tree (linked by @tree->left) to be transformed into form suitable for find_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 * struct f_tree *
build_tree(struct f_tree *from) 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 (from == NULL)
if (!median)
return NULL; return NULL;
do { len = 0;
next = t->left; for (tmp = from; tmp != NULL; tmp = tmp->left)
if (t == median) len++;
continue;
if (val_compare(median->from, t->from)==1) { if (len <= 1024)
t->left = left; buf = alloca(len * sizeof(struct f_tree *));
left = t; else
} else { buf = malloc(len * sizeof(struct f_tree *));
t->left = right;
right = t;
}
} while(t = next);
median->left = build_tree(left); /* Convert a degenerated tree into an sorted array */
median->right = build_tree(right); i = 0;
return median; 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 * struct f_tree *

View File

@ -49,7 +49,8 @@ static struct resclass ev_class = {
"Event", "Event",
sizeof(event), sizeof(event),
(void (*)(resource *)) ev_postpone, (void (*)(resource *)) ev_postpone,
ev_dump ev_dump,
NULL
}; };
/** /**

View File

@ -46,10 +46,14 @@ char *ip_scope_text(unsigned);
struct prefix { struct prefix {
ip_addr addr; 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 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 * Conversions between internal and string representation

View File

@ -72,7 +72,7 @@ int ipv4_classify(u32);
u32 ipv4_class_mask(u32); u32 ipv4_class_mask(u32);
byte *ipv4_skip_header(byte *, int *); 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; return 0;
} }

View File

@ -9,6 +9,8 @@
#ifndef _BIRD_SOCKET_H_ #ifndef _BIRD_SOCKET_H_
#define _BIRD_SOCKET_H_ #define _BIRD_SOCKET_H_
#include <errno.h>
#include "lib/resource.h" #include "lib/resource.h"
typedef struct birdsock { 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); int sk_set_ipv6_checksum(sock *s, int offset);
#endif #endif
int sk_set_broadcast(sock *s, int enable);
static inline int static inline int
sk_send_buffer_empty(sock *sk) sk_send_buffer_empty(sock *sk)
{ {

View File

@ -385,7 +385,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
struct pm_pos pos[2048 + 1]; struct pm_pos pos[2048 + 1];
int plen = parse_path(path, pos); int plen = parse_path(path, pos);
int l, h, i, nh, nl; int l, h, i, nh, nl;
u32 val; u32 val = 0;
/* l and h are bound of interval of positions where /* l and h are bound of interval of positions where
are marked states */ are marked states */
@ -417,7 +417,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
goto step; goto step;
case PM_QUESTION: case PM_QUESTION:
step: step:
nh = -1; nh = nl = -1;
for (i = h; i >= l; i--) for (i = h; i >= l; i--)
if (pos[i].mark) if (pos[i].mark)
{ {

View File

@ -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); free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1);
else else
free = c->ring_read - c->ring_write - 1; free = c->ring_read - c->ring_write - 1;
if (len > free || if ((len > free) ||
free < c->log_threshold && class < (unsigned) L_INFO[0]) (free < c->log_threshold && class < (unsigned) L_INFO[0]))
{ {
c->ring_overflow++; c->ring_overflow++;
continue; continue;

View File

@ -33,6 +33,7 @@ typedef struct cli {
void (*cleanup)(struct cli *c); void (*cleanup)(struct cli *c);
void *rover; /* Private to continuation routine */ void *rover; /* Private to continuation routine */
int last_reply; int last_reply;
int restricted; /* CLI is restricted to read-only commands */
struct linpool *parser_pool; /* Pool used during parsing */ struct linpool *parser_pool; /* Pool used during parsing */
byte *ring_buf; /* Ring buffer for asynchronous messages */ byte *ring_buf; /* Ring buffer for asynchronous messages */
byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */ 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_written(cli *);
void cli_echo(unsigned int class, byte *msg); 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 */ /* Functions provided by sysdep layer */
void cli_write_trigger(cli *); void cli_write_trigger(cli *);

View File

@ -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(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION) 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, CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) 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 <s> optsym
%type <ra> r_args %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 <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 CF_GRAMMAR
@ -324,11 +324,11 @@ CF_CLI_HELP(SHOW, ..., [[Show status information]])
CF_CLI(SHOW STATUS,,, [[Show router status]]) CF_CLI(SHOW STATUS,,, [[Show router status]])
{ cmd_show_status(); } ; { cmd_show_status(); } ;
CF_CLI(SHOW PROTOCOLS, optsym, [<name>], [[Show routing protocols]]) CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]])
{ proto_show($3, 0); } ; { proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
CF_CLI(SHOW PROTOCOLS ALL, optsym, [<name>], [[Show routing protocol details]]) CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
{ proto_show($4, 1); } ; { proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
optsym: optsym:
SYM SYM
@ -459,34 +459,42 @@ echo_size:
; ;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]]) 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]]) 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]]) 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]]) 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)]]) 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)]]) 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_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]]) 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_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]]) 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: proto_patt:
SYM { $$ = $1->name; } SYM { $$.ptr = $1; $$.patt = 0; }
| ALL { $$ = "*"; } | ALL { $$.ptr = NULL; $$.patt = 1; }
| TEXT | TEXT { $$.ptr = $1; $$.patt = 1; }
; ;
proto_patt2:
SYM { $$.ptr = $1; $$.patt = 0; }
| { $$.ptr = NULL; $$.patt = 1; }
| TEXT { $$.ptr = $1; $$.patt = 1; }
;
CF_CODE CF_CODE
CF_END CF_END

View File

@ -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 * if_feed_baby - advertise interfaces to a new protocol
* @p: protocol to feed * @p: protocol to feed

View File

@ -75,8 +75,9 @@ struct iface *if_update(struct iface *);
struct ifa *ifa_update(struct ifa *); struct ifa *ifa_update(struct ifa *);
void ifa_delete(struct ifa *); void ifa_delete(struct ifa *);
void if_start_update(void); void if_start_update(void);
void if_end_update(void);
void if_end_partial_update(struct iface *); 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 *); void if_feed_baby(struct proto *);
struct iface *if_find_by_index(unsigned); struct iface *if_find_by_index(unsigned);
struct iface *if_find_by_name(char *); struct iface *if_find_by_name(char *);
@ -106,6 +107,7 @@ typedef struct neighbor {
} neighbor; } neighbor;
#define NEF_STICKY 1 #define NEF_STICKY 1
#define NEF_ONLINK 2
neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags); neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags);
neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags); neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags);

View File

@ -97,7 +97,8 @@ static struct resclass olock_class = {
"ObjLock", "ObjLock",
sizeof(struct object_lock), sizeof(struct object_lock),
olock_free, olock_free,
olock_dump olock_dump,
NULL
}; };
/** /**

View File

@ -112,12 +112,12 @@ neighbor *
neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
{ {
neighbor *n; neighbor *n;
int class, scope = SCOPE_HOST; int class, scope = -1; ;
unsigned int h = neigh_hash(p, a); unsigned int h = neigh_hash(p, a);
struct iface *i; struct iface *i;
WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ 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; return n;
class = ipa_classify(*a); 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 */ return NULL; /* Bad scope or a somecast */
if (ifa) if (ifa)
scope = if_connected(a, ifa); {
scope = if_connected(a, ifa);
if ((scope < 0) && (flags & NEF_ONLINK))
scope = class & IADDR_SCOPE_MASK;
}
else else
WALK_LIST(i, iface_list) WALK_LIST(i, iface_list)
if ((scope = if_connected(a, i)) >= 0) 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; 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; return NULL;
n = sl_alloc(neigh_slab); n = sl_alloc(neigh_slab);
n->addr = *a; n->addr = *a;
n->iface = ifa; if (scope >= 0)
if (ifa)
{ {
add_tail(&neigh_hash_table[h], &n->n); add_tail(&neigh_hash_table[h], &n->n);
add_tail(&ifa->neighbors, &n->if_n); add_tail(&ifa->neighbors, &n->if_n);
} }
else else
{ {
/* sticky flag does not work for link-local neighbors;
fortunately, we don't use this combination */
add_tail(&sticky_neigh_list, &n->n); add_tail(&sticky_neigh_list, &n->n);
ifa = NULL;
scope = 0; scope = 0;
} }
n->iface = ifa;
n->proto = p; n->proto = p;
n->data = NULL; n->data = NULL;
n->aux = 0; n->aux = 0;

View File

@ -178,13 +178,14 @@ void ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
/** /**
* rt_notify - notify instance about routing table change * rt_notify - notify instance about routing table change
* @p: protocol instance * @p: protocol instance
* @table: a routing table
* @net: a network entry * @net: a network entry
* @new: new route for the network * @new: new route for the network
* @old: old route for the network * @old: old route for the network
* @attrs: extended attributes associated with the @new entry * @attrs: extended attributes associated with the @new entry
* *
* The rt_notify() hook is called to inform the protocol instance about * 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 * belonging to network @net being replaced by a new route @new with
* extended attributes @attrs. Either @new or @old or both can be %NULL * extended attributes @attrs. Either @new or @old or both can be %NULL
* if the corresponding route doesn't exist. * if the corresponding route doesn't exist.

View File

@ -25,12 +25,6 @@ static pool *proto_pool;
static list protocol_list; static list protocol_list;
static list proto_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) #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; list active_proto_list;
@ -57,7 +51,7 @@ proto_enqueue(list *l, struct proto *p)
static void static void
proto_relink(struct proto *p) proto_relink(struct proto *p)
{ {
list *l; list *l = NULL;
if (p->debug & D_STATES) if (p->debug & D_STATES)
{ {
@ -119,7 +113,6 @@ proto_new(struct proto_config *c, unsigned size)
p->table = c->table->table; p->table = c->table->table;
p->in_filter = c->in_filter; p->in_filter = c->in_filter;
p->out_filter = c->out_filter; p->out_filter = c->out_filter;
p->min_scope = SCOPE_SITE;
p->hash_key = random_u32(); p->hash_key = random_u32();
c->proto = p; c->proto = p;
return p; return p;
@ -583,6 +576,12 @@ proto_fell_down(struct proto *p)
bzero(&p->stats, sizeof(struct proto_stats)); bzero(&p->stats, sizeof(struct proto_stats));
rt_unlock_table(p->table); 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); proto_rethink_goal(p);
} }
@ -741,6 +740,8 @@ proto_notify_state(struct proto *p, unsigned ps)
} }
} }
extern struct protocol proto_unix_iface;
static void static void
proto_flush_all(void *unused UNUSED) proto_flush_all(void *unused UNUSED)
{ {
@ -749,6 +750,11 @@ proto_flush_all(void *unused UNUSED)
rt_prune_all(); rt_prune_all();
while ((p = HEAD(flush_proto_list))->n.next) 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); DBG("Flushing protocol %s\n", p->name);
p->core_state = FS_HUNGRY; p->core_state = FS_HUNGRY;
proto_relink(p); proto_relink(p);
@ -781,10 +787,75 @@ proto_state_name(struct proto *p)
} }
static void 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]; 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; buf[0] = 0;
if (p->proto->get_status) if (p->proto->get_status)
p->proto->get_status(p, buf); p->proto->get_status(p, buf);
@ -806,21 +877,12 @@ proto_do_show(struct proto *p, int verbose)
if (p->proto_state != PS_DOWN) if (p->proto_state != PS_DOWN)
{ {
cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", #ifdef CONFIG_PIPE
p->stats.imp_routes, p->stats.exp_routes, p->stats.pref_routes); if (proto_is_pipe(p))
cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); proto_do_show_pipe_stats(p);
cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", else
p->stats.imp_updates_received, p->stats.imp_updates_invalid, #endif
p->stats.imp_updates_filtered, p->stats.imp_updates_ignored, proto_do_show_stats(p);
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);
} }
cli_msg(-1006, ""); cli_msg(-1006, "");
@ -828,25 +890,140 @@ proto_do_show(struct proto *p, int verbose)
} }
void 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(-8, "%s: already disabled", p->name);
return;
}
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)
{
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); cli_msg(9002, "%s is not a protocol", s->name);
return; return;
} }
cli_msg(-2002, "name proto table state since info");
if (s) cmd(((struct proto_config *)s->def)->proto, arg, 0);
proto_do_show(((struct proto_config *)s->def)->proto, verbose);
else
{
WALK_PROTO_LIST(p)
proto_do_show(p, verbose);
WALK_PROTO_LIST_END;
}
cli_msg(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 * struct proto *
proto_get_named(struct symbol *sym, struct protocol *pr) proto_get_named(struct symbol *sym, struct protocol *pr)
{ {
@ -875,112 +1052,3 @@ proto_get_named(struct symbol *sym, struct protocol *pr)
} }
return p; 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, "");
}

View File

@ -16,6 +16,7 @@
struct iface; struct iface;
struct ifa; struct ifa;
struct rtable;
struct rte; struct rte;
struct neighbor; struct neighbor;
struct rta; struct rta;
@ -129,7 +130,6 @@ struct proto {
u32 debug; /* Debugging flags */ u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */ u32 mrtdump; /* MRTDump flags */
unsigned preference; /* Default route preference */ 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 accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
unsigned disabled; /* Manually disabled */ unsigned disabled; /* Manually disabled */
unsigned proto_state; /* Protocol state machine (see below) */ 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 (*if_notify)(struct proto *, unsigned flags, struct iface *i);
void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); 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); void (*neigh_notify)(struct neighbor *neigh);
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs); void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs);
@ -194,21 +194,30 @@ struct proto {
/* Hic sunt protocol-specific data */ /* Hic sunt protocol-specific data */
}; };
struct proto_spec {
void *ptr;
int patt;
};
void *proto_new(struct proto_config *, unsigned size); void *proto_new(struct proto_config *, unsigned size);
void *proto_config_new(struct protocol *, unsigned size); void *proto_config_new(struct protocol *, unsigned size);
void proto_request_feeding(struct proto *p); void proto_request_feeding(struct proto *p);
void proto_show(struct symbol *, int);
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 void proto_cmd_show(struct proto *, unsigned int, int);
#define XX_ENABLE 1 void proto_cmd_disable(struct proto *, unsigned int, int);
#define XX_RESTART 2 void proto_cmd_enable(struct proto *, unsigned int, int);
#define XX_RELOAD 3 void proto_cmd_restart(struct proto *, unsigned int, int);
#define XX_RELOAD_IN 4 void proto_cmd_reload(struct proto *, unsigned int, int);
#define XX_RELOAD_OUT 5 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 *);
#define CMD_RELOAD 0
#define CMD_RELOAD_IN 1
#define CMD_RELOAD_OUT 2
static inline u32 static inline u32
proto_get_router_id(struct proto_config *pc) 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 *); 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 #endif

View File

@ -400,7 +400,7 @@ ea_format(eattr *e, byte *buf)
switch (e->type & EAF_TYPE_MASK) switch (e->type & EAF_TYPE_MASK)
{ {
case EAF_TYPE_INT: case EAF_TYPE_INT:
bsprintf(buf, "%d", e->u.data); bsprintf(buf, "%u", e->u.data);
break; break;
case EAF_TYPE_OPAQUE: case EAF_TYPE_OPAQUE:
for(i=0; i<ad->length; i++) for(i=0; i<ad->length; i++)

View File

@ -33,6 +33,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
!iface_patt_find(&P->iface_list, ad->iface)) !iface_patt_find(&P->iface_list, ad->iface))
/* Empty list is automagically treated as "*" */ /* Empty list is automagically treated as "*" */
return; return;
if (ad->scope <= SCOPE_LINK)
return;
if (c & IF_CHANGE_DOWN) if (c & IF_CHANGE_DOWN)
{ {
net *n; net *n;
@ -56,7 +60,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
bzero(&A, sizeof(A)); bzero(&A, sizeof(A));
A.proto = p; A.proto = p;
A.source = RTS_DEVICE; A.source = RTS_DEVICE;
A.scope = ad->scope; A.scope = SCOPE_UNIVERSE;
A.cast = RTC_UNICAST; A.cast = RTC_UNICAST;
A.dest = RTD_DEVICE; A.dest = RTD_DEVICE;
A.iface = ad->iface; A.iface = ad->iface;
@ -76,7 +80,6 @@ dev_init(struct proto_config *c)
struct proto *p = proto_new(c, sizeof(struct proto)); struct proto *p = proto_new(c, sizeof(struct proto));
p->ifa_notify = dev_ifa_notify; p->ifa_notify = dev_ifa_notify;
p->min_scope = SCOPE_HOST;
return p; return p;
} }

View File

@ -158,37 +158,42 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
} }
static inline void 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 proto *p = a->proto;
struct filter *filter = p->out_filter;
struct proto_stats *stats = &p->stats;
rte *new0 = new; rte *new0 = new;
rte *old0 = old; rte *old0 = old;
int ok; int ok;
int fast_exit_hack = 0; 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) if (new)
{ {
p->stats.exp_updates_received++; stats->exp_updates_received++;
char *drop_reason = NULL; char *drop_reason = NULL;
if ((class & IADDR_SCOPE_MASK) < p->min_scope) 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 = "out of scope";
fast_exit_hack = 1;
}
else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0)
{
p->stats.exp_updates_rejected++;
drop_reason = "rejected by protocol"; drop_reason = "rejected by protocol";
} }
else if (ok) else if (ok)
rte_trace_out(D_FILTERS, p, new, "forced accept by protocol"); rte_trace_out(D_FILTERS, p, new, "forced accept by protocol");
else if (p->out_filter == FILTER_REJECT || else if ((filter == FILTER_REJECT) ||
p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) (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"; drop_reason = "filtered out";
} }
if (drop_reason) if (drop_reason)
@ -200,7 +205,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
} }
} }
else else
p->stats.exp_withdraws_received++; stats->exp_withdraws_received++;
/* Hack: This is here to prevent 'spurious withdraws' /* Hack: This is here to prevent 'spurious withdraws'
for loopback addresses during reload. */ 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 (old && !refeed)
{ {
if (p->out_filter == FILTER_REJECT) if (filter == FILTER_REJECT)
old = NULL; old = NULL;
else else
{ {
ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL; 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; 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) if (old != old0)
rte_free(old); rte_free(old);
@ -249,16 +254,16 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
return; return;
if (new) if (new)
p->stats.exp_updates_accepted++; stats->exp_updates_accepted++;
else else
p->stats.exp_withdraws_accepted++; stats->exp_withdraws_accepted++;
/* Hack: We do not decrease exp_routes during refeed, we instead /* Hack: We do not decrease exp_routes during refeed, we instead
reset exp_routes at the start of refeed. */ reset exp_routes at the start of refeed. */
if (new) if (new)
p->stats.exp_routes++; stats->exp_routes++;
if (old && !refeed) if (old && !refeed)
p->stats.exp_routes--; stats->exp_routes--;
if (p->debug & D_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"); rte_trace_out(D_ROUTES, p, old, "removed");
} }
if (!new) if (!new)
p->rt_notify(p, net, NULL, old, NULL); p->rt_notify(p, a->table, net, NULL, old, NULL);
else if (tmpa) else if (tmpa)
{ {
ea_list *t = tmpa; ea_list *t = tmpa;
while (t->next) while (t->next)
t = t->next; t = t->next;
t->next = new->attrs->eattrs; 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; t->next = NULL;
} }
else 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 */ if (new && new != new0) /* Discard temporary rte's */
rte_free(new); rte_free(new);
if (old && old != old0) 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. * the protocol gets called.
*/ */
static void 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; struct announce_hook *a;
int class = ipa_classify(net->n.prefix);
if (type == RA_OPTIMAL) 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); ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING);
if (a->proto->accept_ra_types == type) 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); n->n.prefix, n->n.pxlen, e->sender->name);
return 0; 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); log(L_WARN "Ignoring bogus route %I/%d received via %s",
if (c < 0 || !(c & IADDR_HOST)) n->n.prefix, n->n.pxlen, e->sender->name);
{ return 0;
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;
}
} }
return 1; return 1;
} }
@ -416,10 +402,16 @@ rte_same(rte *x, rte *y)
static void static void
rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa) 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_best = net->routes;
rte *old = NULL; rte *old = NULL;
rte **k, *r, *s; 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 */ k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k) 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)) if (new && rte_same(old, new))
{ {
/* No changes, ignore the new route */ /* No changes, ignore the new route */
p->stats.imp_updates_ignored++; stats->imp_updates_ignored++;
rte_trace_in(D_ROUTES, p, new, "ignored"); rte_trace_in(D_ROUTES, p, new, "ignored");
rte_free_quick(new); rte_free_quick(new);
old->lastmod = now; old->lastmod = now;
@ -462,19 +454,19 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
if (!old && !new) if (!old && !new)
{ {
p->stats.imp_withdraws_ignored++; stats->imp_withdraws_ignored++;
return; return;
} }
if (new) if (new)
p->stats.imp_updates_accepted++; stats->imp_updates_accepted++;
else else
p->stats.imp_withdraws_accepted++; stats->imp_withdraws_accepted++;
if (new) if (new)
p->stats.imp_routes++; stats->imp_routes++;
if (old) if (old)
p->stats.imp_routes--; stats->imp_routes--;
rte_announce(table, RA_ANY, net, new, old, tmpa); 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) rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new)
{ {
ea_list *tmpa = NULL; 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(); rte_update_lock();
if (new) 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, /* Do not filter routes going through the pipe,
they are filtered in the export filter only. */ they are filtered in the export filter only. */
#ifdef CONFIG_PIPE #ifdef CONFIG_PIPE
if (p->proto == &proto_pipe) if (proto_is_pipe(p))
filter = FILTER_ACCEPT; filter = FILTER_ACCEPT;
#endif #endif
p->stats.imp_updates_received++; stats->imp_updates_received++;
if (!rte_validate(new)) if (!rte_validate(new))
{ {
rte_trace_in(D_FILTERS, p, new, "invalid"); rte_trace_in(D_FILTERS, p, new, "invalid");
p->stats.imp_updates_invalid++; stats->imp_updates_invalid++;
goto drop; goto drop;
} }
if (filter == FILTER_REJECT) if (filter == FILTER_REJECT)
{ {
p->stats.imp_updates_filtered++; stats->imp_updates_filtered++;
rte_trace_in(D_FILTERS, p, new, "filtered out"); rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop; 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); int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0);
if (fr > F_ACCEPT) if (fr > F_ACCEPT)
{ {
p->stats.imp_updates_filtered++; stats->imp_updates_filtered++;
rte_trace_in(D_FILTERS, p, new, "filtered out"); rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop; goto drop;
} }
@ -679,7 +677,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
new->flags |= REF_COW; new->flags |= REF_COW;
} }
else else
p->stats.imp_withdraws_received++; stats->imp_withdraws_received++;
rte_recalculate(table, net, p, src, new, tmpa); rte_recalculate(table, net, p, src, new, tmpa);
rte_update_unlock(); 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(); rte_update_lock();
tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; 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(); 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 (p2 && p2 != p0) ok = 0;
if (ok && d->export_mode) if (ok && d->export_mode)
{ {
int class = ipa_classify(n->n.prefix);
int ic; int ic;
if ((class & IADDR_SCOPE_MASK) < p1->min_scope) if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0)
ok = 0;
else if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0)
ok = 0; ok = 0;
else if (!ic && d->export_mode > 1) 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 'configure soft' command may change the export filter
and do not update routes */ and do not update routes */
if (p1->out_filter == FILTER_REJECT || if ((p1->out_filter == FILTER_REJECT) ||
p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) (p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
ok = 0; ok = 0;
} }
} }

View File

@ -47,7 +47,7 @@ bgp_check_origin(struct bgp_proto *p UNUSED, byte *a, int len UNUSED)
} }
static void 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" }; static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
@ -257,14 +257,14 @@ static struct attr_desc bgp_attr_table[] = {
NULL, NULL }, NULL, NULL },
{ "cluster_list", -1, BAF_OPTIONAL, EAF_TYPE_INT_SET, 0, /* BA_CLUSTER_LIST */ { "cluster_list", -1, BAF_OPTIONAL, EAF_TYPE_INT_SET, 0, /* BA_CLUSTER_LIST */
bgp_check_cluster_list, bgp_format_cluster_list }, bgp_check_cluster_list, bgp_format_cluster_list },
{ NULL, }, /* BA_DPA */ { .name = NULL }, /* BA_DPA */
{ NULL, }, /* BA_ADVERTISER */ { .name = NULL }, /* BA_ADVERTISER */
{ NULL, }, /* BA_RCID_PATH */ { .name = NULL }, /* BA_RCID_PATH */
{ "mp_reach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_REACH_NLRI */ { "mp_reach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_REACH_NLRI */
bgp_check_reach_nlri, NULL }, bgp_check_reach_nlri, NULL },
{ "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_UNREACH_NLRI */ { "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_UNREACH_NLRI */
bgp_check_unreach_nlri, NULL }, 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 */ { "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */
NULL, NULL }, NULL, NULL },
{ "as4_aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */ { "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 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_proto *p = (struct bgp_proto *) P;
struct bgp_bucket *buck; struct bgp_bucket *buck;
@ -1070,16 +1070,6 @@ bgp_rte_better(rte *new, rte *old)
/* Skipping RFC 4271 9.1.2.2. e) */ /* Skipping RFC 4271 9.1.2.2. e) */
/* We don't have interior distances */ /* 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 4271 9.1.2.2. f) Compare BGP identifiers */
/* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighor ID */ /* 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)); 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) if (n > o)
return 0; 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 */ /* 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); return (ipa_compare(new_bgp->cf->remote_ip, old_bgp->cf->remote_ip) < 0);
} }

View File

@ -203,7 +203,7 @@ bgp_start_timer(timer *t, int value)
void void
bgp_close_conn(struct bgp_conn *conn) bgp_close_conn(struct bgp_conn *conn)
{ {
struct bgp_proto *p = conn->bgp; // struct bgp_proto *p = conn->bgp;
DBG("BGP: Closing connection\n"); DBG("BGP: Closing connection\n");
conn->packets_to_send = 0; conn->packets_to_send = 0;
@ -237,7 +237,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
DBG("BGP: Updating startup delay\n"); 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->startup_delay = 0;
p->last_proto_error = now; p->last_proto_error = now;
@ -492,7 +492,7 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
} }
static void 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->data = conn;
s->err_hook = bgp_sock_err; 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; s->tx_hook = bgp_connected;
BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr); BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr);
bgp_setup_conn(p, conn); bgp_setup_conn(p, conn);
bgp_setup_sk(p, conn, s); bgp_setup_sk(conn, s);
bgp_conn_set_state(conn, BS_CONNECT); bgp_conn_set_state(conn, BS_CONNECT);
if (sk_open(s)) if (sk_open(s))
{ {
@ -601,7 +601,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
goto err; goto err;
bgp_setup_conn(p, &p->incoming_conn); 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); sk_set_ttl(sk, p->cf->multihop ? : 1);
bgp_send_open(&p->incoming_conn); bgp_send_open(&p->incoming_conn);
return 0; return 0;
@ -614,6 +614,15 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
return 0; 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 * static sock *
bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags) 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->rbsize = BGP_RX_BUFFER_SIZE;
s->tbsize = BGP_TX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE;
s->rx_hook = bgp_incoming_connection; s->rx_hook = bgp_incoming_connection;
s->err_hook = bgp_listen_sock_err;
if (sk_open(s)) if (sk_open(s))
{ {
log(L_ERR "Unable to open incoming BGP socket"); log(L_ERR "BGP: Unable to open incoming socket");
rfree(s); rfree(s);
return NULL; return NULL;
} }

View File

@ -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); 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_get_attr(struct eattr *e, byte *buf, int buflen);
int bgp_rte_better(struct rte *, struct rte *); 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 *); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
void bgp_attr_init(struct bgp_proto *); void bgp_attr_init(struct bgp_proto *);
unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains); unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains);

View File

@ -59,7 +59,7 @@ bgp_proto:
BGP_CFG->remote_ip = $3; BGP_CFG->remote_ip = $3;
BGP_CFG->remote_as = $5; 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 RR CLIENT ';' { BGP_CFG->rr_client = 1; }
| bgp_proto RS CLIENT ';' { BGP_CFG->rs_client = 1; } | bgp_proto RS CLIENT ';' { BGP_CFG->rs_client = 1; }
| bgp_proto HOLD TIME expr ';' { BGP_CFG->hold_time = $4; } | bgp_proto HOLD TIME expr ';' { BGP_CFG->hold_time = $4; }

View File

@ -44,7 +44,6 @@ static byte *
mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4)
{ {
struct bgp_proto *p = conn->bgp; struct bgp_proto *p = conn->bgp;
ip_addr local_addr;
if (as4) if (as4)
{ {
@ -614,7 +613,7 @@ bgp_tx(sock *sk)
void void
bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len) 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; int cl;
while (len > 0) while (len > 0)
@ -915,7 +914,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
rta *a = NULL; rta *a = NULL;
ip_addr prefix; ip_addr prefix;
net *n; net *n;
rte e;
int err = 0, pxlen; int err = 0, pxlen;
p->mp_reach_len = 0; p->mp_reach_len = 0;
@ -937,8 +935,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
DO_NLRI(mp_reach) DO_NLRI(mp_reach)
{ {
int i;
/* Create fake NEXT_HOP attribute */ /* Create fake NEXT_HOP attribute */
if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2) if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
goto bad; goto bad;

View File

@ -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_ospf *po = ifa->oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
char *beg = "OSPF: Bad HELLO packet from "; char *beg = "OSPF: Bad HELLO packet from ";
unsigned int size, i, twoway, oldpriority, eligible, peers; unsigned int size, i, twoway, eligible, peers;
u32 olddr, oldbdr, oldiface_id, tmp; u32 tmp;
u32 *pnrid; u32 *pnrid;
size = ntohs(ps_i->length); size = ntohs(ps_i->length);
@ -169,11 +169,11 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
if (!twoway) if (!twoway)
ospf_neigh_sm(n, INM_1WAYREC); ospf_neigh_sm(n, INM_1WAYREC);
olddr = n->dr; u32 olddr = n->dr;
oldbdr = n->bdr; u32 oldbdr = n->bdr;
oldpriority = n->priority; u32 oldpriority = n->priority;
#ifdef OSPFv3 #ifdef OSPFv3
oldiface_id = n->iface_id; u32 oldiface_id = n->iface_id;
#endif #endif
n->dr = ntohl(ps->dr); n->dr = ntohl(ps->dr);

View File

@ -122,22 +122,22 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
} }
void void
htonlsab(void *h, void *n, u16 type, u16 len) htonlsab(void *h, void *n, u16 len)
{ {
u32 *hid = h; u32 *hid = h;
u32 *nid = n; u32 *nid = n;
int i; unsigned i;
for (i = 0; i < (len / sizeof(u32)); i++) for (i = 0; i < (len / sizeof(u32)); i++)
nid[i] = htonl(hid[i]); nid[i] = htonl(hid[i]);
} }
void void
ntohlsab(void *n, void *h, u16 type, u16 len) ntohlsab(void *n, void *h, u16 len)
{ {
u32 *nid = n; u32 *nid = n;
u32 *hid = h; u32 *hid = h;
int i; unsigned i;
for (i = 0; i < (len / sizeof(u32)); i++) for (i = 0; i < (len / sizeof(u32)); i++)
hid[i] = ntohl(nid[i]); hid[i] = ntohl(nid[i]);
@ -185,11 +185,10 @@ void
lsasum_calculate(struct ospf_lsa_header *h, void *body) lsasum_calculate(struct ospf_lsa_header *h, void *body)
{ {
u16 length = h->length; 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); // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
htonlsah(h, h); 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]; char buf[1024];
@ -203,7 +202,7 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
// log(L_WARN "Checksum result %4x", h->checksum); // log(L_WARN "Checksum result %4x", h->checksum);
ntohlsah(h, h); 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 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))) if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
return 0; return 0;

View File

@ -12,8 +12,8 @@
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n); 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 ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
void htonlsab(void *h, void *n, u16 type, u16 len); void htonlsab(void *h, void *n, u16 len);
void ntohlsab(void *n, void *h, u16 type, u16 len); void ntohlsab(void *n, void *h, u16 len);
void lsasum_calculate(struct ospf_lsa_header *header, void *body); void lsasum_calculate(struct ospf_lsa_header *header, void *body);
u16 lsasum_check(struct ospf_lsa_header *h, void *body); u16 lsasum_check(struct ospf_lsa_header *h, void *body);
#define CMP_NEWER 1 #define CMP_NEWER 1

View File

@ -290,8 +290,7 @@ ospf_lsupd_flood(struct proto_ospf *po,
htonlsah(hh, lh); htonlsah(hh, lh);
help = (u8 *) (lh + 1); help = (u8 *) (lh + 1);
en = ospf_hash_find_header(po->gr, domain, hh); en = ospf_hash_find_header(po->gr, domain, hh);
htonlsab(en->lsa_body, help, hh->type, hh->length htonlsab(en->lsa_body, help, hh->length - sizeof(struct ospf_lsa_header));
- sizeof(struct ospf_lsa_header));
} }
len = sizeof(struct ospf_lsupd_packet) + ntohs(lh->length); 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); htonlsah(&(en->lsa), pktpos);
pktpos = pktpos + sizeof(struct ospf_lsa_header); pktpos = pktpos + sizeof(struct ospf_lsa_header);
htonlsab(en->lsa_body, pktpos, en->lsa.type, en->lsa.length htonlsab(en->lsa_body, pktpos, en->lsa.length - sizeof(struct ospf_lsa_header));
- sizeof(struct ospf_lsa_header));
pktpos = pktpos + en->lsa.length - sizeof(struct ospf_lsa_header); pktpos = pktpos + en->lsa.length - sizeof(struct ospf_lsa_header);
len += en->lsa.length; len += en->lsa.length;
lsano++; lsano++;
@ -627,8 +625,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
/* pg 144 (5d) */ /* pg 144 (5d) */
void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header)); void *body = mb_alloc(p->pool, lsatmp.length - sizeof(struct ospf_lsa_header));
ntohlsab(lsa + 1, body, lsatmp.type, ntohlsab(lsa + 1, body, lsatmp.length - sizeof(struct ospf_lsa_header));
lsatmp.length - sizeof(struct ospf_lsa_header));
/* We will do validation check after flooding and /* We will do validation check after flooding and
acknowledging given LSA to minimize problems acknowledging given LSA to minimize problems

View File

@ -440,7 +440,6 @@ void
bdr_election(struct ospf_iface *ifa) bdr_election(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
u32 myid = po->router_id; u32 myid = po->router_id;
struct ospf_neighbor *neigh, *ndr, *nbdr, me; struct ospf_neighbor *neigh, *ndr, *nbdr, me;
int doadj; int doadj;
@ -631,7 +630,7 @@ static void
rxmt_timer_hook(timer * timer) rxmt_timer_hook(timer * timer)
{ {
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; 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; struct top_hash_entry *en;
DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n", DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n",

View File

@ -78,7 +78,7 @@
static int ospf_reload_routes(struct proto *p); 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 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_better(struct rte *new, struct rte *old);
static int ospf_rte_same(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_TRACE(D_EVENTS, "LSA graph dump start:");
ospf_top_dump(po->gr, p); ospf_top_dump(po->gr, p);
OSPF_TRACE(D_EVENTS, "LSA graph dump finished"); OSPF_TRACE(D_EVENTS, "LSA graph dump finished");
*/
neigh_dump_all(); neigh_dump_all();
} }
@ -486,8 +488,7 @@ ospf_shutdown(struct proto *p)
} }
static void static void
ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs)
ea_list * attrs)
{ {
struct proto_ospf *po = (struct proto_ospf *) p; 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 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 proto_ospf *po = (struct proto_ospf *) p;
struct ospf_iface *ifa; struct ospf_iface *ifa;
@ -918,7 +919,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
void void
ospf_sh_neigh(struct proto *p, char *iff) ospf_sh_neigh(struct proto *p, char *iff)
{ {
struct ospf_iface *ifa = NULL, *f; struct ospf_iface *ifa = NULL;
struct ospf_neighbor *n; struct ospf_neighbor *n;
struct proto_ospf *po = (struct proto_ospf *) p; struct proto_ospf *po = (struct proto_ospf *) p;
@ -1009,7 +1010,7 @@ void
ospf_sh_iface(struct proto *p, char *iff) ospf_sh_iface(struct proto *p, char *iff)
{ {
struct proto_ospf *po = (struct proto_ospf *) p; 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) if (p->proto_state != PS_UP)
{ {
@ -1196,7 +1197,6 @@ show_lsa_network(struct top_hash_entry *he)
static inline void static inline void
show_lsa_sum_net(struct top_hash_entry *he) show_lsa_sum_net(struct top_hash_entry *he)
{ {
struct ospf_lsa_header *lsa = &(he->lsa);
ip_addr ip; ip_addr ip;
int pxlen; int pxlen;
@ -1236,9 +1236,7 @@ show_lsa_sum_rt(struct top_hash_entry *he)
static inline void static inline void
show_lsa_external(struct top_hash_entry *he) 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 *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_via[STD_ADDRESS_P_LENGTH + 8] = "";
char str_tag[16] = ""; char str_tag[16] = "";
ip_addr ip, rt_fwaddr; ip_addr ip, rt_fwaddr;
@ -1248,7 +1246,7 @@ show_lsa_external(struct top_hash_entry *he)
rt_metric = ext->metric & METRIC_MASK; rt_metric = ext->metric & METRIC_MASK;
ebit = ext->metric & LSA_EXT_EBIT; ebit = ext->metric & LSA_EXT_EBIT;
#ifdef OSPFv2 #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); pxlen = ipa_mklen(ext->netmask);
rt_fwaddr = ext->fwaddr; rt_fwaddr = ext->fwaddr;
rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE); rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
@ -1285,10 +1283,7 @@ show_lsa_external(struct top_hash_entry *he)
static inline void static inline void
show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *olsa) 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_prefix *px = he->lsa_body;
struct ospf_lsa_ext *ext = he->lsa_body;
char *msg;
ip_addr pxa; ip_addr pxa;
int pxlen; int pxlen;
u8 pxopts; u8 pxopts;
@ -1496,8 +1491,6 @@ ospf_sh_lsadb(struct proto *p)
if ((dscope != last_dscope) || (hea[i]->domain != last_domain)) if ((dscope != last_dscope) || (hea[i]->domain != last_domain))
{ {
struct iface *ifa;
cli_msg(-1017, ""); cli_msg(-1017, "");
switch (dscope) switch (dscope)
{ {
@ -1509,8 +1502,10 @@ ospf_sh_lsadb(struct proto *p)
break; break;
#ifdef OSPFv3 #ifdef OSPFv3
case LSA_SCOPE_LINK: 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; break;
#endif #endif
} }

View File

@ -705,7 +705,7 @@ struct ospf_area
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */ struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
list cand; /* List of candidates for RT calc. */ list cand; /* List of candidates for RT calc. */
struct fib net_fib; /* Networks to advertise or not */ struct fib net_fib; /* Networks to advertise or not */
int stub; unsigned stub;
int trcap; /* Transit capability? */ int trcap; /* Transit capability? */
u32 options; /* Optional features */ u32 options; /* Optional features */
struct proto_ospf *po; struct proto_ospf *po;
@ -782,13 +782,14 @@ void schedule_net_lsa(struct ospf_iface *ifa);
#ifdef OSPFv3 #ifdef OSPFv3
void schedule_link_lsa(struct ospf_iface *ifa); void schedule_link_lsa(struct ospf_iface *ifa);
#else #else
static inline void schedule_link_lsa(struct ospf_iface *ifa) {} static inline void schedule_link_lsa(struct ospf_iface *ifa UNUSED) {}
#endif #endif
void ospf_sh_neigh(struct proto *p, char *iff); void ospf_sh_neigh(struct proto *p, char *iff);
void ospf_sh(struct proto *p); void ospf_sh(struct proto *p);
void ospf_sh_iface(struct proto *p, char *iff); void ospf_sh_iface(struct proto *p, char *iff);
void ospf_sh_state(struct proto *p, int verbose); 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) #define EA_OSPF_METRIC1 EA_CODE(EAP_OSPF, 0)

View File

@ -14,7 +14,6 @@ void
ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
{ {
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
struct ospf_packet *pkt; struct ospf_packet *pkt;
pkt = (struct ospf_packet *) buf; 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 */ /* Initially, the packet is associated with the 'master' iface */
struct ospf_iface *ifa = sk->data; struct ospf_iface *ifa = sk->data;
struct proto_ospf *po = ifa->oa->po; 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 src_local = ifa_match_addr(ifa->addr, sk->faddr);
int dst_local = ipa_equal(sk->laddr, ifa->addr->ip); int dst_local = ipa_equal(sk->laddr, ifa->addr->ip);

View File

@ -170,7 +170,7 @@ static void
process_prefixes(struct ospf_area *oa) process_prefixes(struct ospf_area *oa)
{ {
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct proto *p = &po->proto; // struct proto *p = &po->proto;
struct top_hash_entry *en, *src; struct top_hash_entry *en, *src;
struct ospf_lsa_prefix *px; struct ospf_lsa_prefix *px;
ip_addr pxa; ip_addr pxa;
@ -226,9 +226,8 @@ process_prefixes(struct ospf_area *oa)
static void static void
ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en) 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; struct proto_ospf *po = oa->po;
orta nf;
u32 i; u32 i;
struct ospf_lsa_rt *rt = en->lsa_body; 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"); DBG("\n");
orta nf;
nf.type = RTS_OSPF; nf.type = RTS_OSPF;
nf.options = 0; nf.options = 0;
nf.metric1 = act->dist + rtl->metric; 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 static void
ospf_rt_sum_tr(struct ospf_area *oa) 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 proto_ospf *po = oa->po;
struct ospf_area *bb = po->backbone; struct ospf_area *bb = po->backbone;
ip_addr ip, abrip; ip_addr ip, abrip;
@ -573,7 +573,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
type = ORT_NET; type = ORT_NET;
re = fib_find(&po->rtf, &ip, pxlen); 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 #ifdef OSPFv2
struct ospf_lsa_sum *ls = en->lsa_body; 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, calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par) struct top_hash_entry *par)
{ {
// struct proto *p = &oa->po->proto;
struct ospf_neighbor *neigh; struct ospf_neighbor *neigh;
struct proto *p = &oa->po->proto;
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct ospf_iface *ifa; struct ospf_iface *ifa;

View File

@ -741,7 +741,7 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
} }
void 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_ospf *po = oa->po;
struct proto *p = &po->proto; 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); u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
int gw = 0; int gw = 0;
int size = sizeof(struct ospf_lsa_ext); int size = sizeof(struct ospf_lsa_ext);
u32 *buf;
if ((e->attrs->dest == RTD_ROUTER) && if ((e->attrs->dest == RTD_ROUTER) &&
!ipa_equal(e->attrs->gw, IPA_NONE) && !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->fwaddr = gw ? e->attrs->gw : IPA_NONE;
ext->tag = tag; ext->tag = tag;
#else /* OSPFv3 */ #else /* OSPFv3 */
buf = ext->rest; u32 *buf = ext->rest;
buf = put_ipv6_prefix(buf, n->n.prefix, n->n.pxlen, 0, 0); buf = put_ipv6_prefix(buf, n->n.prefix, n->n.pxlen, 0, 0);
if (gw) if (gw)
@ -1015,7 +1014,6 @@ flush_ext_lsa(net *n, struct proto_ospf *po)
{ {
struct proto *p = &po->proto; struct proto *p = &po->proto;
struct fib_node *fn = &n->n; struct fib_node *fn = &n->n;
struct ospf_area *oa;
struct top_hash_entry *en; struct top_hash_entry *en;
OSPF_TRACE(D_EVENTS, "Flushing AS-external-LSA for %I/%d", 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"); bug("ospf_hash_delete() called for invalid node");
} }
/*
static void static void
ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
{ {
/*
struct ospf_lsa_rt *rt = NULL; struct ospf_lsa_rt *rt = NULL;
struct ospf_lsa_rt_link *rr = NULL; struct ospf_lsa_rt_link *rr = NULL;
struct ospf_lsa_net *ln = NULL; struct ospf_lsa_net *ln = NULL;
@ -1686,7 +1685,6 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p)
default: default:
break; break;
} }
*/
} }
void void
@ -1702,6 +1700,7 @@ ospf_top_dump(struct top_graph *f, struct proto *p)
ospf_dump_lsa(e, p); ospf_dump_lsa(e, p);
} }
} }
*/
/* This is very inefficient, please don't call it often */ /* This is very inefficient, please don't call it often */

View File

@ -31,9 +31,12 @@
#include "pipe.h" #include "pipe.h"
static void 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; struct proto *src;
net *nn; net *nn;
rte *e; rte *e;
rta a; 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; 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 static int
pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED) pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
{ {
struct proto *pp = (*ee)->sender; 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 -1; /* Avoid local loops automatically */
return 0; return 0;
} }
@ -130,60 +115,20 @@ static int
pipe_start(struct proto *P) pipe_start(struct proto *P)
{ {
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_proto *p = (struct pipe_proto *) P;
struct pipe_proto *ph;
struct announce_hook *a; struct announce_hook *a;
/* /* Clean up the secondary stats */
* Create a phantom protocol which will represent the remote bzero(&p->peer_stats, sizeof(struct proto_stats));
* 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;
/* /* Lock the peer table, unlock is handled in proto_fell_down() */
* 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;
/*
* 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.
*/
a = proto_add_announce_hook(P, p->peer);
a->proto = &ph->p;
rt_lock_table(p->peer); rt_lock_table(p->peer);
/* Connect the protocol also to the peer routing table. */
a = proto_add_announce_hook(P, p->peer);
return PS_UP; 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 * static struct proto *
pipe_init(struct proto_config *C) pipe_init(struct proto_config *C)
{ {
@ -194,9 +139,10 @@ pipe_init(struct proto_config *C)
p->peer = c->peer->table; p->peer = c->peer->table;
p->mode = c->mode; p->mode = c->mode;
P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY; 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->import_control = pipe_import_control;
P->reload_routes = pipe_reload_routes; P->reload_routes = pipe_reload_routes;
return P; return P;
} }
@ -222,25 +168,23 @@ pipe_get_status(struct proto *P, byte *buf)
static int static int
pipe_reconfigure(struct proto *P, struct proto_config *new) 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 *o = (struct pipe_config *) P->cf;
struct pipe_config *n = (struct pipe_config *) new; struct pipe_config *n = (struct pipe_config *) new;
if ((o->peer->table != n->peer->table) || (o->mode != n->mode)) if ((o->peer->table != n->peer->table) || (o->mode != n->mode))
return 0; return 0;
/* Update also the filter in the phantom protocol */
p->phantom->p.out_filter = new->in_filter;
return 1; return 1;
} }
struct protocol proto_pipe = { struct protocol proto_pipe = {
name: "Pipe", name: "Pipe",
template: "pipe%d", template: "pipe%d",
postconfig: pipe_postconfig, postconfig: pipe_postconfig,
init: pipe_init, init: pipe_init,
start: pipe_start, start: pipe_start,
shutdown: pipe_shutdown,
reconfigure: pipe_reconfigure, reconfigure: pipe_reconfigure,
get_status: pipe_get_status, get_status: pipe_get_status,
}; };

View File

@ -21,8 +21,20 @@ struct pipe_config {
struct pipe_proto { struct pipe_proto {
struct proto p; struct proto p;
struct rtable *peer; struct rtable *peer;
struct proto_stats peer_stats; /* Statistics for the direction peer->primary */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */ 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 #endif

View File

@ -752,6 +752,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
return NULL; return NULL;
} }
/* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */ /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */
return rif;
} }
static void 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. * own), so store it into our data structures.
*/ */
static void 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; CHK_MAGIC;
@ -955,7 +957,7 @@ rip_rte_insert(net *net UNUSED, rte *rte)
static void static void
rip_rte_remove(net *net UNUSED, rte *rte) rip_rte_remove(net *net UNUSED, rte *rte)
{ {
struct proto *p = rte->attrs->proto; // struct proto *p = rte->attrs->proto;
CHK_MAGIC; CHK_MAGIC;
DBG( "rip_rte_remove: %p\n", rte ); DBG( "rip_rte_remove: %p\n", rte );
rem_node( &rte->u.rip.garbage ); rem_node( &rte->u.rip.garbage );

View File

@ -125,11 +125,12 @@ static_shutdown(struct proto *p)
struct static_config *c = (void *) p->cf; struct static_config *c = (void *) p->cf;
struct static_route *r; 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) WALK_LIST(r, c->iface_routes)
static_remove(p, r); r->installed = 0;
WALK_LIST(r, c->other_routes) WALK_LIST(r, c->other_routes)
static_remove(p, r); r->installed = 0;
return PS_DOWN; return PS_DOWN;
} }
@ -294,7 +295,7 @@ static_show_rt(struct static_route *r)
switch (r->dest) switch (r->dest)
{ {
case RTD_ROUTER: bsprintf(via, "via %I", r->via); break; 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_BLACKHOLE: bsprintf(via, "blackhole"); break;
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;

View File

@ -33,39 +33,8 @@
#include "lib/string.h" #include "lib/string.h"
#include "lib/socket.h" #include "lib/socket.h"
#ifdef IPV6
#define HOST_MASK 128
#else
#define HOST_MASK 32
#endif
int rt_sock = 0; 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 int
krt_capable(rte *e) krt_capable(rte *e)
{ {
@ -83,7 +52,7 @@ krt_capable(rte *e)
|| a->dest == RTD_UNREACHABLE || a->dest == RTD_UNREACHABLE
#endif #endif
#ifdef RTF_BLACKHOLE #ifdef RTF_BLACKHOLE
|| a->dest == RTD_BLACKHOLE /* FIXME Prohibited? */ || a->dest == RTD_BLACKHOLE
#endif #endif
); );
} }
@ -96,6 +65,13 @@ krt_capable(rte *e)
l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\ l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
memmove(body, &(u), l); body += l;} 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 static void
krt_sock_send(int cmd, rte *e) krt_sock_send(int cmd, rte *e)
{ {
@ -108,7 +84,7 @@ krt_sock_send(int cmd, rte *e)
char *body = (char *)msg.buf; char *body = (char *)msg.buf;
sockaddr gate, mask, dst; 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(&dst, net->n.prefix, 0);
fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), 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_type = cmd;
msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_seq = msg_seq++;
msg.rtm.rtm_addrs = RTA_DST; 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; msg.rtm.rtm_flags |= RTF_HOST;
} }
@ -200,12 +176,12 @@ krt_sock_send(int cmd, rte *e)
msg.rtm.rtm_msglen = l; msg.rtm.rtm_msglen = l;
if ((l = write(rt_sock, (char *)&msg, l)) < 0) { 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 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) if (old)
{ {
@ -258,68 +234,87 @@ krt_set_start(struct krt_proto *x, int first UNUSED)
bug("krt-sock: sk_open failed"); bug("krt-sock: sk_open failed");
} }
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
static void static void
krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
{ {
sockaddr gate, mask, dst;
rta a; rta a;
rte *e; rte *e;
net *net; net *net;
sockaddr dst, gate, mask;
ip_addr idst, igate, imask; ip_addr idst, igate, imask;
void *body = (char *)msg->buf; void *body = (char *)msg->buf;
int new = (msg->rtm.rtm_type == RTM_ADD); int new = (msg->rtm.rtm_type == RTM_ADD);
int src; int src;
char *errmsg = "KRT: Invalid route received";
int flags = msg->rtm.rtm_flags; int flags = msg->rtm.rtm_flags;
int addrs = msg->rtm.rtm_addrs; int addrs = msg->rtm.rtm_addrs;
int masklen = -1;
if (!(flags & RTF_UP)) if (!(flags & RTF_UP) && scan)
{ SKIP("not up in scan\n");
DBG("Down.\n");
return;
}
if (flags & RTF_HOST) if (!(flags & RTF_DONE) && !scan)
masklen = HOST_MASK; 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) \ if (sa_family_check(&dst))
bzero(p, sizeof(*p));\ get_sockaddr(&dst, &idst, NULL, 0);
if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\ else
unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ SKIP("invalid DST");
memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
body += l;}
GETADDR (&dst, RTA_DST); /* We will check later whether we have valid gateway addr */
GETADDR (&gate, RTA_GATEWAY); if (sa_family_check(&gate))
GETADDR (&mask, RTA_NETMASK); get_sockaddr(&gate, &igate, NULL, 0);
else
igate = IPA_NONE;
idst = IPA_NONE; /* We do not test family for RTA_NETMASK, because BSD sends us
igate = IPA_NONE; some strange values, but interpreting them as IPv4/IPv6 works */
imask = IPA_NONE;
get_sockaddr(&dst, &idst, NULL, 0);
if(CHECK_FAMILY(&gate)) get_sockaddr(&gate, &igate, NULL, 0);
get_sockaddr(&mask, &imask, NULL, 0); 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");
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 ((flags & RTF_GATEWAY) && ipa_zero(igate))
{ log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; }
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)) if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
{ src = KRT_SRC_REDIRECT;
log(L_WARN "krt: Ignoring redirect to %I/%d via %I", idst, masklen, igate); else if (flags & self_mask)
return; {
} if (!scan)
SKIP("echo\n");
src = KRT_SRC_BIRD;
}
else if (flags & alien_mask)
src = KRT_SRC_ALIEN;
else
src = KRT_SRC_KERNEL;
if (masklen < 0) net = net_get(p->p.table, idst, pxlen);
{
log(L_WARN "krt: Got invalid route from kernel!");
return;
}
net = net_get(p->p.table, idst, masklen);
bzero(&a, sizeof(a)); 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.iface = NULL;
a.eattrs = NULL; a.eattrs = NULL;
a.dest = RTD_NONE; /* reject/blackhole routes have also set RTF_GATEWAY,
we wil check them first. */
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);
}
#ifdef RTF_REJECT #ifdef RTF_REJECT
if(flags & RTF_REJECT) { if(flags & RTF_REJECT) {
a.dest = RTD_UNREACHABLE; a.dest = RTD_UNREACHABLE;
a.gw = IPA_NONE; goto done;
} }
#endif #endif
#ifdef RTF_BLACKHOLE #ifdef RTF_BLACKHOLE
if(flags & RTF_BLACKHOLE) { if(flags & RTF_BLACKHOLE) {
a.dest = RTD_BLACKHOLE; a.dest = RTD_BLACKHOLE;
a.gw = IPA_NONE; goto done;
} }
#endif #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); neighbor *ng;
return; a.dest = RTD_ROUTER;
a.gw = igate;
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;
src = KRT_SRC_UNKNOWN; /* FIXME */ done:
e = rte_get_temp(&a); e = rte_get_temp(&a);
e->net = net; e->net = net;
e->u.krt.src = src; 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; e->u.krt.metric = 0;
if (scan) if (scan)
@ -471,6 +466,10 @@ krt_read_addr(struct ks_msg *msg)
int scope, masklen = -1; int scope, masklen = -1;
int new = (ifam->ifam_type == RTM_NEWADDR); 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))) if(!(iface = if_find_by_index(ifam->ifam_index)))
{ {
log(L_ERR "KIF: Received address message for unknown interface %d", 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 (&null, RTA_AUTHOR);
GETADDR (&brd, RTA_BRD); 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(&addr, &iaddr, NULL, 0);
get_sockaddr(&mask, &imask, 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)); memcpy(&ifa.brd, &ibrd, sizeof(ip_addr));
scope = ipa_classify(ifa.ip); scope = ipa_classify(ifa.ip);
ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
if (scope < 0) if (scope < 0)
{ {
log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name); 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; 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) if (new)
ifa_update(&ifa); ifa_update(&ifa);
else else
@ -593,27 +599,27 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
mib[4] = cmd; mib[4] = cmd;
mib[5] = 0; mib[5] = 0;
if( sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0) if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
{ {
die("RT scan..."); die("RT scan...");
} }
obl = *bl; obl = *bl;
while(needed > *bl) *bl *= 2; while (needed > *bl) *bl *= 2;
while(needed < (*bl/2)) *bl /= 2; while (needed < (*bl/2)) *bl /= 2;
if( (obl!=*bl) || !*buf) if ((obl!=*bl) || !*buf)
{ {
if(*buf) mb_free(*buf); if (*buf) mb_free(*buf);
if( (*buf = mb_alloc(pool, *bl)) == NULL ) die("RT scan buf alloc"); if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc");
} }
on = needed; 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"); 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 void
krt_scan_fire(struct krt_proto *p) krt_scan_fire(struct krt_proto *p)
{ {
static byte *buf = NULL; krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP);
static size_t bl = 32768;
krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP);
} }
void void
krt_if_scan(struct kif_proto *p) krt_if_scan(struct kif_proto *p)
{ {
static byte *buf = NULL;
static size_t bl = 4096;
struct proto *P = (struct proto *)p; struct proto *P = (struct proto *)p;
if_start_update(); 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(); if_end_update();
} }
@ -652,7 +659,9 @@ krt_set_construct(struct krt_config *c UNUSED)
void void
krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED) krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
{ {
} mb_free(krt_buffer);
krt_buffer = NULL;
}
void void
krt_if_io_init(void) krt_if_io_init(void)
@ -672,5 +681,7 @@ krt_if_start(struct kif_proto *p UNUSED)
void void
krt_if_shutdown(struct kif_proto *p UNUSED) krt_if_shutdown(struct kif_proto *p UNUSED)
{ {
mb_free(kif_buffer);
kif_buffer = NULL;
} }

View File

@ -9,7 +9,7 @@
#define IPV6 #define IPV6
#define CONFIG_AUTO_ROUTES #define CONFIG_AUTO_ROUTES
#undef CONFIG_SELF_CONSCIOUS #define CONFIG_SELF_CONSCIOUS
#undef CONFIG_MULTIPLE_TABLES #undef CONFIG_MULTIPLE_TABLES
#undef CONFIG_UNIX_IFACE #undef CONFIG_UNIX_IFACE

View File

@ -7,7 +7,7 @@
*/ */
#define CONFIG_AUTO_ROUTES #define CONFIG_AUTO_ROUTES
#undef CONFIG_SELF_CONSCIOUS #define CONFIG_SELF_CONSCIOUS
#undef CONFIG_MULTIPLE_TABLES #undef CONFIG_MULTIPLE_TABLES
#undef CONFIG_UNIX_IFACE #undef CONFIG_UNIX_IFACE

View File

@ -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_scan = {.fd = -1}; /* Netlink socket for synchronous scan */
static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */ static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */
static void static void
nl_open_sock(struct nl_sock *nl) 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); nl_send_route(p, new, 1);
} }
static struct iface * #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
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;
}
static void static void
nl_parse_route(struct nlmsghdr *h, int scan) nl_parse_route(struct nlmsghdr *h, int scan)
@ -599,31 +582,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
#endif #endif
(a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr))) (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
{ {
log(L_ERR "nl_parse_route: Malformed message received"); log(L_ERR "KRT: 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");
return; return;
} }
@ -634,33 +593,57 @@ nl_parse_route(struct nlmsghdr *h, int scan)
} }
else else
dst = IPA_NONE; dst = IPA_NONE;
if (a[RTA_OIF]) if (a[RTA_OIF])
memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif)); memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
else else
oif = ~0; 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) switch (i->rtm_protocol)
{ {
case RTPROT_UNSPEC:
SKIP("proto unspec\n");
case RTPROT_REDIRECT: case RTPROT_REDIRECT:
src = KRT_SRC_REDIRECT; src = KRT_SRC_REDIRECT;
break; break;
case RTPROT_KERNEL: case RTPROT_KERNEL:
DBG("Route originated in kernel, ignoring\n"); src = KRT_SRC_KERNEL;
return; return;
case RTPROT_BIRD: 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) if (!scan)
{ SKIP("echo\n");
DBG("Echo of our own route, ignoring\n");
return;
}
src = KRT_SRC_BIRD; src = KRT_SRC_BIRD;
break; break;
case RTPROT_BOOT:
default: default:
src = KRT_SRC_ALIEN; src = KRT_SRC_ALIEN;
} }
@ -679,52 +662,48 @@ nl_parse_route(struct nlmsghdr *h, int scan)
switch (i->rtm_type) switch (i->rtm_type)
{ {
case RTN_UNICAST: 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; return;
} }
if (a[RTA_GATEWAY]) if (a[RTA_GATEWAY])
{ {
struct iface *ifa = if_find_by_index(oif);
neighbor *ng; neighbor *ng;
ra.dest = RTD_ROUTER; ra.dest = RTD_ROUTER;
memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw)); memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
ipa_ntoh(ra.gw); ipa_ntoh(ra.gw);
if (i->rtm_flags & RTNH_F_ONLINK) ng = neigh_find2(&p->p, &ra.gw, ra.iface,
(i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
if (!ng || (ng->scope == SCOPE_HOST))
{ {
/* route with 'onlink' attribute */ log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
ra.iface = if_find_by_index(oif); net->n.prefix, net->n.pxlen, ra.gw);
if (ra.iface == NULL) return;
{
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, 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;
}
} }
} }
else else
{ {
ra.dest = RTD_DEVICE; 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; break;
case RTN_BLACKHOLE: case RTN_BLACKHOLE:
ra.dest = RTD_BLACKHOLE; ra.dest = RTD_BLACKHOLE;
@ -737,13 +716,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
break; break;
/* FIXME: What about RTN_THROW? */ /* FIXME: What about RTN_THROW? */
default: default:
DBG("KRT: Ignoring route with type=%d\n", i->rtm_type); SKIP("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);
return; return;
} }

View File

@ -101,7 +101,7 @@ struct ip_mreqn
#define fill_mreq_ifa fill_mreq #define fill_mreq_ifa fill_mreq
#define fill_mreq_grp 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)); bzero(m, sizeof(*m));
m->imr_ifindex = ifa->index; m->imr_ifindex = ifa->index;

View File

@ -107,7 +107,7 @@ CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore
{ cmd_reconfig($3, RECONFIG_SOFT); } ; { cmd_reconfig($3, RECONFIG_SOFT); } ;
CF_CLI(DOWN,,, [[Shut the daemon down]]) CF_CLI(DOWN,,, [[Shut the daemon down]])
{ cli_msg(7, "Shutdown requested"); order_shutdown(); } ; { cmd_shutdown(); } ;
cfg_name: cfg_name:
/* empty */ { $$ = NULL; } /* empty */ { $$ = NULL; }

View File

@ -70,7 +70,8 @@ static struct resclass rf_class = {
"FILE", "FILE",
sizeof(struct rfile), sizeof(struct rfile),
rf_free, rf_free,
rf_dump rf_dump,
NULL
}; };
void * void *
@ -195,7 +196,8 @@ static struct resclass tm_class = {
"Timer", "Timer",
sizeof(timer), sizeof(timer),
tm_free, tm_free,
tm_dump tm_dump,
NULL
}; };
/** /**
@ -564,7 +566,8 @@ static struct resclass sk_class = {
"Socket", "Socket",
sizeof(sock), sizeof(sock),
sk_free, sk_free,
sk_dump sk_dump,
NULL
}; };
/** /**
@ -640,7 +643,7 @@ fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
} }
static inline void 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 * static char *
sk_set_ttl_int(sock *s) sk_set_ttl_int(sock *s)
{ {
int one = 1;
#ifdef IPV6 #ifdef IPV6
if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
return "IPV6_UNICAST_HOPS"; 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) if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
return "IP_TTL"; return "IP_TTL";
#ifdef CONFIG_UNIX_DONTROUTE #ifdef CONFIG_UNIX_DONTROUTE
int one = 1;
if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
return "SO_DONTROUTE"; return "SO_DONTROUTE";
#endif #endif
@ -1012,7 +1015,6 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
} }
else if (errno != EINTR && errno != EAGAIN) else if (errno != EINTR && errno != EAGAIN)
{ {
log(L_ERR "accept: %m");
s->err_hook(s, errno); s->err_hook(s, errno);
} }
return 0; return 0;
@ -1602,7 +1604,6 @@ io_loop(void)
{ {
sock *s = current_sock; sock *s = current_sock;
int e; int e;
int steps;
if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook) if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
{ {

View File

@ -139,15 +139,6 @@ kif_shutdown(struct proto *P)
krt_if_shutdown(p); krt_if_shutdown(p);
kif_proto = NULL; 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; return PS_DOWN;
} }
@ -558,32 +549,30 @@ krt_got_route(struct krt_proto *p, rte *e)
rte *old; rte *old;
net *net = e->net; net *net = e->net;
int verdict; int verdict;
#ifdef KRT_ALLOW_LEARN
int src = e->u.krt.src;
#endif
#ifdef CONFIG_AUTO_ROUTES #ifdef KRT_ALLOW_LEARN
if (e->attrs->dest == RTD_DEVICE) switch (e->u.krt.src)
{ {
/* It's a device route. Probably a kernel-generated one. */ case KRT_SRC_KERNEL:
verdict = KRF_IGNORE; verdict = KRF_IGNORE;
goto sentenced; goto sentenced;
}
#endif
#ifdef KRT_ALLOW_LEARN case KRT_SRC_REDIRECT:
if (src == KRT_SRC_ALIEN) verdict = KRF_DELETE;
{ goto sentenced;
case KRT_SRC_ALIEN:
if (KRT_CF->learn) if (KRT_CF->learn)
krt_learn_scan(p, e); krt_learn_scan(p, e);
else 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); rte_free(e);
} }
return; return;
} }
#endif #endif
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
if (net->n.flags & KRF_VERDICT_MASK) if (net->n.flags & KRF_VERDICT_MASK)
{ {
@ -605,7 +594,7 @@ krt_got_route(struct krt_proto *p, rte *e)
else else
verdict = KRF_DELETE; verdict = KRF_DELETE;
sentenced: sentenced:
krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]); 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; net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
if (verdict == KRF_UPDATE || verdict == KRF_DELETE) if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
@ -680,19 +669,24 @@ krt_prune(struct krt_proto *p)
} }
void 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; net *net = e->net;
int src = e->u.krt.src;
switch (src) switch (e->u.krt.src)
{ {
case KRT_SRC_BIRD: case KRT_SRC_BIRD:
ASSERT(0); /* Should be filtered by the back end */ ASSERT(0); /* Should be filtered by the back end */
case KRT_SRC_REDIRECT: case KRT_SRC_REDIRECT:
DBG("It's a redirect, kill him! Kill! Kill!\n"); if (new)
krt_set_notify(p, net, NULL, e); {
krt_trace_in(p, e, "[redirect] deleting");
krt_set_notify(p, net, NULL, e);
}
/* If !new, it is probably echo of our deletion */
break; break;
#ifdef KRT_ALLOW_LEARN #ifdef KRT_ALLOW_LEARN
case KRT_SRC_ALIEN: case KRT_SRC_ALIEN:
if (KRT_CF->learn) if (KRT_CF->learn)
@ -742,7 +736,8 @@ krt_scan(timer *t UNUSED)
*/ */
static void 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; 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.accept_ra_types = RA_OPTIMAL;
p->p.rt_notify = krt_notify; p->p.rt_notify = krt_notify;
p->p.min_scope = SCOPE_HOST;
return &p->p; return &p->p;
} }

View File

@ -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_BIRD 0 /* Our route (not passed in async mode) */
#define KRT_SRC_REDIRECT 1 /* Redirect route, delete it */ #define KRT_SRC_REDIRECT 1 /* Redirect route, delete it */
#define KRT_SRC_ALIEN 2 /* Route installed by someone else */ #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; extern struct protocol proto_unix_iface;

View File

@ -19,6 +19,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "nest/bird.h" #include "nest/bird.h"
#include "nest/cli.h" #include "nest/cli.h"

View File

@ -141,6 +141,9 @@ cmd_reconfig(char *name, int type)
{ {
struct config *conf; struct config *conf;
if (cli_access_restricted())
return;
if (!name) if (!name)
name = config_name; name = config_name;
cli_msg(-2, "Reading configuration from %s", name); cli_msg(-2, "Reading configuration from %s", name);
@ -303,6 +306,16 @@ cli_init_unix(void)
* Shutdown * Shutdown
*/ */
void
cmd_shutdown(void)
{
if (cli_access_restricted())
return;
cli_msg(7, "Shutdown requested");
order_shutdown();
}
void void
async_shutdown(void) async_shutdown(void)
{ {

View File

@ -9,6 +9,8 @@
#ifndef _BIRD_UNIX_H_ #ifndef _BIRD_UNIX_H_
#define _BIRD_UNIX_H_ #define _BIRD_UNIX_H_
#include <sys/socket.h>
struct pool; struct pool;
/* main.c */ /* main.c */
@ -17,6 +19,7 @@ void async_config(void);
void async_dump(void); void async_dump(void);
void async_shutdown(void); void async_shutdown(void);
void cmd_reconfig(char *name, int type); void cmd_reconfig(char *name, int type);
void cmd_shutdown(void);
/* io.c */ /* io.c */
@ -28,10 +31,12 @@ volatile int async_shutdown_flag;
#define BIRD_PF PF_INET6 #define BIRD_PF PF_INET6
#define BIRD_AF AF_INET6 #define BIRD_AF AF_INET6
typedef struct sockaddr_in6 sockaddr; typedef struct sockaddr_in6 sockaddr;
static inline int sa_family_check(sockaddr *sa) { return sa->sin6_family == AF_INET6; }
#else #else
#define BIRD_PF PF_INET #define BIRD_PF PF_INET
#define BIRD_AF AF_INET #define BIRD_AF AF_INET
typedef struct sockaddr_in sockaddr; typedef struct sockaddr_in sockaddr;
static inline int sa_family_check(sockaddr *sa) { return sa->sin_family == AF_INET; }
#endif #endif
#ifndef SUN_LEN #ifndef SUN_LEN

View File

@ -55,7 +55,7 @@ tags:
cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) -name *.[chY]` cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) -name *.[chY]`
install: all 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@ $(INSTALL_PROGRAM) -s $(exedir)/bird $(DESTDIR)/$(sbindir)/bird@SUFFIX6@
if test -n "@CLIENT@" ; then \ if test -n "@CLIENT@" ; then \
$(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc@SUFFIX6@ ; \ $(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc@SUFFIX6@ ; \