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