summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/conf.c9
-rw-r--r--conf/conf.h3
-rw-r--r--doc/reply_codes1
-rw-r--r--nest/proto.c5
-rw-r--r--nest/protocol.h1
-rw-r--r--proto/bgp/bgp.c23
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--sysdep/unix/config.Y4
-rw-r--r--sysdep/unix/krt.c2
-rw-r--r--sysdep/unix/main.c15
-rw-r--r--sysdep/unix/unix.h1
11 files changed, 55 insertions, 11 deletions
diff --git a/conf/conf.c b/conf/conf.c
index d6b3e8e8..0b797dec 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -492,19 +492,24 @@ config_init(void)
* for switching to an empty configuration.
*/
void
-order_shutdown(void)
+order_shutdown(int gr)
{
struct config *c;
if (shutting_down)
return;
- log(L_INFO "Shutting down");
+ if (!gr)
+ log(L_INFO "Shutting down");
+ else
+ log(L_INFO "Shutting down for graceful restart");
+
c = lp_alloc(config->mem, sizeof(struct config));
memcpy(c, config, sizeof(struct config));
init_list(&c->protos);
init_list(&c->tables);
c->shutdown = 1;
+ c->gr_down = gr;
config_commit(c, RECONFIG_HARD, 0);
shutting_down = 1;
diff --git a/conf/conf.h b/conf/conf.h
index 51dcb989..777a1fca 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -55,6 +55,7 @@ struct config {
struct sym_scope *root_scope; /* Scope for root symbols */
int obstacle_count; /* Number of items blocking freeing of this config */
int shutdown; /* This is a pseudo-config for daemon shutdown */
+ int gr_down; /* This is a pseudo-config for graceful restart */
btime load_time; /* When we've got this configuration */
};
@@ -75,7 +76,7 @@ void config_init(void);
void cf_error(const char *msg, ...) NORET;
void config_add_obstacle(struct config *);
void config_del_obstacle(struct config *);
-void order_shutdown(void);
+void order_shutdown(int gr);
#define RECONFIG_NONE 0
#define RECONFIG_HARD 1
diff --git a/doc/reply_codes b/doc/reply_codes
index 3a7f2c90..02f4e656 100644
--- a/doc/reply_codes
+++ b/doc/reply_codes
@@ -33,6 +33,7 @@ Reply codes of BIRD command-line interface
0022 Undo scheduled
0023 Evaluation of expression
0024 Graceful restart status report
+0025 Graceful restart ordered
1000 BIRD version
1001 Interface list
diff --git a/nest/proto.c b/nest/proto.c
index 415471c4..beb3f393 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -1048,6 +1048,11 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
p->down_code = PDC_CF_REMOVE;
p->cf_new = NULL;
}
+ else if (new->gr_down)
+ {
+ p->down_code = PDC_CMD_GR_DOWN;
+ p->cf_new = NULL;
+ }
else /* global shutdown */
{
p->down_code = PDC_CMD_SHUTDOWN;
diff --git a/nest/protocol.h b/nest/protocol.h
index b26d9cc1..53cccd5b 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -257,6 +257,7 @@ struct proto_spec {
#define PDC_CMD_DISABLE 0x11 /* Result of disable command */
#define PDC_CMD_RESTART 0x12 /* Result of restart command */
#define PDC_CMD_SHUTDOWN 0x13 /* Result of global shutdown */
+#define PDC_CMD_GR_DOWN 0x14 /* Result of global graceful restart */
#define PDC_RX_LIMIT_HIT 0x21 /* Route receive limit reached */
#define PDC_IN_LIMIT_HIT 0x22 /* Route import limit reached */
#define PDC_OUT_LIMIT_HIT 0x23 /* Route export limit reached */
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 470c6ff5..cfc31ed0 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -422,7 +422,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
}
static void
-bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode, byte *data, uint len)
+bgp_graceful_close_conn(struct bgp_conn *conn, int subcode, byte *data, uint len)
{
switch (conn->state)
{
@@ -438,7 +438,13 @@ bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode, byte *data, uint le
case BS_OPENSENT:
case BS_OPENCONFIRM:
case BS_ESTABLISHED:
- bgp_error(conn, 6, subcode, data, len);
+ if (subcode < 0)
+ {
+ bgp_conn_enter_close_state(conn);
+ bgp_schedule_packet(conn, NULL, PKT_SCHEDULE_CLOSE);
+ }
+ else
+ bgp_error(conn, 6, subcode, data, len);
return;
default:
@@ -501,7 +507,7 @@ bgp_spawn(struct bgp_proto *pp, ip_addr remote_ip)
}
void
-bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len)
+bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len)
{
proto_notify_state(&p->p, PS_STOP);
bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
@@ -1555,7 +1561,7 @@ static int
bgp_shutdown(struct proto *P)
{
struct bgp_proto *p = (struct bgp_proto *) P;
- uint subcode = 0;
+ int subcode = 0;
char *message = NULL;
byte *data = NULL;
@@ -1576,6 +1582,7 @@ bgp_shutdown(struct proto *P)
case PDC_CMD_DISABLE:
case PDC_CMD_SHUTDOWN:
+ shutdown:
subcode = 2; // Errcode 6, 2 - administrative shutdown
message = P->message;
break;
@@ -1585,6 +1592,14 @@ bgp_shutdown(struct proto *P)
message = P->message;
break;
+ case PDC_CMD_GR_DOWN:
+ if ((p->cf->gr_mode != BGP_GR_ABLE) &&
+ (p->cf->llgr_mode != BGP_LLGR_ABLE))
+ goto shutdown;
+
+ subcode = -1; // Do not send NOTIFICATION, just close the connection
+ break;
+
case PDC_RX_LIMIT_HIT:
case PDC_IN_LIMIT_HIT:
subcode = 1; // Errcode 6, 1 - max number of prefixes reached
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index d8c9fe94..d7f7427f 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -488,7 +488,7 @@ void bgp_graceful_restart_done(struct bgp_channel *c);
void bgp_refresh_begin(struct bgp_channel *c);
void bgp_refresh_end(struct bgp_channel *c);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
-void bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len);
+void bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len);
struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y
index 2895a69e..b78e0e6c 100644
--- a/sysdep/unix/config.Y
+++ b/sysdep/unix/config.Y
@@ -133,6 +133,10 @@ CF_CLI(CONFIGURE CHECK, cfg_name, [\"<file>\"], [[Parse configuration and check
CF_CLI(DOWN,,, [[Shut the daemon down]])
{ cmd_shutdown(); } ;
+CF_CLI(GRACEFUL DOWN,,, [[Shut the daemon down for graceful restart]])
+{ cmd_graceful_restart(); } ;
+
+
cfg_name:
/* empty */ { $$ = NULL; }
| TEXT
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 3aee3fe2..f0e78442 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -1129,7 +1129,7 @@ krt_shutdown(struct proto *P)
krt_scan_timer_stop(p);
/* FIXME we should flush routes even when persist during reconfiguration */
- if (p->initialized && !KRT_CF->persist)
+ if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
krt_flush_routes(p);
p->ready = 0;
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index c381b44f..39465aa8 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -565,14 +565,14 @@ cmd_shutdown(void)
return;
cli_msg(7, "Shutdown requested");
- order_shutdown();
+ order_shutdown(0);
}
void
async_shutdown(void)
{
DBG("Shutting down...\n");
- order_shutdown();
+ order_shutdown(0);
}
void
@@ -584,6 +584,17 @@ sysdep_shutdown_done(void)
exit(0);
}
+void
+cmd_graceful_restart(void)
+{
+ if (cli_access_restricted())
+ return;
+
+ cli_msg(25, "Graceful restart requested");
+ order_shutdown(1);
+}
+
+
/*
* Signals
*/
diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h
index d5ce8ff9..bf0aedeb 100644
--- a/sysdep/unix/unix.h
+++ b/sysdep/unix/unix.h
@@ -28,6 +28,7 @@ void cmd_reconfig_confirm(void);
void cmd_reconfig_undo(void);
void cmd_reconfig_status(void);
void cmd_shutdown(void);
+void cmd_graceful_restart(void);
#define UNIX_DEFAULT_CONFIGURE_TIMEOUT 300