Annotation of embedaddon/bird/conf/conf.c, revision 1.1.1.2

1.1       misho       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;
1.1.1.2 ! misho     166:   c->fallback = config;
1.1       misho     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:
1.1.1.2 ! misho     177:   c->fallback = NULL;
1.1       misho     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--;
1.1.1.2 ! misho     209:   if (!c->obstacle_count && (c != config))
1.1       misho     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;
1.1.1.2 ! misho     518:   new_config->err_chno = ifs->chno - ifs->toklen + 1;
1.1       misho     519:   new_config->err_file_name = ifs->file_name;
                    520:   cf_lex_unwind();
                    521:   longjmp(conf_jmpbuf, 1);
                    522: }
                    523: 
                    524: /**
                    525:  * cfg_strdup - copy a string to config memory
                    526:  * @c: string to copy
                    527:  *
                    528:  * cfg_strdup() creates a new copy of the string in the memory
                    529:  * pool associated with the configuration being currently parsed.
                    530:  * It's often used when a string literal occurs in the configuration
                    531:  * and we want to preserve it for further use.
                    532:  */
                    533: char *
                    534: cfg_strdup(const char *c)
                    535: {
                    536:   int l = strlen(c) + 1;
                    537:   char *z = cfg_allocu(l);
                    538:   memcpy(z, c, l);
                    539:   return z;
                    540: }
                    541: 
                    542: 
                    543: void
                    544: cfg_copy_list(list *dest, list *src, unsigned node_size)
                    545: {
                    546:   node *dn, *sn;
                    547: 
                    548:   init_list(dest);
                    549:   WALK_LIST(sn, *src)
                    550:   {
                    551:     dn = cfg_alloc(node_size);
                    552:     memcpy(dn, sn, node_size);
                    553:     add_tail(dest, dn);
                    554:   }
                    555: }

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