mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 12:48:43 +00:00
Merge branch 'dev' into ospf3
Conflicts: proto/ospf/lsreq.c proto/ospf/lsupd.c proto/ospf/rt.c
This commit is contained in:
commit
63542845df
8
NEWS
8
NEWS
@ -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)
|
||||
o Better scalability of BGP.
|
||||
o New accessors for AS path - first and last.
|
||||
|
1
TODO
1
TODO
@ -21,7 +21,6 @@ Globals
|
||||
|
||||
Various ideas
|
||||
~~~~~~~~~~~~~
|
||||
- client: paging of output
|
||||
- client: Ctrl-R eats one more enter
|
||||
- bgp: timing of updates?
|
||||
- netlink: realms
|
||||
|
@ -162,6 +162,7 @@ protocol static {
|
||||
|
||||
#protocol bgp {
|
||||
# disabled;
|
||||
# description "My BGP uplink"
|
||||
# local as 65000;
|
||||
# neighbor 62.168.0.130 as 5588;
|
||||
# multihop 20 via 62.168.0.13;
|
||||
|
@ -129,7 +129,11 @@ options. The most important ones are:
|
||||
enable debug messages and run bird in foreground.
|
||||
|
||||
<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>
|
||||
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
|
||||
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.
|
||||
</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
|
||||
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>
|
||||
Reload configuration from a given file. BIRD will smoothly
|
||||
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
|
||||
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/
|
||||
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 ˜ [ 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
|
||||
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{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/.
|
||||
Default: switched off.
|
||||
|
||||
<tag>next hop self</tag> Avoid calculation of the Next Hop attribute
|
||||
and always advertise our own source address (see below) as a next hop.
|
||||
This needs to be used only
|
||||
occasionally to circumvent misconfigurations of other routers.
|
||||
<tag>next hop self</tag> Avoid calculation of the Next Hop
|
||||
attribute and always advertise our own source address (see
|
||||
below) as a next hop. This needs to be used only occasionally
|
||||
to circumvent misconfigurations of other routers.
|
||||
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
|
||||
for next hop calculation. Default: the address of the local end
|
||||
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
|
||||
replacement for full mesh EBGP routing in Internet exchange
|
||||
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
|
||||
attributes to be transparent (for example does not prepend its AS number to
|
||||
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
|
||||
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
|
||||
@ -980,6 +1032,11 @@ for each neighbor using the following configuration parameters:
|
||||
<tag>path metric <m/switch/</tag> Enable comparison of path lengths
|
||||
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
|
||||
Discriminator to be used during route selection when the MED attribute
|
||||
is missing. Default: 0.
|
||||
|
@ -23,6 +23,7 @@ Reply codes of BIRD command-line interface
|
||||
0012 Restarted
|
||||
0013 Status report
|
||||
0014 Route count
|
||||
0015 Reloading
|
||||
|
||||
1000 BIRD version
|
||||
1001 Interface list
|
||||
@ -40,6 +41,7 @@ Reply codes of BIRD command-line interface
|
||||
1013 Show ospf neighbors
|
||||
1014 Show ospf
|
||||
1015 Show ospf interface
|
||||
1016 Show ospf state/topology
|
||||
|
||||
8000 Reply too long
|
||||
8001 Route not found
|
||||
@ -47,6 +49,7 @@ Reply codes of BIRD command-line interface
|
||||
8003 No protocols match
|
||||
8004 Stopped due to reconfiguration
|
||||
8005 Protocol is down => cannot dump
|
||||
8006 Reload failed
|
||||
|
||||
9000 Command too long
|
||||
9001 Parse error
|
||||
|
@ -731,7 +731,7 @@ interpret(struct f_inst *what)
|
||||
case P('a','f'): /* Get first ASN from AS PATH */
|
||||
ONEARG;
|
||||
if (v1.type != T_PATH)
|
||||
runtime( "AS Path expected" );
|
||||
runtime( "AS path expected" );
|
||||
|
||||
as = 0;
|
||||
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('A','p'): TWOARGS; break;
|
||||
case P('C','a'): TWOARGS; break;
|
||||
case P('a','f'):
|
||||
case P('a','l'): ONEARG; break;
|
||||
default:
|
||||
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
Summary: BIRD Internet Routing Daemon
|
||||
Name: bird
|
||||
Version: 1.1.5
|
||||
Version: 1.1.6
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Networking/Daemons
|
||||
|
@ -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(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)
|
||||
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,
|
||||
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
|
||||
@ -141,6 +142,7 @@ proto_item:
|
||||
| EXPORT imexport { this_proto->out_filter = $2; }
|
||||
| TABLE rtable { this_proto->table = $2; }
|
||||
| ROUTER ID idval { this_proto->router_id = $3; }
|
||||
| DESCRIPTION TEXT { this_proto->dsc = $2; }
|
||||
;
|
||||
|
||||
imexport:
|
||||
@ -436,11 +438,17 @@ echo_size:
|
||||
;
|
||||
|
||||
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]])
|
||||
{ proto_xxable($2, 1); } ;
|
||||
{ proto_xxable($2, XX_ENABLE); } ;
|
||||
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(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging]])
|
||||
|
93
nest/proto.c
93
nest/proto.c
@ -73,6 +73,10 @@ proto_relink(struct proto *p)
|
||||
rem_node(&p->n);
|
||||
switch (p->core_state)
|
||||
{
|
||||
case FS_HUNGRY:
|
||||
l = &inactive_proto_list;
|
||||
break;
|
||||
case FS_FEEDING:
|
||||
case FS_HAPPY:
|
||||
l = &active_proto_list;
|
||||
break;
|
||||
@ -80,7 +84,7 @@ proto_relink(struct proto *p)
|
||||
l = &flush_proto_list;
|
||||
break;
|
||||
default:
|
||||
l = &inactive_proto_list;
|
||||
ASSERT(0);
|
||||
}
|
||||
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)
|
||||
{
|
||||
/* Found match, let's check if we can smoothly switch to new configuration */
|
||||
/* No need to check description */
|
||||
nc = sym->def;
|
||||
if (!force_reconfig
|
||||
&& nc->protocol == oc->protocol
|
||||
@ -548,7 +553,7 @@ proto_feed_more(void *P)
|
||||
}
|
||||
|
||||
static void
|
||||
proto_feed(void *P)
|
||||
proto_feed_initial(void *P)
|
||||
{
|
||||
struct proto *p = P;
|
||||
|
||||
@ -576,15 +581,50 @@ proto_schedule_flush(struct proto *p)
|
||||
}
|
||||
|
||||
static void
|
||||
proto_schedule_feed(struct proto *p)
|
||||
proto_schedule_feed(struct proto *p, int initial)
|
||||
{
|
||||
DBG("%s: Scheduling meal\n", p->name);
|
||||
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);
|
||||
p->attn->hook = proto_feed;
|
||||
p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
|
||||
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
|
||||
* @p: protocol the state of which has changed
|
||||
@ -614,7 +654,7 @@ proto_notify_state(struct proto *p, unsigned ps)
|
||||
switch (ps)
|
||||
{
|
||||
case PS_DOWN:
|
||||
if ((cs = FS_FEEDING) || (cs == FS_HAPPY))
|
||||
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
|
||||
proto_schedule_flush(p);
|
||||
|
||||
neigh_prune(); // FIXME convert neighbors to resource?
|
||||
@ -634,10 +674,10 @@ proto_notify_state(struct proto *p, unsigned ps)
|
||||
case PS_UP:
|
||||
ASSERT(ops == PS_DOWN || ops == PS_START);
|
||||
ASSERT(cs == FS_HUNGRY);
|
||||
proto_schedule_feed(p);
|
||||
proto_schedule_feed(p, 1);
|
||||
break;
|
||||
case PS_STOP:
|
||||
if ((cs = FS_FEEDING) || (cs == FS_HAPPY))
|
||||
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
|
||||
proto_schedule_flush(p);
|
||||
break;
|
||||
default:
|
||||
@ -702,6 +742,8 @@ proto_do_show(struct proto *p, int verbose)
|
||||
buf);
|
||||
if (verbose)
|
||||
{
|
||||
if (p->cf->dsc)
|
||||
cli_msg(-1006, " Description: %s", p->cf->dsc);
|
||||
cli_msg(-1006, " Preference: %d", p->preference);
|
||||
cli_msg(-1006, " Input filter: %s", filter_name(p->in_filter));
|
||||
cli_msg(-1006, " Output filter: %s", filter_name(p->out_filter));
|
||||
@ -788,25 +830,29 @@ proto_xxable(char *pattern, int xx)
|
||||
cnt++;
|
||||
switch (xx)
|
||||
{
|
||||
case 0:
|
||||
case XX_DISABLE:
|
||||
if (p->disabled)
|
||||
cli_msg(-8, "%s: already disabled", p->name);
|
||||
else
|
||||
{
|
||||
cli_msg(-9, "%s: disabled", p->name);
|
||||
p->disabled = 1;
|
||||
proto_rethink_goal(p);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
|
||||
case XX_ENABLE:
|
||||
if (!p->disabled)
|
||||
cli_msg(-10, "%s: already enabled", p->name);
|
||||
else
|
||||
{
|
||||
cli_msg(-11, "%s: enabled", p->name);
|
||||
p->disabled = 0;
|
||||
proto_rethink_goal(p);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
|
||||
case XX_RESTART:
|
||||
if (p->disabled)
|
||||
cli_msg(-8, "%s: already disabled", p->name);
|
||||
else
|
||||
@ -814,13 +860,38 @@ proto_xxable(char *pattern, int xx)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
proto_rethink_goal(p);
|
||||
}
|
||||
WALK_PROTO_LIST_END;
|
||||
if (!cnt)
|
||||
|
@ -81,6 +81,7 @@ struct proto_config {
|
||||
struct protocol *protocol; /* Protocol */
|
||||
struct proto *proto; /* Instance we've created */
|
||||
char *name;
|
||||
char *dsc;
|
||||
unsigned debug, preference, disabled; /* Generic parameters */
|
||||
u32 router_id; /* Protocol specific router ID */
|
||||
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_goal; /* State we want to reach (see below) */
|
||||
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 */
|
||||
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 */
|
||||
@ -151,6 +153,9 @@ struct proto {
|
||||
* It can construct a new rte, add private attributes and
|
||||
* decide whether the route shall be imported: 1=yes, -1=no,
|
||||
* 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);
|
||||
@ -160,6 +165,7 @@ struct proto {
|
||||
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
|
||||
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 (*reload_routes)(struct proto *);
|
||||
|
||||
/*
|
||||
* 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_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 *, 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
|
||||
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 -->
|
||||
* FEEDING/UP --> HAPPY/UP --> FLUSHING/STOP|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
|
||||
|
@ -158,13 +158,15 @@ 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)
|
||||
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;
|
||||
rte *new0 = new;
|
||||
rte *old0 = old;
|
||||
int ok;
|
||||
|
||||
int fast_exit_hack = 0;
|
||||
|
||||
if (new)
|
||||
{
|
||||
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++;
|
||||
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)
|
||||
{
|
||||
@ -199,7 +202,32 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
|
||||
else
|
||||
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)
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -224,9 +253,11 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
|
||||
else
|
||||
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)
|
||||
p->stats.exp_routes++;
|
||||
if (old)
|
||||
if (old && !refeed)
|
||||
p->stats.exp_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);
|
||||
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 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))
|
||||
{
|
||||
/* 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;
|
||||
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)
|
||||
rte_trace_in(D_ROUTES, p, old, "removed");
|
||||
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;
|
||||
struct filter *filter = p->in_filter;
|
||||
|
||||
/* Do not filter routes going to the secondary side of the pipe,
|
||||
that should only go through export filter.
|
||||
FIXME Make a better check whether p is really a pipe. */
|
||||
if (p->table != table)
|
||||
/* Do not filter routes going through the pipe,
|
||||
they are filtered in the export filter only. */
|
||||
#ifdef CONFIG_PIPE
|
||||
if (p->proto == &proto_pipe)
|
||||
filter = FILTER_ACCEPT;
|
||||
#endif
|
||||
|
||||
p->stats.imp_updates_received++;
|
||||
if (!rte_validate(new))
|
||||
@ -636,6 +687,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
|
||||
|
||||
drop:
|
||||
rte_free(new);
|
||||
rte_recalculate(table, net, p, src, NULL, NULL);
|
||||
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();
|
||||
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();
|
||||
}
|
||||
|
||||
@ -1121,6 +1173,11 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||
ok = 0;
|
||||
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 ||
|
||||
p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
|
||||
ok = 0;
|
||||
|
@ -165,6 +165,22 @@ bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a, int len)
|
||||
#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
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
NULL, NULL },
|
||||
{ "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;
|
||||
|
||||
/* RFC 4271 9.1.2.2. c) Compare MED's */
|
||||
|
||||
if (bgp_get_neighbor(new) == bgp_get_neighbor(old))
|
||||
{
|
||||
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));
|
||||
n = x ? x->u.data : new_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)
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
bgp_start_locked(struct object_lock *lock)
|
||||
{
|
||||
@ -792,6 +803,7 @@ bgp_init(struct proto_config *C)
|
||||
P->rte_better = bgp_rte_better;
|
||||
P->import_control = bgp_import_control;
|
||||
P->neigh_notify = bgp_neigh_notify;
|
||||
P->reload_routes = bgp_reload_routes;
|
||||
p->cf = c;
|
||||
p->local_as = c->local_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))
|
||||
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" };
|
||||
|
@ -23,10 +23,13 @@ struct bgp_config {
|
||||
ip_addr multihop_via; /* Multihop: address to route to */
|
||||
ip_addr source_addr; /* Source address to use */
|
||||
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 prefer_older; /* Prefer older routes according to RFC 5004 */
|
||||
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */
|
||||
u32 default_med; /* Default value for MULTI_EXIT_DISC attribute */
|
||||
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] */
|
||||
u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */
|
||||
int rr_client; /* Whether neighbor is RR client of me */
|
||||
@ -45,6 +48,10 @@ struct bgp_config {
|
||||
char *password; /* Password used for MD5 authentication */
|
||||
};
|
||||
|
||||
#define MLL_SELF 1
|
||||
#define MLL_DROP 2
|
||||
#define MLL_IGNORE 3
|
||||
|
||||
struct bgp_conn {
|
||||
struct bgp_proto *bgp;
|
||||
struct birdsock *sk;
|
||||
@ -60,6 +67,7 @@ struct bgp_conn {
|
||||
int start_state; /* protocol start_state snapshot when connection established */
|
||||
int want_as4_support; /* Connection tries to establish AS4 session */
|
||||
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 */
|
||||
};
|
||||
|
||||
@ -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_NOTIFICATION 0x03
|
||||
#define PKT_KEEPALIVE 0x04
|
||||
#define PKT_ROUTE_REFRESH 0x05
|
||||
#define PKT_SCHEDULE_CLOSE 0x1f /* Used internally to schedule socket close */
|
||||
|
||||
/* Attributes */
|
||||
|
@ -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_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS,
|
||||
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
|
||||
|
||||
@ -39,6 +40,7 @@ bgp_proto_start: proto_start BGP {
|
||||
BGP_CFG->error_amnesia_time = 300;
|
||||
BGP_CFG->error_delay_time_min = 60;
|
||||
BGP_CFG->error_delay_time_max = 300;
|
||||
BGP_CFG->enable_refresh = 1;
|
||||
BGP_CFG->enable_as4 = bgp_as4_support;
|
||||
BGP_CFG->capabilities = 2;
|
||||
BGP_CFG->advertise_ipv4 = 1;
|
||||
@ -64,7 +66,11 @@ bgp_proto:
|
||||
| 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 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 PREFER OLDER bool ';' { BGP_CFG->prefer_older = $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 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 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 ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
|
||||
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
|
||||
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
|
||||
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
|
||||
|
@ -63,6 +63,14 @@ bgp_put_cap_ipv4(struct bgp_conn *conn UNUSED, byte *buf)
|
||||
}
|
||||
#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 *
|
||||
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);
|
||||
#endif
|
||||
|
||||
if (p->cf->enable_refresh)
|
||||
cap = bgp_put_cap_rr(conn, cap);
|
||||
|
||||
if (conn->want_as4_support)
|
||||
cap = bgp_put_cap_as4(conn, cap);
|
||||
|
||||
@ -199,7 +210,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||
|
||||
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);
|
||||
rem_node(&buck->send_node);
|
||||
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_bucket *buck;
|
||||
int size, second;
|
||||
int size, second, rem_stored;
|
||||
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;
|
||||
ea_list *ea;
|
||||
eattr *nh;
|
||||
@ -272,28 +283,25 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
rem_node(&buck->send_node);
|
||||
bgp_free_bucket(p, buck);
|
||||
continue;
|
||||
}
|
||||
|
||||
w += size;
|
||||
remains -= size;
|
||||
tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
|
||||
*tmp++ = 0;
|
||||
*tmp++ = BGP_AF_IPV6;
|
||||
*tmp++ = 1;
|
||||
|
||||
/* We have two addresses here in NEXT_HOP eattr. Really.
|
||||
Unless NEXT_HOP was modified by filter */
|
||||
nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
|
||||
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);
|
||||
ipp = (ip_addr *) nh->u.ptr->data;
|
||||
ip = ipp[0];
|
||||
@ -322,12 +330,32 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||
ip_ll = ipp[1];
|
||||
else
|
||||
{
|
||||
ip = p->source_addr;
|
||||
ip_ll = p->local_link;
|
||||
switch (p->cf->missing_lladdr)
|
||||
{
|
||||
case MLL_SELF:
|
||||
ip = p->source_addr;
|
||||
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))
|
||||
{
|
||||
*tmp++ = 32;
|
||||
@ -369,6 +397,24 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||
|
||||
#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
|
||||
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;
|
||||
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))
|
||||
{
|
||||
end = bgp_create_update(conn, pkt);
|
||||
@ -500,6 +552,11 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
|
||||
|
||||
switch (opt[0])
|
||||
{
|
||||
case 2:
|
||||
if (cl != 0)
|
||||
goto err;
|
||||
conn->peer_refresh_support = 1;
|
||||
break;
|
||||
case 65:
|
||||
if (cl != 4)
|
||||
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
|
||||
* @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_NOTIFICATION: return bgp_rx_notification(conn, pkt, len);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
if (self)
|
||||
{
|
||||
struct top_hash_entry *en;
|
||||
|
||||
if ((lsatmp.age == LSA_MAXAGE) && (lsatmp.sn == LSA_MAXSEQNO))
|
||||
{
|
||||
ospf_lsack_enqueue(n, lsa, ACKL_DIRECT);
|
||||
continue;
|
||||
}
|
||||
|
||||
lsatmp.age = LSA_MAXAGE;
|
||||
lsatmp.sn = LSA_MAXSEQNO;
|
||||
lsa->age = htons(LSA_MAXAGE);
|
||||
lsa->sn = htonl(LSA_MAXSEQNO);
|
||||
OSPF_TRACE(D_EVENTS, "Premature aging self originated LSA.");
|
||||
OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R",
|
||||
OSPF_TRACE(D_EVENTS, "Received old self-originated LSA (Type: %04x, Id: %R, Rt: %R)",
|
||||
lsatmp.type, lsatmp.id, lsatmp.rt);
|
||||
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
|
||||
lsatmp.checksum = ntohs(lsa->checksum);
|
||||
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);
|
||||
|
||||
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.sn = LSA_MAXSEQNO;
|
||||
lsa->age = htons(LSA_MAXAGE);
|
||||
lsa->sn = htonl(LSA_MAXSEQNO);
|
||||
lsasum_check(lsa, (lsa + 1)); /* It also calculates chsum! */
|
||||
lsatmp.checksum = ntohs(lsa->checksum);
|
||||
ospf_lsupd_flood(po, NULL, lsa, &lsatmp, domain, 0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -577,7 +585,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
/* pg 144 (5a) */
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "pipe.h"
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
dest->pipe_busy = 1;
|
||||
src_table->pipe_busy = 1;
|
||||
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
|
||||
@ -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;
|
||||
|
||||
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
|
||||
@ -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;
|
||||
|
||||
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
|
||||
@ -134,7 +134,20 @@ pipe_start(struct proto *P)
|
||||
ph->p.rt_notify = pipe_rt_notify_sec;
|
||||
ph->p.proto_state = PS_UP;
|
||||
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
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define _BIRD_CONFIG_H_
|
||||
|
||||
/* BIRD version */
|
||||
#define BIRD_VERSION "1.1.5"
|
||||
#define BIRD_VERSION "1.1.6"
|
||||
|
||||
/* Include parameters determined by configure script */
|
||||
#include "sysdep/autoconf.h"
|
||||
|
@ -313,8 +313,9 @@ async_shutdown(void)
|
||||
void
|
||||
sysdep_shutdown_done(void)
|
||||
{
|
||||
unlink(PATH_CONTROL_SOCKET);
|
||||
die("System shutdown completed");
|
||||
unlink(path_control_socket);
|
||||
log_msg(L_FATAL "System shutdown completed");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -364,15 +365,17 @@ signal_init(void)
|
||||
* Parsing of command-line arguments
|
||||
*/
|
||||
|
||||
static char *opt_list = "c:dD:s:";
|
||||
static char *opt_list = "c:dD:ps:";
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
int parse_and_exit;
|
||||
|
||||
static void
|
||||
parse_args(int argc, char **argv)
|
||||
{
|
||||
@ -401,6 +404,9 @@ parse_args(int argc, char **argv)
|
||||
log_init_debug(optarg);
|
||||
debug_flag |= 2;
|
||||
break;
|
||||
case 'p':
|
||||
parse_and_exit = 1;
|
||||
break;
|
||||
case 's':
|
||||
path_control_socket = optarg;
|
||||
break;
|
||||
@ -428,7 +434,8 @@ main(int argc, char **argv)
|
||||
log_init_debug("");
|
||||
log_init(debug_flag, 1);
|
||||
|
||||
test_old_bird(path_control_socket);
|
||||
if (!parse_and_exit)
|
||||
test_old_bird(path_control_socket);
|
||||
|
||||
DBG("Initializing.\n");
|
||||
resource_init();
|
||||
@ -443,6 +450,9 @@ main(int argc, char **argv)
|
||||
|
||||
read_config();
|
||||
|
||||
if (parse_and_exit)
|
||||
exit(0);
|
||||
|
||||
if (!debug_flag)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
Loading…
Reference in New Issue
Block a user