File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / conf / conf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Aug 22 12:33:54 2017 UTC (6 years, 10 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_3p0, v1_6_3, HEAD
bird 1.6.3

    1: /*
    2:  *	BIRD Internet Routing Daemon -- Configuration File Handling
    3:  *
    4:  *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
    5:  *
    6:  *	Can be freely distributed and used under the terms of the GNU GPL.
    7:  */
    8: 
    9: /**
   10:  * DOC: Configuration manager
   11:  *
   12:  * Configuration of BIRD is complex, yet straightforward. There are three
   13:  * modules taking care of the configuration: config manager (which takes care
   14:  * of storage of the config information and controls switching between configs),
   15:  * lexical analyzer and parser.
   16:  *
   17:  * The configuration manager stores each config as a &config structure
   18:  * accompanied by a linear pool from which all information associated
   19:  * with the config and pointed to by the &config structure is allocated.
   20:  *
   21:  * There can exist up to four different configurations at one time: an active
   22:  * one (pointed to by @config), configuration we are just switching from
   23:  * (@old_config), one queued for the next reconfiguration (@future_config; if
   24:  * there is one and the user wants to reconfigure once again, we just free the
   25:  * previous queued config and replace it with the new one) and finally a config
   26:  * being parsed (@new_config). The stored @old_config is also used for undo
   27:  * reconfiguration, which works in a similar way. Reconfiguration could also
   28:  * have timeout (using @config_timer) and undo is automatically called if the
   29:  * new configuration is not confirmed later. The new config (@new_config) and
   30:  * associated linear pool (@cfg_mem) is non-NULL only during parsing.
   31:  *
   32:  * Loading of new configuration is very simple: just call config_alloc() to get
   33:  * a new &config structure, then use config_parse() to parse a configuration
   34:  * file and fill all fields of the structure and finally ask the config manager
   35:  * to switch to the new config by calling config_commit().
   36:  *
   37:  * CLI commands are parsed in a very similar way -- there is also a stripped-down
   38:  * &config structure associated with them and they are lex-ed and parsed by the
   39:  * same functions, only a special fake token is prepended before the command
   40:  * text to make the parser recognize only the rules corresponding to CLI commands.
   41:  */
   42: 
   43: #include <setjmp.h>
   44: #include <stdarg.h>
   45: 
   46: #undef LOCAL_DEBUG
   47: 
   48: #include "nest/bird.h"
   49: #include "nest/route.h"
   50: #include "nest/protocol.h"
   51: #include "nest/iface.h"
   52: #include "lib/resource.h"
   53: #include "lib/string.h"
   54: #include "lib/event.h"
   55: #include "lib/timer.h"
   56: #include "conf/conf.h"
   57: #include "filter/filter.h"
   58: 
   59: static jmp_buf conf_jmpbuf;
   60: 
   61: struct config *config, *new_config;
   62: 
   63: static struct config *old_config;	/* Old configuration */
   64: static struct config *future_config;	/* New config held here if recon requested during recon */
   65: static int old_cftype;			/* Type of transition old_config -> config (RECONFIG_SOFT/HARD) */
   66: static int future_cftype;		/* Type of scheduled transition, may also be RECONFIG_UNDO */
   67: /* Note that when future_cftype is RECONFIG_UNDO, then future_config is NULL,
   68:    therefore proper check for future scheduled config checks future_cftype */
   69: 
   70: static event *config_event;		/* Event for finalizing reconfiguration */
   71: static timer *config_timer;		/* Timer for scheduled configuration rollback */
   72: 
   73: /* These are public just for cmd_show_status(), should not be accessed elsewhere */
   74: int shutting_down;			/* Shutdown requested, do not accept new config changes */
   75: int configuring;			/* Reconfiguration is running */
   76: int undo_available;			/* Undo was not requested from last reconfiguration */
   77: /* Note that both shutting_down and undo_available are related to requests, not processing */
   78: 
   79: /**
   80:  * config_alloc - allocate a new configuration
   81:  * @name: name of the config
   82:  *
   83:  * This function creates new &config structure, attaches a resource
   84:  * pool and a linear memory pool to it and makes it available for
   85:  * further use. Returns a pointer to the structure.
   86:  */
   87: struct config *
   88: config_alloc(const byte *name)
   89: {
   90:   pool *p = rp_new(&root_pool, "Config");
   91:   linpool *l = lp_new(p, 4080);
   92:   struct config *c = lp_allocz(l, sizeof(struct config));
   93: 
   94:   /* Duplication of name string in local linear pool */
   95:   uint nlen = strlen(name) + 1;
   96:   char *ndup = lp_allocu(l, nlen);
   97:   memcpy(ndup, name, nlen);
   98: 
   99:   c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
  100:   c->pool = p;
  101:   c->mem = l;
  102:   c->file_name = ndup;
  103:   c->load_time = now;
  104:   c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600};
  105:   c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0};
  106:   c->gr_wait = DEFAULT_GR_WAIT;
  107: 
  108:   return c;
  109: }
  110: 
  111: /**
  112:  * config_parse - parse a configuration
  113:  * @c: configuration
  114:  *
  115:  * config_parse() reads input by calling a hook function pointed to
  116:  * by @cf_read_hook and parses it according to the configuration
  117:  * grammar. It also calls all the preconfig and postconfig hooks
  118:  * before, resp. after parsing.
  119:  *
  120:  * Result: 1 if the config has been parsed successfully, 0 if any
  121:  * error has occurred (such as anybody calling cf_error()) and
  122:  * the @err_msg field has been set to the error message.
  123:  */
  124: int
  125: config_parse(struct config *c)
  126: {
  127:   int done = 0;
  128:   DBG("Parsing configuration file `%s'\n", c->file_name);
  129:   new_config = c;
  130:   cfg_mem = c->mem;
  131:   if (setjmp(conf_jmpbuf))
  132:     goto cleanup;
  133: 
  134:   cf_lex_init(0, c);
  135:   sysdep_preconfig(c);
  136:   protos_preconfig(c);
  137:   rt_preconfig(c);
  138:   roa_preconfig(c);
  139:   cf_parse();
  140:   protos_postconfig(c);
  141:   if (EMPTY_LIST(c->protos))
  142:     cf_error("No protocol is specified in the config file");
  143: #ifdef IPV6
  144:   if (!c->router_id)
  145:     cf_error("Router ID must be configured manually on IPv6 routers");
  146: #endif
  147:   done = 1;
  148: 
  149: cleanup:
  150:   new_config = NULL;
  151:   cfg_mem = NULL;
  152:   return done;
  153: }
  154: 
  155: /**
  156:  * cli_parse - parse a CLI command
  157:  * @c: temporary config structure
  158:  *
  159:  * cli_parse() is similar to config_parse(), but instead of a configuration,
  160:  * it parses a CLI command. See the CLI module for more information.
  161:  */
  162: int
  163: cli_parse(struct config *c)
  164: {
  165:   int done = 0;
  166:   c->sym_fallback = config->sym_hash;
  167:   new_config = c;
  168:   cfg_mem = c->mem;
  169:   if (setjmp(conf_jmpbuf))
  170:     goto cleanup;
  171: 
  172:   cf_lex_init(1, c);
  173:   cf_parse();
  174:   done = 1;
  175: 
  176: cleanup:
  177:   c->sym_fallback = NULL;
  178:   new_config = NULL;
  179:   cfg_mem = NULL;
  180:   return done;
  181: }
  182: 
  183: /**
  184:  * config_free - free a configuration
  185:  * @c: configuration to be freed
  186:  *
  187:  * This function takes a &config structure and frees all resources
  188:  * associated with it.
  189:  */
  190: void
  191: config_free(struct config *c)
  192: {
  193:   if (c)
  194:     rfree(c->pool);
  195: }
  196: 
  197: void
  198: config_add_obstacle(struct config *c)
  199: {
  200:   DBG("+++ adding obstacle %d\n", c->obstacle_count);
  201:   c->obstacle_count++;
  202: }
  203: 
  204: void
  205: config_del_obstacle(struct config *c)
  206: {
  207:   DBG("+++ deleting obstacle %d\n", c->obstacle_count);
  208:   c->obstacle_count--;
  209:   if (!c->obstacle_count)
  210:     ev_schedule(config_event);
  211: }
  212: 
  213: static int
  214: global_commit(struct config *new, struct config *old)
  215: {
  216:   if (!old)
  217:     return 0;
  218: 
  219:   if (!ipa_equal(old->listen_bgp_addr, new->listen_bgp_addr) ||
  220:       (old->listen_bgp_port != new->listen_bgp_port) ||
  221:       (old->listen_bgp_flags != new->listen_bgp_flags))
  222:     log(L_WARN "Reconfiguration of BGP listening socket not implemented, please restart BIRD.");
  223: 
  224:   if (!new->router_id)
  225:     {
  226:       new->router_id = old->router_id;
  227: 
  228:       if (new->router_id_from)
  229: 	{
  230: 	  u32 id = if_choose_router_id(new->router_id_from, old->router_id);
  231: 	  if (!id)
  232: 	    log(L_WARN "Cannot determine router ID, using old one");
  233: 	  else
  234: 	    new->router_id = id;
  235: 	}
  236:     }
  237: 
  238:   return 0;
  239: }
  240: 
  241: static int
  242: config_do_commit(struct config *c, int type)
  243: {
  244:   if (type == RECONFIG_UNDO)
  245:     {
  246:       c = old_config;
  247:       type = old_cftype;
  248:     }
  249:   else
  250:     config_free(old_config);
  251: 
  252:   old_config = config;
  253:   old_cftype = type;
  254:   config = c;
  255: 
  256:   configuring = 1;
  257:   if (old_config && !config->shutdown)
  258:     log(L_INFO "Reconfiguring");
  259: 
  260:   if (old_config)
  261:     old_config->obstacle_count++;
  262: 
  263:   DBG("sysdep_commit\n");
  264:   int force_restart = sysdep_commit(c, old_config);
  265:   DBG("global_commit\n");
  266:   force_restart |= global_commit(c, old_config);
  267:   DBG("rt_commit\n");
  268:   rt_commit(c, old_config);
  269:   roa_commit(c, old_config);
  270:   DBG("protos_commit\n");
  271:   protos_commit(c, old_config, force_restart, type);
  272: 
  273:   int obs = 0;
  274:   if (old_config)
  275:     obs = --old_config->obstacle_count;
  276: 
  277:   DBG("do_commit finished with %d obstacles remaining\n", obs);
  278:   return !obs;
  279: }
  280: 
  281: static void
  282: config_done(void *unused UNUSED)
  283: {
  284:   if (config->shutdown)
  285:     sysdep_shutdown_done();
  286: 
  287:   configuring = 0;
  288:   if (old_config)
  289:     log(L_INFO "Reconfigured");
  290: 
  291:   if (future_cftype)
  292:     {
  293:       int type = future_cftype;
  294:       struct config *conf = future_config;
  295:       future_cftype = RECONFIG_NONE;
  296:       future_config = NULL;
  297: 
  298:       log(L_INFO "Reconfiguring to queued configuration");
  299:       if (config_do_commit(conf, type))
  300: 	config_done(NULL);
  301:     }
  302: }
  303: 
  304: /**
  305:  * config_commit - commit a configuration
  306:  * @c: new configuration
  307:  * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
  308:  * @timeout: timeout for undo (or 0 for no timeout)
  309:  *
  310:  * When a configuration is parsed and prepared for use, the
  311:  * config_commit() function starts the process of reconfiguration.
  312:  * It checks whether there is already a reconfiguration in progress
  313:  * in which case it just queues the new config for later processing.
  314:  * Else it notifies all modules about the new configuration by calling
  315:  * their commit() functions which can either accept it immediately
  316:  * or call config_add_obstacle() to report that they need some time
  317:  * to complete the reconfiguration. After all such obstacles are removed
  318:  * using config_del_obstacle(), the old configuration is freed and
  319:  * everything runs according to the new one.
  320:  *
  321:  * When @timeout is nonzero, the undo timer is activated with given
  322:  * timeout. The timer is deactivated when config_commit(),
  323:  * config_confirm() or config_undo() is called.
  324:  *
  325:  * Result: %CONF_DONE if the configuration has been accepted immediately,
  326:  * %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
  327:  * if it's been queued due to another reconfiguration being in progress now
  328:  * or %CONF_SHUTDOWN if BIRD is in shutdown mode and no new configurations
  329:  * are accepted.
  330:  */
  331: int
  332: config_commit(struct config *c, int type, int timeout)
  333: {
  334:   if (shutting_down)
  335:     {
  336:       config_free(c);
  337:       return CONF_SHUTDOWN;
  338:     }
  339: 
  340:   undo_available = 1;
  341:   if (timeout > 0)
  342:     tm_start(config_timer, timeout);
  343:   else
  344:     tm_stop(config_timer);
  345: 
  346:   if (configuring)
  347:     {
  348:       if (future_cftype)
  349: 	{
  350: 	  log(L_INFO "Queueing new configuration, ignoring the one already queued");
  351: 	  config_free(future_config);
  352: 	}
  353:       else
  354: 	log(L_INFO "Queueing new configuration");
  355: 
  356:       future_cftype = type;
  357:       future_config = c;
  358:       return CONF_QUEUED;
  359:     }
  360: 
  361:   if (config_do_commit(c, type))
  362:     {
  363:       config_done(NULL);
  364:       return CONF_DONE;
  365:     }
  366:   return CONF_PROGRESS;
  367: }
  368: 
  369: /**
  370:  * config_confirm - confirm a commited configuration
  371:  *
  372:  * When the undo timer is activated by config_commit() with nonzero timeout,
  373:  * this function can be used to deactivate it and therefore confirm
  374:  * the current configuration.
  375:  *
  376:  * Result: %CONF_CONFIRM when the current configuration is confirmed,
  377:  * %CONF_NONE when there is nothing to confirm (i.e. undo timer is not active).
  378:  */
  379: int
  380: config_confirm(void)
  381: {
  382:   if (config_timer->expires == 0)
  383:     return CONF_NOTHING;
  384: 
  385:   tm_stop(config_timer);
  386: 
  387:   return CONF_CONFIRM;
  388: }
  389: 
  390: /**
  391:  * config_undo - undo a configuration
  392:  *
  393:  * Function config_undo() can be used to change the current
  394:  * configuration back to stored %old_config. If no reconfiguration is
  395:  * running, this stored configuration is commited in the same way as a
  396:  * new configuration in config_commit(). If there is already a
  397:  * reconfiguration in progress and no next reconfiguration is
  398:  * scheduled, then the undo is scheduled for later processing as
  399:  * usual, but if another reconfiguration is already scheduled, then
  400:  * such reconfiguration is removed instead (i.e. undo is applied on
  401:  * the last commit that scheduled it).
  402:  *
  403:  * Result: %CONF_DONE if the configuration has been accepted immediately,
  404:  * %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
  405:  * if it's been queued due to another reconfiguration being in progress now,
  406:  * %CONF_UNQUEUED if a scheduled reconfiguration is removed, %CONF_NOTHING
  407:  * if there is no relevant configuration to undo (the previous config request
  408:  * was config_undo() too)  or %CONF_SHUTDOWN if BIRD is in shutdown mode and
  409:  * no new configuration changes  are accepted.
  410:  */
  411: int
  412: config_undo(void)
  413: {
  414:   if (shutting_down)
  415:     return CONF_SHUTDOWN;
  416: 
  417:   if (!undo_available || !old_config)
  418:     return CONF_NOTHING;
  419: 
  420:   undo_available = 0;
  421:   tm_stop(config_timer);
  422: 
  423:   if (configuring)
  424:     {
  425:       if (future_cftype)
  426: 	{
  427: 	  config_free(future_config);
  428: 	  future_config = NULL;
  429: 
  430: 	  log(L_INFO "Removing queued configuration");
  431: 	  future_cftype = RECONFIG_NONE;
  432: 	  return CONF_UNQUEUED;
  433: 	}
  434:       else
  435: 	{
  436: 	  log(L_INFO "Queueing undo configuration");
  437: 	  future_cftype = RECONFIG_UNDO;
  438: 	  return CONF_QUEUED;
  439: 	}
  440:     }
  441: 
  442:   if (config_do_commit(NULL, RECONFIG_UNDO))
  443:     {
  444:       config_done(NULL);
  445:       return CONF_DONE;
  446:     }
  447:   return CONF_PROGRESS;
  448: }
  449: 
  450: extern void cmd_reconfig_undo_notify(void);
  451: 
  452: static void
  453: config_timeout(struct timer *t UNUSED)
  454: {
  455:   log(L_INFO "Config timeout expired, starting undo");
  456:   cmd_reconfig_undo_notify();
  457: 
  458:   int r = config_undo();
  459:   if (r < 0)
  460:     log(L_ERR "Undo request failed");
  461: }
  462: 
  463: void
  464: config_init(void)
  465: {
  466:   config_event = ev_new(&root_pool);
  467:   config_event->hook = config_done;
  468: 
  469:   config_timer = tm_new(&root_pool);
  470:   config_timer->hook = config_timeout;
  471: }
  472: 
  473: /**
  474:  * order_shutdown - order BIRD shutdown
  475:  *
  476:  * This function initiates shutdown of BIRD. It's accomplished by asking
  477:  * for switching to an empty configuration.
  478:  */
  479: void
  480: order_shutdown(void)
  481: {
  482:   struct config *c;
  483: 
  484:   if (shutting_down)
  485:     return;
  486: 
  487:   log(L_INFO "Shutting down");
  488:   c = lp_alloc(config->mem, sizeof(struct config));
  489:   memcpy(c, config, sizeof(struct config));
  490:   init_list(&c->protos);
  491:   init_list(&c->tables);
  492:   c->shutdown = 1;
  493: 
  494:   config_commit(c, RECONFIG_HARD, 0);
  495:   shutting_down = 1;
  496: }
  497: 
  498: /**
  499:  * cf_error - report a configuration error
  500:  * @msg: printf-like format string
  501:  *
  502:  * cf_error() can be called during execution of config_parse(), that is
  503:  * from the parser, a preconfig hook or a postconfig hook, to report an
  504:  * error in the configuration.
  505:  */
  506: void
  507: cf_error(char *msg, ...)
  508: {
  509:   char buf[1024];
  510:   va_list args;
  511: 
  512:   va_start(args, msg);
  513:   if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
  514:     strcpy(buf, "<bug: error message too long>");
  515:   va_end(args);
  516:   new_config->err_msg = cfg_strdup(buf);
  517:   new_config->err_lino = ifs->lino;
  518:   new_config->err_file_name = ifs->file_name;
  519:   cf_lex_unwind();
  520:   longjmp(conf_jmpbuf, 1);
  521: }
  522: 
  523: /**
  524:  * cfg_strdup - copy a string to config memory
  525:  * @c: string to copy
  526:  *
  527:  * cfg_strdup() creates a new copy of the string in the memory
  528:  * pool associated with the configuration being currently parsed.
  529:  * It's often used when a string literal occurs in the configuration
  530:  * and we want to preserve it for further use.
  531:  */
  532: char *
  533: cfg_strdup(const char *c)
  534: {
  535:   int l = strlen(c) + 1;
  536:   char *z = cfg_allocu(l);
  537:   memcpy(z, c, l);
  538:   return z;
  539: }
  540: 
  541: 
  542: void
  543: cfg_copy_list(list *dest, list *src, unsigned node_size)
  544: {
  545:   node *dn, *sn;
  546: 
  547:   init_list(dest);
  548:   WALK_LIST(sn, *src)
  549:   {
  550:     dn = cfg_alloc(node_size);
  551:     memcpy(dn, sn, node_size);
  552:     add_tail(dest, dn);
  553:   }
  554: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>