summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2009-11-26 20:47:59 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2009-11-26 20:47:59 +0100
commitbf47fe4b2e40ccfcfe6af2d86548d06cdf9739c5 (patch)
tree59108f1bdc8f5192a27e9a40d72a7e950686dd8c /nest
parent5e6f568115511e2bcf43c60dfdcbd7a35cb04b93 (diff)
downloadbird-bf47fe4b2e40ccfcfe6af2d86548d06cdf9739c5.tar
bird-bf47fe4b2e40ccfcfe6af2d86548d06cdf9739c5.zip
Implements BGP route refresh.
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y7
-rw-r--r--nest/proto.c67
-rw-r--r--nest/protocol.h9
-rw-r--r--nest/rt-table.c14
4 files changed, 91 insertions, 6 deletions
diff --git a/nest/config.Y b/nest/config.Y
index 3d6f154..dde20c5 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -45,6 +45,7 @@ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILT
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
+CF_KEYWORDS(RELOAD, REFEED)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@@ -442,6 +443,12 @@ CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]]
{ proto_xxable($2, 1); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]])
{ proto_xxable($2, 2); } ;
+CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
+{ proto_xxable($2, 3); } ;
+CF_CLI(REFEED, proto_patt, <protocol> | \"<pattern>\" | all, [[Refeed protocol BROKEN]])
+{ proto_xxable($2, 4); } ;
+
+
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]])
diff --git a/nest/proto.c b/nest/proto.c
index c05db76..c531d86 100644
--- a/nest/proto.c
+++ b/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);
}
@@ -549,7 +553,7 @@ proto_feed_more(void *P)
}
static void
-proto_feed(void *P)
+proto_feed_initial(void *P)
{
struct proto *p = P;
@@ -577,16 +581,45 @@ 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;
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
* @ps: the new status
@@ -635,7 +668,7 @@ 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))
@@ -798,6 +831,7 @@ proto_xxable(char *pattern, int xx)
{
cli_msg(-9, "%s: disabled", p->name);
p->disabled = 1;
+ proto_rethink_goal(p);
}
break;
case 1:
@@ -807,6 +841,7 @@ proto_xxable(char *pattern, int xx)
{
cli_msg(-11, "%s: enabled", p->name);
p->disabled = 0;
+ proto_rethink_goal(p);
}
break;
case 2:
@@ -817,13 +852,33 @@ 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 3:
+ // FIXME change msg number
+ if (p->disabled)
+ cli_msg(-8, "%s: already disabled", p->name);
+ else if (p->reload_routes && p->reload_routes(p))
+ cli_msg(-12, "%s: reloading", p->name);
+ else
+ cli_msg(-12, "%s: reload failed", p->name);
+ break;
+ case 4:
+ // FIXME change msg number
+ if (p->disabled)
+ cli_msg(-8, "%s: already disabled", p->name);
+ else
+ {
+ proto_request_feeding(p);
+ cli_msg(-12, "%s: reexport failed", p->name);
+ }
+ break;
+
default:
ASSERT(0);
}
- proto_rethink_goal(p);
}
WALK_PROTO_LIST_END;
if (!cnt)
diff --git a/nest/protocol.h b/nest/protocol.h
index 807b579..66e6c43 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -152,6 +152,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);
@@ -161,6 +164,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):
@@ -190,6 +194,7 @@ 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);
@@ -271,6 +276,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
diff --git a/nest/rt-table.c b/nest/rt-table.c
index dda0e56..e0cd797 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -199,6 +199,14 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
else
p->stats.exp_withdraws_received++;
+ /* 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 */
+
if (old)
{
if (p->out_filter == FILTER_REJECT)
@@ -216,6 +224,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;
@@ -1122,6 +1131,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;