summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_main.c')
-rw-r--r--bgpd/bgp_main.c365
1 files changed, 219 insertions, 146 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 366949af..32cbf91b 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -19,6 +19,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include <zebra.h>
+#include <stdbool.h>
#include "vector.h"
#include "vty.h"
@@ -37,7 +38,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "plist.h"
#include "qpnexus.h"
#include "qlib_init.h"
-#include "thread.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -72,57 +72,24 @@ static const struct option longopts[] =
{ "dryrun", no_argument, NULL, 'C'},
{ "help", no_argument, NULL, 'h'},
{ "threaded", no_argument, NULL, 't'},
+ { "ignore_warnings", no_argument, NULL, 'I'},
{ 0 }
};
-
-/* signal definitions */
-void sighup (void);
-void sigint (void);
-void sigusr1 (void);
-void sigusr2 (void);
-
-/* prototypes */
-static void bgp_exit (int);
-static void init_second_stage(int pthreads);
-static void bgp_in_thread_init(void);
-static void routing_start(void) ;
-static int routing_foreground(void);
-static int routing_background(void);
-static void sighup_action(mqueue_block mqb, mqb_flag_t flag);
-static void sighup_enqueue(void);
-static void sigterm_action(mqueue_block mqb, mqb_flag_t flag);
-static void sigterm_enqueue(void);
-
-static struct quagga_signal_t bgp_signals[] =
-{
- {
- .signal = SIGHUP,
- .handler = &sighup,
- },
- {
- .signal = SIGUSR1,
- .handler = &sigusr1,
- },
- {
- .signal = SIGUSR2,
- .handler = &sigusr2,
- },
- {
- .signal = SIGINT,
- .handler = &sigint,
- },
- {
- .signal = SIGTERM,
- .handler = &sigint,
- },
-};
-
/* Configuration file and directory. */
char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG;
/* Route retain mode flag. */
static int retain_mode = 0;
+/* whether to ignore warnings in configuration file */
+static bool config_ignore_warnings = false;
+
+/* whether configured to run with qpthreads */
+static bool config_threaded = 0;
+
+/* whether configured to run as an AS2 speaker */
+static bool config_as2_speaker = 0;
+
/* Master of threads. */
struct thread_master *master;
@@ -130,12 +97,12 @@ struct thread_master *master;
char *config_file = NULL;
/* Have we done the second stage initialization? */
-static int done_2nd_state_init = 0;
+static int done_2nd_stage_init = 0;
/* Process ID saved for use by init system */
static const char *pid_file = PATH_BGPD_PID;
/* VTY port number and address. */
-int vty_port = BGP_VTY_PORT;
+int vty_port = BGP_VTY_PORT;
char *vty_addr = NULL;
/* privileges */
@@ -167,59 +134,113 @@ usage (char *progname, int status)
fprintf (stderr, "Try `%s --help' for more information.\n", progname);
else
{
- printf ("Usage : %s [OPTION...]\n\n\
-Daemon which manages kernel routing table management and \
-redistribution between different routing protocols.\n\n\
--d, --daemon Runs in daemon mode\n\
--f, --config_file Set configuration file name\n\
--i, --pid_file Set process identifier file name\n\
--p, --bgp_port Set bgp protocol's port number\n\
--l, --listenon Listen on specified address (implies -n)\n\
--A, --vty_addr Set vty's bind address\n\
--P, --vty_port Set vty's port number\n\
--r, --retain When program terminates, retain added route by bgpd.\n\
--n, --no_kernel Do not install route to kernel.\n\
--u, --user User to run as\n\
--g, --group Group to run as\n\
--v, --version Print program version\n\
--C, --dryrun Check configuration for validity and exit\n\
--h, --help Display this help and exit\n\
--t, --threaded Use pthreads\n\
-\n\
-Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+ printf (
+ "Usage : %s [OPTION...]\n"
+ "\n"
+ "Daemon which manages kernel routing table management and redistribution "
+ "between different routing protocols.\n"
+ "\n"
+ "-d, --daemon Runs in daemon mode\n"
+ "-f, --config_file Set configuration file name\n"
+ "-i, --pid_file Set process identifier file name\n"
+ "-p, --bgp_port Set bgp protocol's port number\n"
+ "-l, --listenon Listen on specified address (implies -n)\n"
+ "-A, --vty_addr Set vty's bind address\n"
+ "-P, --vty_port Set vty's port number\n"
+ "-r, --retain When program terminates, retain added route by bgpd.\n"
+ "-n, --no_kernel Do not install route to kernel.\n"
+ "-u, --user User to run as\n"
+ "-g, --group Group to run as\n"
+ "-v, --version Print program version\n"
+ "-C, --dryrun Check configuration for validity and exit\n"
+ "-h, --help Display this help and exit\n"
+ "-t, --threaded Use pthreads\n"
+ "-I, --ignore_warnings Ignore warnings while reading configuration file\n"
+ "-2, --as2 Do not advertise AS4 capability\n"
+ "\n"
+ "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
}
exit (status);
}
+/*==============================================================================
+ * Signal Handling.
+ *
+ * Actual signals are caught in lib/sigevent. When a signal is caught, a flag
+ * is set and the immediate signal handler returns.
+ *
+ * Those flags are polled in the qpnexus loop, and the Quagga level signal
+ * handler called -- in the main (CLI) thread.
+ */
+
+/* signal definitions */
+void sighup (void);
+void sigint (void);
+void sigusr1 (void);
+void sigusr2 (void);
+
+/* prototypes */
+static void bgp_exit (int);
+static void init_second_stage(int pthreads);
+static void bgp_in_thread_init(void);
+static void routing_start(void) ;
+static void routing_finish(void) ;
+static int routing_foreground(void);
+static int routing_background(void);
+static void sighup_action(mqueue_block mqb, mqb_flag_t flag);
+static void sighup_enqueue(void);
+static void sigterm_action(mqueue_block mqb, mqb_flag_t flag);
+static void sigterm_enqueue(void);
+
+static struct quagga_signal_t bgp_signals[] =
+{
+ {
+ .signal = SIGHUP,
+ .handler = &sighup,
+ },
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ },
+ {
+ .signal = SIGUSR2,
+ .handler = &sigusr2,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+};
-/* SIGHUP handler. */
+/*------------------------------------------------------------------------------
+ * SIGHUP handler.
+ *
+ * The vty level is reset, closing all terminals and vtysh servers, and
+ * closing all listeners.
+ *
+ * A message is sent to the Routeing Engine to restart.
+ *
+ * When the Routeing Engine has restarted, it will send a message to the CLI
+ * to restart the listeners.
+ */
void
sighup (void)
{
zlog (NULL, LOG_INFO, "SIGHUP received");
- /* tell the routing engine */
- sighup_enqueue();
-
- zlog_info ("bgpd restarting!");
-
- /* Reload config file. */
- vty_reset();
- vty_read_config (config_file, config_default);
-
- /* Create VTY's socket */
- vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH);
+ vty_reset_because("Reloading configuration");
+ sighup_enqueue(); /* tell the Routeing Engine */
- /* Try to return to normal operation. */
}
/* SIGINT handler. */
void
sigint (void)
{
-#ifdef QDEBUG
- vty_goodbye();
-#endif
zlog_notice ("Terminating on signal");
/* tell the routing engine to send notifies to peers and wait
@@ -245,20 +266,23 @@ sigusr2 (void)
exit(1);
}
-
-/*
- Try to free up allocations we know about so that diagnostic tools such as
- valgrind are able to better illuminate leaks.
-
- Zebra route removal and protocol teardown are not meant to be done here.
- For example, "retain_mode" may be set.
-*/
+/*------------------------------------------------------------------------------
+ * Final exit code...
+ *
+ * ...try to free up allocations we know about so that diagnostic tools such as
+ * valgrind are able to better illuminate leaks.
+ *
+ * Zebra route removal and protocol teardown are not meant to be done here.
+ * For example, "retain_mode" may be set.
+ *
+ * Note that by the time reach here, only the main (CLI) thread is running,
+ *
+ */
static void
bgp_exit (int status)
{
struct bgp *bgp;
struct listnode *node, *nnode;
- int *socket;
struct interface *ifp;
extern struct zclient *zclient;
extern struct zclient *zlookup;
@@ -271,14 +295,6 @@ bgp_exit (int status)
bgp_delete (bgp);
list_free (bm->bgp);
- /* reverse bgp_master_init */
- for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket))
- {
- if (close ((int)(long)socket) == -1)
- zlog_err ("close (%d): %s", (int)(long)socket, safe_strerror (errno));
- }
- list_delete (bm->listen_sockets);
-
/* reverse bgp_zebra_init/if_init */
if (retain_mode)
if_add_hook (IF_DELETE_HOOK, NULL);
@@ -286,6 +302,9 @@ bgp_exit (int status)
if_delete (ifp);
list_free (iflist);
+ /* curtains */
+ zlog_notice ("Terminated");
+
/* reverse bgp_attr_init */
bgp_attr_finish ();
@@ -332,43 +351,59 @@ bgp_exit (int status)
if (zlog_default)
closezlog (zlog_default);
+ zlog_default = NULL ;
+
+ if (qpthreads_enabled)
+ {
+ qpn_reset_free(routing_nexus);
+ qpn_reset_free(bgp_nexus);
+ } ;
+ cli_nexus = qpn_reset_free(cli_nexus);
if (CONF_BGP_DEBUG (normal, NORMAL))
log_memstats_stderr ("bgpd");
- if (qpthreads_enabled)
- {
- routing_nexus = qpn_free(routing_nexus);
- bgp_nexus = qpn_free(bgp_nexus);
- }
- cli_nexus = qpn_free(cli_nexus);
-
qexit (status);
}
+/*------------------------------------------------------------------------------
+ * Second stage initialisation and qpthreads_enabled.
+ *
+ * Really want to do this before the configuration file is read. However,
+ * also want to allow qpthreads to be enabled by configuration file.
+ *
+ * So... configuration file reader has a mechanism to look for a given
+ * command as the *first* in the file and:
+ *
+ * 1. if it's there, invoke the command in the usual way
+ *
+ * 2. if it's not there, invoke the command but with a NULL set of arguments,
+ * which signals the "default" nature of the call.
+ *
+ * This mechanism is used so that the "threaded_cmd" is the time at which
+ * second stage initialisation is done. (But only once -- not on rereading
+ * the configuration file.)
+ */
+
/* Threaded command. If present must be the first command in the
- * configuration file. If not the first command it will log and abort. */
+ * configuration file. If not the first command it will log and abort.
+ */
DEFUN_HID_CALL (threaded,
threaded_cmd,
"threaded",
"Use pthreads\n")
{
- if (!qpthreads_enabled)
- init_second_stage(1);
+ if (argv != NULL)
+ config_threaded = 1 ; /* Explicit command => turn on threading */
+ if (!done_2nd_stage_init)
+ init_second_stage(config_threaded) ;
+ else
+ vty_out(vty, "pthreads are %s\n", qpthreads_enabled ? "enabled"
+ : "disabled") ;
return CMD_SUCCESS;
}
-/* If neither the command line nor the first command enabled pthreads
- * then disable pthreads. This is a call back after processing the
- * first command in the configuration file
- */
-static void after_first_cmd()
-{
- if (!qpthreads_enabled)
- init_second_stage(0);
-}
-
/* Enable or disables pthreads. Create the nexus(es). Perform
* any post nexus creation initialization. The nexus(es) need
* to be created as soon as we know the pthread state so that
@@ -377,10 +412,9 @@ static void after_first_cmd()
static void
init_second_stage(int pthreads)
{
- if (done_2nd_state_init)
- return;
+ assert(!done_2nd_stage_init) ;
- done_2nd_state_init = 1;
+ done_2nd_stage_init = 1;
qlib_init_second_stage(pthreads);
bgp_peer_index_mutex_init();
@@ -411,6 +445,7 @@ init_second_stage(int pthreads)
qpn_add_hook_function(&routing_nexus->in_thread_init, routing_start) ;
qpn_add_hook_function(&bgp_nexus->in_thread_init, bgp_in_thread_init) ;
+ qpn_add_hook_function(&routing_nexus->in_thread_final, routing_finish) ;
qpn_add_hook_function(&bgp_nexus->in_thread_final, bgp_close_listeners) ;
qpn_add_hook_function(&routing_nexus->foreground, routing_foreground) ;
@@ -445,7 +480,6 @@ main (int argc, char **argv)
int dryrun = 0;
char *progname;
int tmp_port;
- int threaded = 0;
/* Set umask before anything for security */
umask (0027);
@@ -468,7 +502,7 @@ main (int argc, char **argv)
/* Command line argument treatment. */
while (1)
{
- opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vCt", longopts, 0);
+ opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vCtI2", longopts, 0);
if (opt == EOF)
break;
@@ -533,9 +567,15 @@ main (int argc, char **argv)
case 'h':
usage (progname, 0);
break;
- case 't':
- threaded = 1;
- break;
+ case 't':
+ config_threaded = 1;
+ break;
+ case 'I':
+ config_ignore_warnings = 1;
+ break ;
+ case '2':
+ config_as2_speaker = 1;
+ break ;
default:
usage (progname, 1);
break;
@@ -554,17 +594,25 @@ main (int argc, char **argv)
vty_init (master);
memory_init ();
- if (threaded)
- init_second_stage(1);
+ /* Read config file.
+ *
+ * NB: second state initialisation is done in the threaded_cmd, which must
+ * either be the first command in the file, or is executed by default
+ * before the first command in the file.
+ *
+ * NB: if fails to open the configuration file, fails to read anything, or
+ * it is completely empty (or effectively so), then may still need to do
+ * second stage initialisation.
+ */
+ done_2nd_stage_init = 0 ;
- /* Parse config file. */
- vty_read_config_first_cmd_special (config_file, config_default, after_first_cmd);
+ vty_read_config_first_cmd_special(config_file, config_default,
+ &threaded_cmd, config_ignore_warnings) ;
- /* if not threaded and empty config file then still need to
- * do second stage initialization
- */
- if (!done_2nd_state_init)
- init_second_stage(0);
+ if (!done_2nd_stage_init)
+ init_second_stage(config_threaded) ;
+
+ bm->as2_speaker = config_as2_speaker ;
/* Start execution only if not in dry-run mode */
if (dryrun)
@@ -575,18 +623,18 @@ main (int argc, char **argv)
*/
assert(!qpthreads_thread_created);
- /* Turn into daemon if daemon_mode is set. */
+ /* Turn into daemon if daemon_mode is set. */
if (daemon_mode && daemon (0, 0) < 0)
{
zlog_err("BGPd daemon failed: %s", safe_strerror(errno));
return (1);
}
- /* Process ID file creation. */
+ /* Process ID file creation. */
pid_output (pid_file);
- /* Make bgp vty socket. */
- vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH);
+ /* Ready to run VTY now. */
+ vty_start(vty_addr, vty_port, BGP_VTYSH_PATH);
/* Print banner. */
#ifdef QDEBUG
@@ -614,9 +662,12 @@ main (int argc, char **argv)
}
else
{
- qpn_exec(cli_nexus); /* only nexus - on main thread */
+ qpn_exec(cli_nexus); /* only nexus - on main thread */
}
+ /* Note that from this point forward is running in the main (CLI) thread
+ * and any other threads have been joined and their nexuses freed.
+ */
bgp_exit(0);
}
@@ -624,7 +675,7 @@ main (int argc, char **argv)
static void
bgp_in_thread_init(void)
{
- bgp_open_listeners(bm->port, bm->address);
+ bgp_open_listeners(bm->address, bm->port);
}
/* routing_nexus in-thread initialization -- for gdb ! */
@@ -637,6 +688,12 @@ routing_start(void)
routing_started = 1 ;
}
+static void
+routing_finish(void)
+{
+ routing_started = 0 ;
+}
+
/* legacy threads in routing engine */
static int
routing_foreground(void)
@@ -651,14 +708,17 @@ routing_background(void)
return thread_dispatch_background(master) ;
}
-/* SIGINT/TERM SIGHUP need to tell routing engine what to do */
-
+/*------------------------------------------------------------------------------
+ * SIGHUP: message sent to Routeing engine and the action it then takes.
+ *
+ * TODO: should SIGHUP be a priority message (!)
+ */
static void
sighup_enqueue(void)
{
mqueue_block mqb = mqb_init_new(NULL, sighup_action, NULL) ;
- mqueue_enqueue(routing_nexus->queue, mqb, 0) ;
+ mqueue_enqueue(routing_nexus->queue, mqb, 1) ;
}
/* dispatch a command from the message queue block */
@@ -667,19 +727,32 @@ sighup_action(mqueue_block mqb, mqb_flag_t flag)
{
if (flag == mqb_action)
{
+ zlog_info ("bgpd restarting!");
+
bgp_terminate (0, 0); /* send notifies */
bgp_reset ();
+
+ /* Reload config file. */
+ vty_read_config (config_file, config_default);
+
+ /* Create VTY's socket */
+ vty_restart(vty_addr, vty_port, BGP_VTYSH_PATH);
+
+ /* Try to return to normal operation. */
}
mqb_free(mqb);
}
+/*------------------------------------------------------------------------------
+ * SIGTERM: message sent to Routeing engine and the action it then takes.
+ */
static void
sigterm_enqueue(void)
{
mqueue_block mqb = mqb_init_new(NULL, sigterm_action, NULL) ;
- mqueue_enqueue(routing_nexus->queue, mqb, 0) ;
+ mqueue_enqueue(routing_nexus->queue, mqb, 1) ;
}
/* dispatch a command from the message queue block */