diff options
Diffstat (limited to 'bgpd/bgp_main.c')
-rw-r--r-- | bgpd/bgp_main.c | 365 |
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 */ |