Merge branch 'dev' into ospf3

Conflicts:

	proto/ospf/lsreq.c
	proto/ospf/lsupd.c
	proto/ospf/rt.c
This commit is contained in:
Ondrej Zajicek 2009-12-14 20:37:32 +01:00
commit 63542845df
20 changed files with 478 additions and 87 deletions

8
NEWS
View file

@ -1,3 +1,11 @@
Version 1.1.6 (2009-11-19)
o Implements RFC 5004 - prefer older external routes.
o There is a change how route servers handle missing IPv6 link
local addresses in next hop atribute - see 'missing lladdr'
option.
o Several minor features (description field, parse check option).
o Several minor bugfixes.
Version 1.1.5 (2009-10-29) Version 1.1.5 (2009-10-29)
o Better scalability of BGP. o Better scalability of BGP.
o New accessors for AS path - first and last. o New accessors for AS path - first and last.

1
TODO
View file

@ -21,7 +21,6 @@ Globals
Various ideas Various ideas
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
- client: paging of output
- client: Ctrl-R eats one more enter - client: Ctrl-R eats one more enter
- bgp: timing of updates? - bgp: timing of updates?
- netlink: realms - netlink: realms

View file

@ -162,6 +162,7 @@ protocol static {
#protocol bgp { #protocol bgp {
# disabled; # disabled;
# description "My BGP uplink"
# local as 65000; # local as 65000;
# neighbor 62.168.0.130 as 5588; # neighbor 62.168.0.130 as 5588;
# multihop 20 via 62.168.0.13; # multihop 20 via 62.168.0.13;

View file

@ -129,7 +129,11 @@ options. The most important ones are:
enable debug messages and run bird in foreground. enable debug messages and run bird in foreground.
<tag>-D <m/filename of debug log/</tag> <tag>-D <m/filename of debug log/</tag>
log debugging information to given file instead of stderr log debugging information to given file instead of stderr.
<tag>-p</tag>
just parse the config file and exit. Return value is zero if the config file is valid,
nonzero if there are some errors.
<tag>-s <m/name of communication socket/</tag> <tag>-s <m/name of communication socket/</tag>
use given filename for a socket for communications with the client, default is <it/prefix/<file>/var/run/bird.ctl</file>. use given filename for a socket for communications with the client, default is <it/prefix/<file>/var/run/bird.ctl</file>.
@ -306,6 +310,10 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
<tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it <tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it
works in the direction from the routing table to the protocol. Default: <cf/none/. works in the direction from the routing table to the protocol. Default: <cf/none/.
<tag>description "<m/text/"</tag> This is an optional
description of the protocol. It is displayed as a part of the
output of 'show route all' command.
<tag>table <m/name/</tag> Connect this protocol to a non-default routing table. <tag>table <m/name/</tag> Connect this protocol to a non-default routing table.
</descrip> </descrip>
@ -474,9 +482,6 @@ This argument can be omitted if there exists only a single instance.
number of networks, number of routes before and after filtering). If number of networks, number of routes before and after filtering). If
you use <cf/count/ instead, only the statistics will be printed. you use <cf/count/ instead, only the statistics will be printed.
<tag>enable|disable|restart <m/name/|"<m/pattern/"|all</tag>
Enable, disable or restart a given protocol instance, instances matching the <cf><m/pattern/</cf> or <cf/all/ instances.
<tag>configure [soft] ["<m/config file/"]</tag> <tag>configure [soft] ["<m/config file/"]</tag>
Reload configuration from a given file. BIRD will smoothly Reload configuration from a given file. BIRD will smoothly
switch itself to the new configuration, protocols are switch itself to the new configuration, protocols are
@ -488,6 +493,27 @@ This argument can be omitted if there exists only a single instance.
but new routes would be processed according to the new but new routes would be processed according to the new
filters. filters.
<tag>enable|disable|restart <m/name/|"<m/pattern/"|all</tag>
Enable, disable or restart a given protocol instance, instances matching the <cf><m/pattern/</cf> or <cf/all/ instances.
<tag>reload [in|out] <m/name/|"<m/pattern/"|all</tag>
Reload a given protocol instance, that means re-import routes
from the protocol instance and re-export preferred routes to
the instance. If <cf/in/ or <cf/out/ options are used, the
command is restricted to one direction (re-import or
re-export).
This command is useful if appropriate filters have changed but
the protocol instance was not restarted (or reloaded),
therefore it still propagates the old set of routes. For example
when <cf/configure soft/ command was used to change filters.
Re-export always succeeds, but re-import is protocol-dependent
and might fail (for example, if BGP neighbor does not support
route-refresh extension). In that case, re-export is also
skipped.
<tag/down/ <tag/down/
Shut BIRD down. Shut BIRD down.
@ -641,7 +667,7 @@ incompatible with each other (that is to prevent you from shooting in the foot).
but <cf>1.0.0.0/16 &tilde; [ 1.0.0.0/8- ]</cf> is false. but <cf>1.0.0.0/16 &tilde; [ 1.0.0.0/8- ]</cf> is false.
Cisco-style patterns like <cf>10.0.0.0/8 ge 16 le 24</cf> can be expressed Cisco-style patterns like <cf>10.0.0.0/8 ge 16 le 24</cf> can be expressed
in Bird as <cf>10.0.0.0/8{16,24}</cf>, <cf>192.168.0.0/16 le 24</cf> as in BIRD as <cf>10.0.0.0/8{16,24}</cf>, <cf>192.168.0.0/16 le 24</cf> as
<cf>192.168.0.0/16{16,24}</cf> and <cf>192.168.0.0/16 ge 24</cf> as <cf>192.168.0.0/16{16,24}</cf> and <cf>192.168.0.0/16 ge 24</cf> as
<cf>192.168.0.0/16{24,32}</cf>. <cf>192.168.0.0/16{24,32}</cf>.
@ -882,12 +908,28 @@ for each neighbor using the following configuration parameters:
we should route via our direct neighbor with address <m/ip/. we should route via our direct neighbor with address <m/ip/.
Default: switched off. Default: switched off.
<tag>next hop self</tag> Avoid calculation of the Next Hop attribute <tag>next hop self</tag> Avoid calculation of the Next Hop
and always advertise our own source address (see below) as a next hop. attribute and always advertise our own source address (see
This needs to be used only below) as a next hop. This needs to be used only occasionally
occasionally to circumvent misconfigurations of other routers. to circumvent misconfigurations of other routers.
Default: disabled. Default: disabled.
<tag>missing lladdr self|drop|ignore</tag>Next Hop attribute
in BGP-IPv6 sometimes contains just the global IPv6 address,
but sometimes it has to contain both global and link-local
IPv6 addresses. This option specifies what to do if BIRD have
to send both addresses but does not know link-local address.
This situation might happen when routes from other protocols
are exported to BGP, or when improper updates are received
from BGP peers. <cf/self/ means that BIRD advertises its own
local address instead. <cf/drop/ means that BIRD skips that
prefixes and logs error. <cf/ignore/ means that BIRD ignores
the problem and sends just the global address (and therefore
forms improper BGP update). Default: <cf/self/, unless BIRD
is configured as a route server (option <cf/rs client/), in
that case default is <cf/drop/, because route servers usually
does not forward packets ifselves.
<tag>source address <m/ip/</tag> Define local address we should use <tag>source address <m/ip/</tag> Define local address we should use
for next hop calculation. Default: the address of the local end for next hop calculation. Default: the address of the local end
of the interface our neighbor is connected to. of the interface our neighbor is connected to.
@ -915,11 +957,21 @@ for each neighbor using the following configuration parameters:
as a route server client. A route server is used as a as a route server client. A route server is used as a
replacement for full mesh EBGP routing in Internet exchange replacement for full mesh EBGP routing in Internet exchange
points in a similar way to route reflectors used in IBGP routing. points in a similar way to route reflectors used in IBGP routing.
Bird does not implement obsoleted RFC 1863, but uses ad-hoc implementation, BIRD does not implement obsoleted RFC 1863, but uses ad-hoc implementation,
which behaves like plain EBGP but reduces modifications to advertised route which behaves like plain EBGP but reduces modifications to advertised route
attributes to be transparent (for example does not prepend its AS number to attributes to be transparent (for example does not prepend its AS number to
AS PATH attribute and keep MED attribute). Default: disabled. AS PATH attribute and keep MED attribute). Default: disabled.
<tag>enable route refresh <m/switch/</tag> When BGP speaker
changes its import filter, it has to re-examine all routes
received from its neighbor against the new filter. As these
routes might not be available, there is a BGP protocol
extension Route Refresh (specified in RFC 2918) that allows
BGP speaker to request re-advertisment of all routes from its
neighbor. This option specifies whether BIRD advertises this
capability and accepts such requests. Even when disabled, BIRD
can send route refresh requests. Default: on.
<tag>enable as4 <m/switch/</tag> BGP protocol was designed to use 2B AS numbers <tag>enable as4 <m/switch/</tag> BGP protocol was designed to use 2B AS numbers
and was extended later to allow 4B AS number. BIRD supports 4B AS extension, and was extended later to allow 4B AS number. BIRD supports 4B AS extension,
but by disabling this option it can be persuaded not to advertise it and but by disabling this option it can be persuaded not to advertise it and
@ -980,6 +1032,11 @@ for each neighbor using the following configuration parameters:
<tag>path metric <m/switch/</tag> Enable comparison of path lengths <tag>path metric <m/switch/</tag> Enable comparison of path lengths
when deciding which BGP route is the best one. Default: on. when deciding which BGP route is the best one. Default: on.
<tag>prefer older <m/switch/</tag> Standard route selection algorithm
breaks ties by comparing router IDs. This changes the behavior
to prefer older routes (when both are external and from different
peer). For details, see RFC 5004. Default: off.
<tag>default bgp_med <m/number/</tag> Value of the Multiple Exit <tag>default bgp_med <m/number/</tag> Value of the Multiple Exit
Discriminator to be used during route selection when the MED attribute Discriminator to be used during route selection when the MED attribute
is missing. Default: 0. is missing. Default: 0.

View file

@ -23,6 +23,7 @@ Reply codes of BIRD command-line interface
0012 Restarted 0012 Restarted
0013 Status report 0013 Status report
0014 Route count 0014 Route count
0015 Reloading
1000 BIRD version 1000 BIRD version
1001 Interface list 1001 Interface list
@ -40,6 +41,7 @@ Reply codes of BIRD command-line interface
1013 Show ospf neighbors 1013 Show ospf neighbors
1014 Show ospf 1014 Show ospf
1015 Show ospf interface 1015 Show ospf interface
1016 Show ospf state/topology
8000 Reply too long 8000 Reply too long
8001 Route not found 8001 Route not found
@ -47,6 +49,7 @@ Reply codes of BIRD command-line interface
8003 No protocols match 8003 No protocols match
8004 Stopped due to reconfiguration 8004 Stopped due to reconfiguration
8005 Protocol is down => cannot dump 8005 Protocol is down => cannot dump
8006 Reload failed
9000 Command too long 9000 Command too long
9001 Parse error 9001 Parse error

View file

@ -731,7 +731,7 @@ interpret(struct f_inst *what)
case P('a','f'): /* Get first ASN from AS PATH */ case P('a','f'): /* Get first ASN from AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS Path expected" ); runtime( "AS path expected" );
as = 0; as = 0;
as_path_get_first(v1.val.ad, &as); as_path_get_first(v1.val.ad, &as);
@ -942,6 +942,8 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case P('i','M'): TWOARGS; break; case P('i','M'): TWOARGS; break;
case P('A','p'): TWOARGS; break; case P('A','p'): TWOARGS; break;
case P('C','a'): TWOARGS; break; case P('C','a'): TWOARGS; break;
case P('a','f'):
case P('a','l'): ONEARG; break;
default: default:
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
} }

View file

@ -1,6 +1,6 @@
Summary: BIRD Internet Routing Daemon Summary: BIRD Internet Routing Daemon
Name: bird Name: bird
Version: 1.1.5 Version: 1.1.6
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: Networking/Daemons Group: Networking/Daemons

View file

@ -44,7 +44,8 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS) CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
CF_KEYWORDS(RELOAD, IN, OUT)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@ -141,6 +142,7 @@ proto_item:
| EXPORT imexport { this_proto->out_filter = $2; } | EXPORT imexport { this_proto->out_filter = $2; }
| TABLE rtable { this_proto->table = $2; } | TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; } | ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION TEXT { this_proto->dsc = $2; }
; ;
imexport: imexport:
@ -436,11 +438,17 @@ echo_size:
; ;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]]) CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]])
{ proto_xxable($2, 0); } ; { proto_xxable($2, XX_DISABLE); } ;
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]]) CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]])
{ proto_xxable($2, 1); } ; { proto_xxable($2, XX_ENABLE); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]]) CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]])
{ proto_xxable($2, 2); } ; { proto_xxable($2, XX_RESTART); } ;
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
{ proto_xxable($2, XX_RELOAD); } ;
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
{ proto_xxable($3, XX_RELOAD_IN); } ;
CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
{ proto_xxable($3, XX_RELOAD_OUT); } ;
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging]]) CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging]])
CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging]]) CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging]])

View file

@ -73,6 +73,10 @@ proto_relink(struct proto *p)
rem_node(&p->n); rem_node(&p->n);
switch (p->core_state) switch (p->core_state)
{ {
case FS_HUNGRY:
l = &inactive_proto_list;
break;
case FS_FEEDING:
case FS_HAPPY: case FS_HAPPY:
l = &active_proto_list; l = &active_proto_list;
break; break;
@ -80,7 +84,7 @@ proto_relink(struct proto *p)
l = &flush_proto_list; l = &flush_proto_list;
break; break;
default: default:
l = &inactive_proto_list; ASSERT(0);
} }
proto_enqueue(l, p); proto_enqueue(l, p);
} }
@ -307,6 +311,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
if (sym && sym->class == SYM_PROTO && !new->shutdown) if (sym && sym->class == SYM_PROTO && !new->shutdown)
{ {
/* Found match, let's check if we can smoothly switch to new configuration */ /* Found match, let's check if we can smoothly switch to new configuration */
/* No need to check description */
nc = sym->def; nc = sym->def;
if (!force_reconfig if (!force_reconfig
&& nc->protocol == oc->protocol && nc->protocol == oc->protocol
@ -548,7 +553,7 @@ proto_feed_more(void *P)
} }
static void static void
proto_feed(void *P) proto_feed_initial(void *P)
{ {
struct proto *p = P; struct proto *p = P;
@ -576,15 +581,50 @@ proto_schedule_flush(struct proto *p)
} }
static void static void
proto_schedule_feed(struct proto *p) proto_schedule_feed(struct proto *p, int initial)
{ {
DBG("%s: Scheduling meal\n", p->name); DBG("%s: Scheduling meal\n", p->name);
p->core_state = FS_FEEDING; p->core_state = FS_FEEDING;
p->refeeding = !initial;
/* Hack: reset exp_routes during refeed, and do not decrease it later */
if (!initial)
p->stats.exp_routes = 0;
proto_relink(p); proto_relink(p);
p->attn->hook = proto_feed; p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
ev_schedule(p->attn); ev_schedule(p->attn);
} }
/**
* proto_request_feeding - request feeding routes to the protocol
* @p: given protocol
*
* Sometimes it is needed to send again all routes to the
* protocol. This is called feeding and can be requested by this
* function. This would cause protocol core state transition
* to FS_FEEDING (during feeding) and when completed, it will
* switch back to FS_HAPPY. This function can be called even
* when feeding is already running, in that case it is restarted.
*/
void
proto_request_feeding(struct proto *p)
{
ASSERT(p->proto_state == PS_UP);
/* If we are already feeding, we want to restart it */
if (p->core_state == FS_FEEDING)
{
/* Unless feeding is in initial state */
if (p->attn->hook == proto_feed_initial)
return;
rt_feed_baby_abort(p);
}
proto_schedule_feed(p, 0);
}
/** /**
* proto_notify_state - notify core about protocol state change * proto_notify_state - notify core about protocol state change
* @p: protocol the state of which has changed * @p: protocol the state of which has changed
@ -614,7 +654,7 @@ proto_notify_state(struct proto *p, unsigned ps)
switch (ps) switch (ps)
{ {
case PS_DOWN: case PS_DOWN:
if ((cs = FS_FEEDING) || (cs == FS_HAPPY)) if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p); proto_schedule_flush(p);
neigh_prune(); // FIXME convert neighbors to resource? neigh_prune(); // FIXME convert neighbors to resource?
@ -634,10 +674,10 @@ proto_notify_state(struct proto *p, unsigned ps)
case PS_UP: case PS_UP:
ASSERT(ops == PS_DOWN || ops == PS_START); ASSERT(ops == PS_DOWN || ops == PS_START);
ASSERT(cs == FS_HUNGRY); ASSERT(cs == FS_HUNGRY);
proto_schedule_feed(p); proto_schedule_feed(p, 1);
break; break;
case PS_STOP: case PS_STOP:
if ((cs = FS_FEEDING) || (cs == FS_HAPPY)) if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p); proto_schedule_flush(p);
break; break;
default: default:
@ -702,6 +742,8 @@ proto_do_show(struct proto *p, int verbose)
buf); buf);
if (verbose) if (verbose)
{ {
if (p->cf->dsc)
cli_msg(-1006, " Description: %s", p->cf->dsc);
cli_msg(-1006, " Preference: %d", p->preference); cli_msg(-1006, " Preference: %d", p->preference);
cli_msg(-1006, " Input filter: %s", filter_name(p->in_filter)); cli_msg(-1006, " Input filter: %s", filter_name(p->in_filter));
cli_msg(-1006, " Output filter: %s", filter_name(p->out_filter)); cli_msg(-1006, " Output filter: %s", filter_name(p->out_filter));
@ -788,25 +830,29 @@ proto_xxable(char *pattern, int xx)
cnt++; cnt++;
switch (xx) switch (xx)
{ {
case 0: case XX_DISABLE:
if (p->disabled) if (p->disabled)
cli_msg(-8, "%s: already disabled", p->name); cli_msg(-8, "%s: already disabled", p->name);
else else
{ {
cli_msg(-9, "%s: disabled", p->name); cli_msg(-9, "%s: disabled", p->name);
p->disabled = 1; p->disabled = 1;
proto_rethink_goal(p);
} }
break; break;
case 1:
case XX_ENABLE:
if (!p->disabled) if (!p->disabled)
cli_msg(-10, "%s: already enabled", p->name); cli_msg(-10, "%s: already enabled", p->name);
else else
{ {
cli_msg(-11, "%s: enabled", p->name); cli_msg(-11, "%s: enabled", p->name);
p->disabled = 0; p->disabled = 0;
proto_rethink_goal(p);
} }
break; break;
case 2:
case XX_RESTART:
if (p->disabled) if (p->disabled)
cli_msg(-8, "%s: already disabled", p->name); cli_msg(-8, "%s: already disabled", p->name);
else else
@ -814,13 +860,38 @@ proto_xxable(char *pattern, int xx)
p->disabled = 1; p->disabled = 1;
proto_rethink_goal(p); proto_rethink_goal(p);
p->disabled = 0; p->disabled = 0;
proto_rethink_goal(p);
cli_msg(-12, "%s: restarted", p->name); cli_msg(-12, "%s: restarted", p->name);
} }
break; break;
case XX_RELOAD:
case XX_RELOAD_IN:
case XX_RELOAD_OUT:
if (p->disabled)
{
cli_msg(-8, "%s: already disabled", p->name);
break;
}
/* 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: default:
ASSERT(0); ASSERT(0);
} }
proto_rethink_goal(p);
} }
WALK_PROTO_LIST_END; WALK_PROTO_LIST_END;
if (!cnt) if (!cnt)

View file

@ -81,6 +81,7 @@ struct proto_config {
struct protocol *protocol; /* Protocol */ struct protocol *protocol; /* Protocol */
struct proto *proto; /* Instance we've created */ struct proto *proto; /* Instance we've created */
char *name; char *name;
char *dsc;
unsigned debug, preference, disabled; /* Generic parameters */ unsigned debug, preference, disabled; /* Generic parameters */
u32 router_id; /* Protocol specific router ID */ u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */ struct rtable_config *table; /* Table we're attached to */
@ -133,6 +134,7 @@ struct proto {
unsigned core_state; /* Core state machine (see below) */ unsigned core_state; /* Core state machine (see below) */
unsigned core_goal; /* State we want to reach (see below) */ unsigned core_goal; /* State we want to reach (see below) */
unsigned reconfiguring; /* We're shutting down due to reconfiguration */ unsigned reconfiguring; /* We're shutting down due to reconfiguration */
unsigned refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
u32 hash_key; /* Random key used for hashing of neighbors */ u32 hash_key; /* Random key used for hashing of neighbors */
bird_clock_t last_state_change; /* Time of last state transition */ bird_clock_t last_state_change; /* Time of last state transition */
char *last_state_name_announced; /* Last state name we've announced to the user */ char *last_state_name_announced; /* Last state name we've announced to the user */
@ -151,6 +153,9 @@ struct proto {
* It can construct a new rte, add private attributes and * It can construct a new rte, add private attributes and
* decide whether the route shall be imported: 1=yes, -1=no, * decide whether the route shall be imported: 1=yes, -1=no,
* 0=process it through the import filter set by the user. * 0=process it through the import filter set by the user.
* reload_routes Request protocol to reload all its routes to the core
* (using rte_update()). Returns: 0=reload cannot be done,
* 1= reload is scheduled and will happen (asynchronously).
*/ */
void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
@ -160,6 +165,7 @@ struct proto {
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs); void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs);
int (*import_control)(struct proto *, struct rte **rt, struct ea_list **attrs, struct linpool *pool); int (*import_control)(struct proto *, struct rte **rt, struct ea_list **attrs, struct linpool *pool);
int (*reload_routes)(struct proto *);
/* /*
* Routing entry hooks (called only for rte's belonging to this protocol): * Routing entry hooks (called only for rte's belonging to this protocol):
@ -189,11 +195,19 @@ struct proto {
void *proto_new(struct proto_config *, unsigned size); void *proto_new(struct proto_config *, unsigned size);
void *proto_config_new(struct protocol *, unsigned size); void *proto_config_new(struct protocol *, unsigned size);
void proto_request_feeding(struct proto *p);
void proto_show(struct symbol *, int); void proto_show(struct symbol *, int);
struct proto *proto_get_named(struct symbol *, struct protocol *); struct proto *proto_get_named(struct symbol *, struct protocol *);
void proto_xxable(char *, int); void proto_xxable(char *, int);
void proto_debug(char *, unsigned int); void proto_debug(char *, 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
static inline u32 static inline u32
proto_get_router_id(struct proto_config *pc) proto_get_router_id(struct proto_config *pc)
{ {
@ -270,6 +284,10 @@ void proto_notify_state(struct proto *p, unsigned state);
* HUNGRY/DOWN --> HUNGRY/START --> HUNGRY/UP --> * HUNGRY/DOWN --> HUNGRY/START --> HUNGRY/UP -->
* FEEDING/UP --> HAPPY/UP --> FLUSHING/STOP|DOWN --> * FEEDING/UP --> HAPPY/UP --> FLUSHING/STOP|DOWN -->
* HUNGRY/STOP|DOWN --> HUNGRY/DOWN * HUNGRY/STOP|DOWN --> HUNGRY/DOWN
*
* Sometimes, protocol might switch from HAPPY/UP to FEEDING/UP
* if it wants to refeed the routes (for example BGP does so
* as a result of received ROUTE-REFRESH request).
*/ */
#define FS_HUNGRY 0 #define FS_HUNGRY 0

View file

@ -158,13 +158,15 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
} }
static inline void static inline void
do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class) do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed)
{ {
struct proto *p = a->proto; struct proto *p = a->proto;
rte *new0 = new; rte *new0 = new;
rte *old0 = old; rte *old0 = old;
int ok; int ok;
int fast_exit_hack = 0;
if (new) if (new)
{ {
p->stats.exp_updates_received++; p->stats.exp_updates_received++;
@ -174,6 +176,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
{ {
p->stats.exp_updates_rejected++; p->stats.exp_updates_rejected++;
drop_reason = "out of scope"; 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) else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0)
{ {
@ -199,7 +202,32 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
else else
p->stats.exp_withdraws_received++; p->stats.exp_withdraws_received++;
if (old) /* Hack: This is here to prevent 'spurious withdraws'
for loopback addresses during reload. */
if (fast_exit_hack)
return;
/*
* This is a tricky part - we don't know whether route 'old' was
* exported to protocol 'p' or was filtered by the export filter.
* We try tu run the export filter to know this to have a correct
* value in 'old' argument of rt_update (and proper filter value)
*
* FIXME - this is broken because 'configure soft' may change
* filters but keep routes. Refeed is expected to be called after
* change of the filters and with old == new, therefore we do not
* even try to run the filter on an old route, This may lead to
* 'spurious withdraws' but ensure that there are no 'missing
* withdraws'.
*
* This is not completely safe as there is a window between
* reconfiguration and the end of refeed - if a newly filtered
* route disappears during this period, proper withdraw is not
* sent (because old would be also filtered) and the route is
* not refeeded (because it disappeared before that).
*/
if (old && !refeed)
{ {
if (p->out_filter == FILTER_REJECT) if (p->out_filter == FILTER_REJECT)
old = NULL; old = NULL;
@ -216,6 +244,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
} }
} }
/* FIXME - This is broken because of incorrect 'old' value (see above) */
if (!new && !old) if (!new && !old)
return; return;
@ -224,9 +253,11 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
else else
p->stats.exp_withdraws_accepted++; p->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) if (new)
p->stats.exp_routes++; p->stats.exp_routes++;
if (old) if (old && !refeed)
p->stats.exp_routes--; p->stats.exp_routes--;
if (p->debug & D_ROUTES) if (p->debug & D_ROUTES)
@ -304,7 +335,7 @@ rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa)
{ {
ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING);
if (a->proto->accept_ra_types == type) if (a->proto->accept_ra_types == type)
do_rte_announce(a, type, net, new, old, tmpa, class); do_rte_announce(a, type, net, new, old, tmpa, class, 0);
} }
} }
@ -394,6 +425,26 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
{ {
if (old->attrs->proto == src) if (old->attrs->proto == src)
{ {
/* If there is the same route in the routing table but from
* a different sender, then there are two paths from the
* source protocol to this routing table through transparent
* pipes, which is not allowed.
*
* We log that and ignore the route. If it is withdraw, we
* ignore it completely (there might be 'spurious withdraws',
* see FIXME in do_rte_announce())
*/
if (old->sender != p)
{
if (new)
{
log(L_ERR "Pipe collision detected when sending %I/%d to table %s",
net->n.prefix, net->n.pxlen, table->name);
rte_free_quick(new);
}
return;
}
if (new && rte_same(old, new)) if (new && rte_same(old, new))
{ {
/* No changes, ignore the new route */ /* No changes, ignore the new route */
@ -495,11 +546,10 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
net->routes->next = new; net->routes->next = new;
rte_trace_in(D_ROUTES, p, new, "added"); rte_trace_in(D_ROUTES, p, new, "added");
} }
else if (old && (p->debug & D_ROUTES))
{
/* Not really a case - the list of routes is correct, we just
log the route removal */
/* Log the route removal */
if (!new && old && (p->debug & D_ROUTES))
{
if (old != old_best) if (old != old_best)
rte_trace_in(D_ROUTES, p, old, "removed"); rte_trace_in(D_ROUTES, p, old, "removed");
else if (net->routes) else if (net->routes)
@ -589,11 +639,12 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
new->sender = p; new->sender = p;
struct filter *filter = p->in_filter; struct filter *filter = p->in_filter;
/* Do not filter routes going to the secondary side of the pipe, /* Do not filter routes going through the pipe,
that should only go through export filter. they are filtered in the export filter only. */
FIXME Make a better check whether p is really a pipe. */ #ifdef CONFIG_PIPE
if (p->table != table) if (p->proto == &proto_pipe)
filter = FILTER_ACCEPT; filter = FILTER_ACCEPT;
#endif
p->stats.imp_updates_received++; p->stats.imp_updates_received++;
if (!rte_validate(new)) if (!rte_validate(new))
@ -636,6 +687,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
drop: drop:
rte_free(new); rte_free(new);
rte_recalculate(table, net, p, src, NULL, NULL);
rte_update_unlock(); rte_update_unlock();
} }
@ -943,7 +995,7 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
rte_update_lock(); rte_update_lock();
tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
do_rte_announce(h, type, n, e, NULL, tmpa, ipa_classify(n->n.prefix)); do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding);
rte_update_unlock(); rte_update_unlock();
} }
@ -1121,6 +1173,11 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
ok = 0; ok = 0;
else if (!ic && d->export_mode > 1) else if (!ic && d->export_mode > 1)
{ {
/* FIXME - this shows what should be exported according
to current filters, but not what was really exported.
'configure soft' command may change the export filter
and do not update routes */
if (p1->out_filter == FILTER_REJECT || if (p1->out_filter == FILTER_REJECT ||
p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
ok = 0; ok = 0;

View file

@ -165,6 +165,22 @@ bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a, int len)
#endif #endif
} }
static void
bgp_format_next_hop(eattr *a, byte *buf, int buflen UNUSED)
{
ip_addr *ipp = (ip_addr *) a->u.ptr->data;
#ifdef IPV6
/* in IPv6, we might have two addresses in NEXT HOP */
if ((a->u.ptr->length == NEXT_HOP_LENGTH) && ipa_nonzero(ipp[1]))
{
bsprintf(buf, "%I %I", ipp[0], ipp[1]);
return;
}
#endif
bsprintf(buf, "%I", ipp[0]);
}
static int static int
bgp_check_aggregator(struct bgp_proto *p, byte *a UNUSED, int len) bgp_check_aggregator(struct bgp_proto *p, byte *a UNUSED, int len)
{ {
@ -234,7 +250,7 @@ static struct attr_desc bgp_attr_table[] = {
{ "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1, /* BA_AS_PATH */ { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1, /* BA_AS_PATH */
NULL, NULL }, /* is checked by validate_as_path() as a special case */ NULL, NULL }, /* is checked by validate_as_path() as a special case */
{ "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1, /* BA_NEXT_HOP */ { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1, /* BA_NEXT_HOP */
bgp_check_next_hop, NULL }, bgp_check_next_hop, bgp_format_next_hop },
{ "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 1, /* BA_MULTI_EXIT_DISC */ { "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 1, /* BA_MULTI_EXIT_DISC */
NULL, NULL }, NULL, NULL },
{ "local_pref", 4, BAF_TRANSITIVE, EAF_TYPE_INT, 0, /* BA_LOCAL_PREF */ { "local_pref", 4, BAF_TRANSITIVE, EAF_TYPE_INT, 0, /* BA_LOCAL_PREF */
@ -1044,7 +1060,6 @@ bgp_rte_better(rte *new, rte *old)
return 0; return 0;
/* RFC 4271 9.1.2.2. c) Compare MED's */ /* RFC 4271 9.1.2.2. c) Compare MED's */
if (bgp_get_neighbor(new) == bgp_get_neighbor(old)) if (bgp_get_neighbor(new) == bgp_get_neighbor(old))
{ {
x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
@ -1082,12 +1097,19 @@ bgp_rte_better(rte *new, rte *old)
y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
n = x ? x->u.data : new_bgp->remote_id; n = x ? x->u.data : new_bgp->remote_id;
o = y ? y->u.data : old_bgp->remote_id; o = y ? y->u.data : old_bgp->remote_id;
/* RFC 5004 - prefer older routes */
/* (if both are external and from different peer) */
if ((new_bgp->cf->prefer_older || old_bgp->cf->prefer_older) &&
!new_bgp->is_internal && n != o)
return 0;
/* rest of RFC 4271 9.1.2.2. f) */
if (n < o) if (n < o)
return 1; return 1;
if (n > o) if (n > o)
return 0; return 0;
/* RFC 4271 9.1.2.2. g) Compare peer IP adresses */ /* RFC 4271 9.1.2.2. g) Compare peer IP adresses */
return (ipa_compare(new_bgp->cf->remote_ip, old_bgp->cf->remote_ip) < 0); return (ipa_compare(new_bgp->cf->remote_ip, old_bgp->cf->remote_ip) < 0);
} }

View file

@ -676,6 +676,17 @@ bgp_neigh_notify(neighbor *n)
} }
} }
static int
bgp_reload_routes(struct proto *P)
{
struct bgp_proto *p = (struct bgp_proto *) P;
if (!p->conn || !p->conn->peer_refresh_support)
return 0;
bgp_schedule_packet(p->conn, PKT_ROUTE_REFRESH);
return 1;
}
static void static void
bgp_start_locked(struct object_lock *lock) bgp_start_locked(struct object_lock *lock)
{ {
@ -792,6 +803,7 @@ bgp_init(struct proto_config *C)
P->rte_better = bgp_rte_better; P->rte_better = bgp_rte_better;
P->import_control = bgp_import_control; P->import_control = bgp_import_control;
P->neigh_notify = bgp_neigh_notify; P->neigh_notify = bgp_neigh_notify;
P->reload_routes = bgp_reload_routes;
p->cf = c; p->cf = c;
p->local_as = c->local_as; p->local_as = c->local_as;
p->remote_as = c->remote_as; p->remote_as = c->remote_as;
@ -886,6 +898,10 @@ bgp_check(struct bgp_config *c)
if ((c->local_as == c->remote_as) && (c->rs_client)) if ((c->local_as == c->remote_as) && (c->rs_client))
cf_error("Only external neighbor can be RS client"); cf_error("Only external neighbor can be RS client");
/* Different default based on rs_client */
if (c->missing_lladdr == 0)
c->missing_lladdr = c->rs_client ? MLL_DROP : MLL_SELF;
} }
static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" }; static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" };

View file

@ -23,10 +23,13 @@ struct bgp_config {
ip_addr multihop_via; /* Multihop: address to route to */ ip_addr multihop_via; /* Multihop: address to route to */
ip_addr source_addr; /* Source address to use */ ip_addr source_addr; /* Source address to use */
int next_hop_self; /* Always set next hop to local IP address */ int next_hop_self; /* Always set next hop to local IP address */
int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */
int compare_path_lengths; /* Use path lengths when selecting best route */ int compare_path_lengths; /* Use path lengths when selecting best route */
int prefer_older; /* Prefer older routes according to RFC 5004 */
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */ u32 default_local_pref; /* Default value for LOCAL_PREF attribute */
u32 default_med; /* Default value for MULTI_EXIT_DISC attribute */ u32 default_med; /* Default value for MULTI_EXIT_DISC attribute */
int capabilities; /* Enable capability handshake [RFC3392] */ int capabilities; /* Enable capability handshake [RFC3392] */
int enable_refresh; /* Enable local support for route refresh [RFC2918] */
int enable_as4; /* Enable local support for 4B AS numbers [RFC4893] */ int enable_as4; /* Enable local support for 4B AS numbers [RFC4893] */
u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */ u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */
int rr_client; /* Whether neighbor is RR client of me */ int rr_client; /* Whether neighbor is RR client of me */
@ -45,6 +48,10 @@ struct bgp_config {
char *password; /* Password used for MD5 authentication */ char *password; /* Password used for MD5 authentication */
}; };
#define MLL_SELF 1
#define MLL_DROP 2
#define MLL_IGNORE 3
struct bgp_conn { struct bgp_conn {
struct bgp_proto *bgp; struct bgp_proto *bgp;
struct birdsock *sk; struct birdsock *sk;
@ -60,6 +67,7 @@ struct bgp_conn {
int start_state; /* protocol start_state snapshot when connection established */ int start_state; /* protocol start_state snapshot when connection established */
int want_as4_support; /* Connection tries to establish AS4 session */ int want_as4_support; /* Connection tries to establish AS4 session */
int peer_as4_support; /* Peer supports 4B AS numbers [RFC4893] */ int peer_as4_support; /* Peer supports 4B AS numbers [RFC4893] */
int peer_refresh_support; /* Peer supports route refresh [RFC2918] */
unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */ unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
}; };
@ -196,6 +204,7 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi
#define PKT_UPDATE 0x02 #define PKT_UPDATE 0x02
#define PKT_NOTIFICATION 0x03 #define PKT_NOTIFICATION 0x03
#define PKT_KEEPALIVE 0x04 #define PKT_KEEPALIVE 0x04
#define PKT_ROUTE_REFRESH 0x05
#define PKT_SCHEDULE_CLOSE 0x1f /* Used internally to schedule socket close */ #define PKT_SCHEDULE_CLOSE 0x1f /* Used internally to schedule socket close */
/* Attributes */ /* Attributes */

View file

@ -22,7 +22,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP, BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP,
BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS, BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS,
PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4, PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4,
CAPABILITIES, LIMIT, PASSIVE) CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER, MISSING, LLADDR,
DROP, IGNORE, ROUTE, REFRESH)
CF_GRAMMAR CF_GRAMMAR
@ -39,6 +40,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->error_amnesia_time = 300; BGP_CFG->error_amnesia_time = 300;
BGP_CFG->error_delay_time_min = 60; BGP_CFG->error_delay_time_min = 60;
BGP_CFG->error_delay_time_max = 300; BGP_CFG->error_delay_time_max = 300;
BGP_CFG->enable_refresh = 1;
BGP_CFG->enable_as4 = bgp_as4_support; BGP_CFG->enable_as4 = bgp_as4_support;
BGP_CFG->capabilities = 2; BGP_CFG->capabilities = 2;
BGP_CFG->advertise_ipv4 = 1; BGP_CFG->advertise_ipv4 = 1;
@ -64,7 +66,11 @@ bgp_proto:
| bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; } | bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; }
| bgp_proto MULTIHOP expr VIA ipa ';' { BGP_CFG->multihop = $3; BGP_CFG->multihop_via = $5; } | bgp_proto MULTIHOP expr VIA ipa ';' { BGP_CFG->multihop = $3; BGP_CFG->multihop_via = $5; }
| bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; } | bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; }
| bgp_proto MISSING LLADDR SELF ';' { BGP_CFG->missing_lladdr = MLL_SELF; }
| bgp_proto MISSING LLADDR DROP ';' { BGP_CFG->missing_lladdr = MLL_DROP; }
| bgp_proto MISSING LLADDR IGNORE ';' { BGP_CFG->missing_lladdr = MLL_IGNORE; }
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; } | bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
| bgp_proto PREFER OLDER bool ';' { BGP_CFG->prefer_older = $4; }
| bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; } | bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; }
| bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; } | bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; }
| bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->source_addr = $4; } | bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->source_addr = $4; }
@ -72,6 +78,7 @@ bgp_proto:
| bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; } | bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; }
| bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; } | bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
| bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; } | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
| bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; } | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; } | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; } | bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }

View file

@ -63,6 +63,14 @@ bgp_put_cap_ipv4(struct bgp_conn *conn UNUSED, byte *buf)
} }
#endif #endif
static byte *
bgp_put_cap_rr(struct bgp_conn *conn UNUSED, byte *buf)
{
*buf++ = 2; /* Capability 2: Support for route refresh */
*buf++ = 0; /* Capability data length */
return buf;
}
static byte * static byte *
bgp_put_cap_as4(struct bgp_conn *conn, byte *buf) bgp_put_cap_as4(struct bgp_conn *conn, byte *buf)
{ {
@ -105,6 +113,9 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
cap = bgp_put_cap_ipv6(conn, cap); cap = bgp_put_cap_ipv6(conn, cap);
#endif #endif
if (p->cf->enable_refresh)
cap = bgp_put_cap_rr(conn, cap);
if (conn->want_as4_support) if (conn->want_as4_support)
cap = bgp_put_cap_as4(conn, cap); cap = bgp_put_cap_as4(conn, cap);
@ -199,7 +210,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
if (a_size < 0) if (a_size < 0)
{ {
log(L_ERR "%s: Attribute list too long, skipping corresponding route group", p->p.name); log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
bgp_flush_prefixes(p, buck); bgp_flush_prefixes(p, buck);
rem_node(&buck->send_node); rem_node(&buck->send_node);
bgp_free_bucket(p, buck); bgp_free_bucket(p, buck);
@ -234,9 +245,9 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
{ {
struct bgp_proto *p = conn->bgp; struct bgp_proto *p = conn->bgp;
struct bgp_bucket *buck; struct bgp_bucket *buck;
int size, second; int size, second, rem_stored;
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
byte *w, *tmp, *tstart; byte *w, *w_stored, *tmp, *tstart;
ip_addr *ipp, ip, ip_ll; ip_addr *ipp, ip, ip_ll;
ea_list *ea; ea_list *ea;
eattr *nh; eattr *nh;
@ -272,28 +283,25 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
} }
DBG("Processing bucket %p\n", buck); DBG("Processing bucket %p\n", buck);
size = bgp_encode_attrs(p, w, buck->eattrs, 2048); rem_stored = remains;
w_stored = w;
size = bgp_encode_attrs(p, w, buck->eattrs, 2048);
if (size < 0) if (size < 0)
{ {
log(L_ERR "%s: Attribute list too long, ignoring corresponding route group", p->p.name); log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
bgp_flush_prefixes(p, buck); bgp_flush_prefixes(p, buck);
rem_node(&buck->send_node); rem_node(&buck->send_node);
bgp_free_bucket(p, buck); bgp_free_bucket(p, buck);
continue; continue;
} }
w += size; w += size;
remains -= size; remains -= size;
tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
*tmp++ = 0; /* We have two addresses here in NEXT_HOP eattr. Really.
*tmp++ = BGP_AF_IPV6; Unless NEXT_HOP was modified by filter */
*tmp++ = 1;
nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
ASSERT(nh); ASSERT(nh);
/* We have two addresses here in 'nh'. Really.
Unless NEXT_HOP was modified by filter */
second = (nh->u.ptr->length == NEXT_HOP_LENGTH); second = (nh->u.ptr->length == NEXT_HOP_LENGTH);
ipp = (ip_addr *) nh->u.ptr->data; ipp = (ip_addr *) nh->u.ptr->data;
ip = ipp[0]; ip = ipp[0];
@ -322,11 +330,31 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
ip_ll = ipp[1]; ip_ll = ipp[1];
else else
{ {
switch (p->cf->missing_lladdr)
{
case MLL_SELF:
ip = p->source_addr; ip = p->source_addr;
ip_ll = p->local_link; ip_ll = p->local_link;
break;
case MLL_DROP:
log(L_ERR "%s: Missing link-local next hop address, skipping corresponding routes", p->p.name);
w = w_stored;
remains = rem_stored;
bgp_flush_prefixes(p, buck);
rem_node(&buck->send_node);
bgp_free_bucket(p, buck);
continue;
case MLL_IGNORE:
break;
} }
} }
} }
}
tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
*tmp++ = 0;
*tmp++ = BGP_AF_IPV6;
*tmp++ = 1;
if (ipa_nonzero(ip_ll)) if (ipa_nonzero(ip_ll))
{ {
@ -369,6 +397,24 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
#endif #endif
static byte *
bgp_create_route_refresh(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
BGP_TRACE(D_PACKETS, "Sending ROUTE-REFRESH");
#ifdef IPV6
*buf++ = 0; /* AFI IPv6 */
*buf++ = BGP_AF_IPV6;
#else
*buf++ = 0; /* AFI IPv4 */
*buf++ = BGP_AF_IPV4;
#endif
*buf++ = 0; /* RFU */
*buf++ = 1; /* and SAFI 1 */
return buf;
}
static void static void
bgp_create_header(byte *buf, unsigned int len, unsigned int type) bgp_create_header(byte *buf, unsigned int len, unsigned int type)
{ {
@ -430,6 +476,12 @@ bgp_fire_tx(struct bgp_conn *conn)
type = PKT_OPEN; type = PKT_OPEN;
end = bgp_create_open(conn, pkt); end = bgp_create_open(conn, pkt);
} }
else if (s & (1 << PKT_ROUTE_REFRESH))
{
s &= ~(1 << PKT_ROUTE_REFRESH);
type = PKT_ROUTE_REFRESH;
end = bgp_create_route_refresh(conn, pkt);
}
else if (s & (1 << PKT_UPDATE)) else if (s & (1 << PKT_UPDATE))
{ {
end = bgp_create_update(conn, pkt); end = bgp_create_update(conn, pkt);
@ -500,6 +552,11 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
switch (opt[0]) switch (opt[0])
{ {
case 2:
if (cl != 0)
goto err;
conn->peer_refresh_support = 1;
break;
case 65: case 65:
if (cl != 4) if (cl != 4)
goto err; goto err;
@ -1067,6 +1124,30 @@ bgp_rx_keepalive(struct bgp_conn *conn)
} }
} }
static void
bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len)
{
struct bgp_proto *p = conn->bgp;
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
if (conn->state != BS_ESTABLISHED)
{ bgp_error(conn, 5, 0, NULL, 0); return; }
if (!p->cf->enable_refresh)
{ bgp_error(conn, 1, 3, pkt+18, 1); return; }
if (len != (BGP_HEADER_LENGTH + 4))
{ bgp_error(conn, 1, 2, pkt+16, 2); return; }
/* FIXME - we ignore AFI/SAFI values, as we support
just one value and even an error code for an invalid
request is not defined */
proto_request_feeding(&p->p);
}
/** /**
* bgp_rx_packet - handle a received packet * bgp_rx_packet - handle a received packet
* @conn: BGP connection * @conn: BGP connection
@ -1086,6 +1167,7 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
case PKT_UPDATE: return bgp_rx_update(conn, pkt, len); case PKT_UPDATE: return bgp_rx_update(conn, pkt, len);
case PKT_NOTIFICATION: return bgp_rx_notification(conn, pkt, len); case PKT_NOTIFICATION: return bgp_rx_notification(conn, pkt, len);
case PKT_KEEPALIVE: return bgp_rx_keepalive(conn); case PKT_KEEPALIVE: return bgp_rx_keepalive(conn);
case PKT_ROUTE_REFRESH: return bgp_rx_route_refresh(conn, pkt, len);
default: bgp_error(conn, 1, 3, pkt+18, 1); default: bgp_error(conn, 1, 3, pkt+18, 1);
} }
} }

View file

@ -549,27 +549,35 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
/* pg 145 (5f) - premature aging of self originated lsa */ /* pg 145 (5f) - premature aging of self originated lsa */
if (self) if (self)
{ {
struct top_hash_entry *en;
if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO)) if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO))
{ {
ospf_lsack_enqueue(n, lsa, ACKL_DIRECT); ospf_lsack_enqueue(n, lsa, ACKL_DIRECT);
continue; continue;
} }
OSPF_TRACE(D_EVENTS, "Received old self-originated LSA (Type: %04x, Id: %R, Rt: %R)",
lsatmp.type, lsatmp.id, lsatmp.rt);
if (lsadb)
{
OSPF_TRACE(D_EVENTS, "Reflooding new self-originated LSA with newer sequence number");
lsadb->lsa.sn = lsatmp.sn + 1;
lsadb->lsa.age = 0;
lsadb->inst_t = now;
lsadb->ini_age = 0;
lsasum_calculate(&lsadb->lsa, lsadb->lsa_body);
ospf_lsupd_flood(po, NULL, NULL, &lsadb->lsa, domain, 1);
}
else
{
OSPF_TRACE(D_EVENTS, "Premature aging it");
lsatmp.age = LSA_MAXAGE; lsatmp.age = LSA_MAXAGE;
lsatmp.sn = LSA_MAXSEQNO; lsatmp.sn = LSA_MAXSEQNO;
lsa->age = htons(LSA_MAXAGE); lsa->age = htons(LSA_MAXAGE);
lsa->sn = htonl(LSA_MAXSEQNO); lsa->sn = htonl(LSA_MAXSEQNO);
OSPF_TRACE(D_EVENTS, "Premature aging self originated LSA.");
OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R",
lsatmp.type, lsatmp.id, lsatmp.rt);
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */ lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
lsatmp.checksum = ntohs(lsa->checksum); lsatmp.checksum = ntohs(lsa->checksum);
ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0); ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
if (en = ospf_hash_find_header(po->gr, domain, &lsatmp))
{ /* FIXME verify hacks */
ospf_lsupd_flood(po, NULL, NULL, &en->lsa, domain, 1);
} }
continue; continue;
} }
@ -577,7 +585,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
/* pg 144 (5a) */ /* pg 144 (5a) */
if (lsadb && ((now - lsadb->inst_t) <= MINLSARRIVAL)) /* FIXME: test for flooding? */ if (lsadb && ((now - lsadb->inst_t) <= MINLSARRIVAL)) /* FIXME: test for flooding? */
{ {
DBG("I got it in less that MINLSARRIVAL\n"); OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MINLSARRIVAL");
sendreq = 0; sendreq = 0;
continue; continue;
} }

View file

@ -31,7 +31,7 @@
#include "pipe.h" #include "pipe.h"
static void static void
pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs) pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs)
{ {
struct proto *src; struct proto *src;
net *nn; net *nn;
@ -80,9 +80,9 @@ pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old, ea_lis
src = old->attrs->proto; src = old->attrs->proto;
} }
dest->pipe_busy = 1; src_table->pipe_busy = 1;
rte_update(dest, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e); rte_update(dest, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e);
dest->pipe_busy = 0; src_table->pipe_busy = 0;
} }
static void static void
@ -91,7 +91,7 @@ pipe_rt_notify_pri(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs
struct pipe_proto *p = (struct pipe_proto *) P; struct pipe_proto *p = (struct pipe_proto *) P;
DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen); DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
pipe_send(p, p->peer, net, new, old, attrs); pipe_send(p, p->p.table, p->peer, net, new, old, attrs);
} }
static void static void
@ -100,7 +100,7 @@ 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; struct pipe_proto *p = ((struct pipe_proto *) P)->phantom;
DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen); DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
pipe_send(p, p->p.table, net, new, old, attrs); pipe_send(p, p->peer, p->p.table, net, new, old, attrs);
} }
static int static int
@ -134,7 +134,20 @@ pipe_start(struct proto *P)
ph->p.rt_notify = pipe_rt_notify_sec; ph->p.rt_notify = pipe_rt_notify_sec;
ph->p.proto_state = PS_UP; ph->p.proto_state = PS_UP;
ph->p.core_state = ph->p.core_goal = FS_HAPPY; ph->p.core_state = ph->p.core_goal = FS_HAPPY;
ph->p.in_filter = ph->p.out_filter = FILTER_ACCEPT; /* We do all filtering on the local end */
/*
* 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 * Connect the phantom protocol to the peer routing table, but

View file

@ -7,7 +7,7 @@
#define _BIRD_CONFIG_H_ #define _BIRD_CONFIG_H_
/* BIRD version */ /* BIRD version */
#define BIRD_VERSION "1.1.5" #define BIRD_VERSION "1.1.6"
/* Include parameters determined by configure script */ /* Include parameters determined by configure script */
#include "sysdep/autoconf.h" #include "sysdep/autoconf.h"

View file

@ -313,8 +313,9 @@ async_shutdown(void)
void void
sysdep_shutdown_done(void) sysdep_shutdown_done(void)
{ {
unlink(PATH_CONTROL_SOCKET); unlink(path_control_socket);
die("System shutdown completed"); log_msg(L_FATAL "System shutdown completed");
exit(0);
} }
/* /*
@ -364,15 +365,17 @@ signal_init(void)
* Parsing of command-line arguments * Parsing of command-line arguments
*/ */
static char *opt_list = "c:dD:s:"; static char *opt_list = "c:dD:ps:";
static void static void
usage(void) usage(void)
{ {
fprintf(stderr, "Usage: bird [-c <config-file>] [-d] [-D <debug-file>] [-s <control-socket>]\n"); fprintf(stderr, "Usage: bird [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>]\n");
exit(1); exit(1);
} }
int parse_and_exit;
static void static void
parse_args(int argc, char **argv) parse_args(int argc, char **argv)
{ {
@ -401,6 +404,9 @@ parse_args(int argc, char **argv)
log_init_debug(optarg); log_init_debug(optarg);
debug_flag |= 2; debug_flag |= 2;
break; break;
case 'p':
parse_and_exit = 1;
break;
case 's': case 's':
path_control_socket = optarg; path_control_socket = optarg;
break; break;
@ -428,6 +434,7 @@ main(int argc, char **argv)
log_init_debug(""); log_init_debug("");
log_init(debug_flag, 1); log_init(debug_flag, 1);
if (!parse_and_exit)
test_old_bird(path_control_socket); test_old_bird(path_control_socket);
DBG("Initializing.\n"); DBG("Initializing.\n");
@ -443,6 +450,9 @@ main(int argc, char **argv)
read_config(); read_config();
if (parse_and_exit)
exit(0);
if (!debug_flag) if (!debug_flag)
{ {
pid_t pid = fork(); pid_t pid = fork();