conf.c 14.9 KB
Newer Older
1 2 3
/*
 *	BIRD Internet Routing Daemon -- Configuration File Handling
 *
4
 *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
5 6 7 8
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

Martin Mareš's avatar
Martin Mareš committed
9 10 11
/**
 * DOC: Configuration manager
 *
12
 * Configuration of BIRD is complex, yet straightforward. There are three
Martin Mareš's avatar
Martin Mareš committed
13
 * modules taking care of the configuration: config manager (which takes care
Martin Mareš's avatar
Martin Mareš committed
14
 * of storage of the config information and controls switching between configs),
15
 * lexical analyzer and parser.
Martin Mareš's avatar
Martin Mareš committed
16 17 18 19 20
 *
 * The configuration manager stores each config as a &config structure
 * accompanied by a linear pool from which all information associated
 * with the config and pointed to by the &config structure is allocated.
 *
21
 * There can exist up to four different configurations at one time: an active
Martin Mareš's avatar
Martin Mareš committed
22
 * one (pointed to by @config), configuration we are just switching from
23 24 25 26 27 28 29 30
 * (@old_config), one queued for the next reconfiguration (@future_config; if
 * there is one and the user wants to reconfigure once again, we just free the
 * previous queued config and replace it with the new one) and finally a config
 * being parsed (@new_config). The stored @old_config is also used for undo
 * reconfiguration, which works in a similar way. Reconfiguration could also
 * have timeout (using @config_timer) and undo is automatically called if the
 * new configuration is not confirmed later. The new config (@new_config) and
 * associated linear pool (@cfg_mem) is non-NULL only during parsing.
Martin Mareš's avatar
Martin Mareš committed
31
 *
32 33 34 35
 * Loading of new configuration is very simple: just call config_alloc() to get
 * a new &config structure, then use config_parse() to parse a configuration
 * file and fill all fields of the structure and finally ask the config manager
 * to switch to the new config by calling config_commit().
Martin Mareš's avatar
Martin Mareš committed
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
Martin Mareš's avatar
Martin Mareš committed
39 40 41 42
 * same functions, only a special fake token is prepended before the command
 * text to make the parser recognize only the rules corresponding to CLI commands.
 */

43 44 45
#include <setjmp.h>
#include <stdarg.h>

46
#undef LOCAL_DEBUG
47

48
#include "nest/bird.h"
49
#include "nest/route.h"
50 51 52 53
#include "nest/protocol.h"
#include "nest/iface.h"
#include "lib/resource.h"
#include "lib/string.h"
54
#include "lib/event.h"
55
#include "lib/timer.h"
56 57 58 59 60
#include "conf/conf.h"
#include "filter/filter.h"

static jmp_buf conf_jmpbuf;

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
struct config *config, *new_config;

static struct config *old_config;	/* Old configuration */
static struct config *future_config;	/* New config held here if recon requested during recon */
static int old_cftype;			/* Type of transition old_config -> config (RECONFIG_SOFT/HARD) */
static int future_cftype;		/* Type of scheduled transition, may also be RECONFIG_UNDO */
/* Note that when future_cftype is RECONFIG_UNDO, then future_config is NULL,
   therefore proper check for future scheduled config checks future_cftype */

static event *config_event;		/* Event for finalizing reconfiguration */
static timer *config_timer;		/* Timer for scheduled configuration rollback */

/* These are public just for cmd_show_status(), should not be accessed elsewhere */
int shutting_down;			/* Shutdown requested, do not accept new config changes */
int configuring;			/* Reconfiguration is running */
int undo_available;			/* Undo was not requested from last reconfiguration */
/* Note that both shutting_down and undo_available are related to requests, not processing */
78

Martin Mareš's avatar
Martin Mareš committed
79 80 81 82 83 84 85 86
/**
 * config_alloc - allocate a new configuration
 * @name: name of the config
 *
 * This function creates new &config structure, attaches a resource
 * pool and a linear memory pool to it and makes it available for
 * further use. Returns a pointer to the structure.
 */
87
struct config *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
88
config_alloc(const byte *name)
89 90
{
  pool *p = rp_new(&root_pool, "Config");
91
  linpool *l = lp_new(p, 4080);
92 93
  struct config *c = lp_allocz(l, sizeof(struct config));

94 95 96 97 98
  /* Duplication of name string in local linear pool */
  uint nlen = strlen(name) + 1;
  char *ndup = lp_allocu(l, nlen);
  memcpy(ndup, name, nlen);

99
  c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
100
  c->pool = p;
101 102
  c->mem = l;
  c->file_name = ndup;
103
  c->load_time = now;
104 105
  c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600};
  c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0};
106
  c->gr_wait = DEFAULT_GR_WAIT;
107

108 109 110
  return c;
}

Martin Mareš's avatar
Martin Mareš committed
111 112 113 114 115 116 117
/**
 * config_parse - parse a configuration
 * @c: configuration
 *
 * config_parse() reads input by calling a hook function pointed to
 * by @cf_read_hook and parses it according to the configuration
 * grammar. It also calls all the preconfig and postconfig hooks
118
 * before, resp. after parsing.
Martin Mareš's avatar
Martin Mareš committed
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
Martin Mareš's avatar
Martin Mareš committed
122 123
 * the @err_msg field has been set to the error message.
 */
124 125 126
int
config_parse(struct config *c)
{
127
  int done = 0;
128
  DBG("Parsing configuration file `%s'\n", c->file_name);
129 130 131
  new_config = c;
  cfg_mem = c->mem;
  if (setjmp(conf_jmpbuf))
132 133
    goto cleanup;

134
  cf_lex_init(0, c);
135
  sysdep_preconfig(c);
136
  protos_preconfig(c);
137
  rt_preconfig(c);
138
  roa_preconfig(c);
139 140
  cf_parse();
  protos_postconfig(c);
141 142
  if (EMPTY_LIST(c->protos))
    cf_error("No protocol is specified in the config file");
143 144 145 146
#ifdef IPV6
  if (!c->router_id)
    cf_error("Router ID must be configured manually on IPv6 routers");
#endif
147 148 149 150 151 152
  done = 1;

cleanup:
  new_config = NULL;
  cfg_mem = NULL;
  return done;
153 154
}

Martin Mareš's avatar
Martin Mareš committed
155 156 157 158 159 160 161
/**
 * cli_parse - parse a CLI command
 * @c: temporary config structure
 *
 * cli_parse() is similar to config_parse(), but instead of a configuration,
 * it parses a CLI command. See the CLI module for more information.
 */
162 163 164
int
cli_parse(struct config *c)
{
165
  int done = 0;
166
  c->fallback = config;
167
  new_config = c;
168 169
  cfg_mem = c->mem;
  if (setjmp(conf_jmpbuf))
170 171
    goto cleanup;

172
  cf_lex_init(1, c);
173
  cf_parse();
174 175 176
  done = 1;

cleanup:
177
  c->fallback = NULL;
178 179 180
  new_config = NULL;
  cfg_mem = NULL;
  return done;
181 182
}

Martin Mareš's avatar
Martin Mareš committed
183 184 185 186 187 188 189
/**
 * config_free - free a configuration
 * @c: configuration to be freed
 *
 * This function takes a &config structure and frees all resources
 * associated with it.
 */
190 191 192
void
config_free(struct config *c)
{
193 194
  if (c)
    rfree(c->pool);
195 196 197
}

void
198 199 200 201 202 203 204 205
config_add_obstacle(struct config *c)
{
  DBG("+++ adding obstacle %d\n", c->obstacle_count);
  c->obstacle_count++;
}

void
config_del_obstacle(struct config *c)
206
{
207 208
  DBG("+++ deleting obstacle %d\n", c->obstacle_count);
  c->obstacle_count--;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
209
  if (!c->obstacle_count && (c != config))
210
    ev_schedule(config_event);
211 212 213
}

static int
214
global_commit(struct config *new, struct config *old)
215 216 217
{
  if (!old)
    return 0;
218

219 220 221
  if (!ipa_equal(old->listen_bgp_addr, new->listen_bgp_addr) ||
      (old->listen_bgp_port != new->listen_bgp_port) ||
      (old->listen_bgp_flags != new->listen_bgp_flags))
222 223
    log(L_WARN "Reconfiguration of BGP listening socket not implemented, please restart BIRD.");

224
  if (!new->router_id)
225 226 227 228 229 230 231 232 233 234 235 236 237
    {
      new->router_id = old->router_id;

      if (new->router_id_from)
	{
	  u32 id = if_choose_router_id(new->router_id_from, old->router_id);
	  if (!id)
	    log(L_WARN "Cannot determine router ID, using old one");
	  else
	    new->router_id = id;
	}
    }

238 239 240 241
  return 0;
}

static int
242
config_do_commit(struct config *c, int type)
243
{
244 245 246 247 248 249 250
  if (type == RECONFIG_UNDO)
    {
      c = old_config;
      type = old_cftype;
    }
  else
    config_free(old_config);
251 252

  old_config = config;
253 254 255 256 257 258 259
  old_cftype = type;
  config = c;

  configuring = 1;
  if (old_config && !config->shutdown)
    log(L_INFO "Reconfiguring");

260 261
  if (old_config)
    old_config->obstacle_count++;
262

263
  DBG("sysdep_commit\n");
264
  int force_restart = sysdep_commit(c, old_config);
265 266 267 268
  DBG("global_commit\n");
  force_restart |= global_commit(c, old_config);
  DBG("rt_commit\n");
  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 276 277 278
    obs = --old_config->obstacle_count;

  DBG("do_commit finished with %d obstacles remaining\n", obs);
  return !obs;
279 280
}

281
static void
282
config_done(void *unused UNUSED)
283
{
284 285 286 287 288 289
  if (config->shutdown)
    sysdep_shutdown_done();

  configuring = 0;
  if (old_config)
    log(L_INFO "Reconfigured");
290

291
  if (future_cftype)
292
    {
293 294 295
      int type = future_cftype;
      struct config *conf = future_config;
      future_cftype = RECONFIG_NONE;
296
      future_config = NULL;
297

298
      log(L_INFO "Reconfiguring to queued configuration");
299 300
      if (config_do_commit(conf, type))
	config_done(NULL);
301 302 303
    }
}

Martin Mareš's avatar
Martin Mareš committed
304 305 306
/**
 * config_commit - commit a configuration
 * @c: new configuration
307
 * @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
308
 * @timeout: timeout for undo (or 0 for no timeout)
Martin Mareš's avatar
Martin Mareš committed
309 310 311 312 313 314 315 316 317 318 319 320
 *
 * When a configuration is parsed and prepared for use, the
 * config_commit() function starts the process of reconfiguration.
 * It checks whether there is already a reconfiguration in progress
 * in which case it just queues the new config for later processing.
 * Else it notifies all modules about the new configuration by calling
 * their commit() functions which can either accept it immediately
 * or call config_add_obstacle() to report that they need some time
 * to complete the reconfiguration. After all such obstacles are removed
 * using config_del_obstacle(), the old configuration is freed and
 * everything runs according to the new one.
 *
321 322 323 324
 * When @timeout is nonzero, the undo timer is activated with given
 * timeout. The timer is deactivated when config_commit(),
 * config_confirm() or config_undo() is called.
 *
Martin Mareš's avatar
Martin Mareš committed
325 326 327 328 329 330
 * Result: %CONF_DONE if the configuration has been accepted immediately,
 * %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
 * if it's been queued due to another reconfiguration being in progress now
 * or %CONF_SHUTDOWN if BIRD is in shutdown mode and no new configurations
 * are accepted.
 */
331
int
332
config_commit(struct config *c, int type, int timeout)
333
{
334
  if (shutting_down)
335
    {
336 337
      config_free(c);
      return CONF_SHUTDOWN;
338
    }
339 340 341 342 343 344 345 346

  undo_available = 1;
  if (timeout > 0)
    tm_start(config_timer, timeout);
  else
    tm_stop(config_timer);

  if (configuring)
347
    {
348
      if (future_cftype)
349 350 351 352 353
	{
	  log(L_INFO "Queueing new configuration, ignoring the one already queued");
	  config_free(future_config);
	}
      else
354 355 356
	log(L_INFO "Queueing new configuration");

      future_cftype = type;
357 358 359
      future_config = c;
      return CONF_QUEUED;
    }
360

361
  if (config_do_commit(c, type))
362 363 364 365
    {
      config_done(NULL);
      return CONF_DONE;
    }
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
  return CONF_PROGRESS;
}

/**
 * config_confirm - confirm a commited configuration
 *
 * When the undo timer is activated by config_commit() with nonzero timeout,
 * this function can be used to deactivate it and therefore confirm
 * the current configuration.
 *
 * Result: %CONF_CONFIRM when the current configuration is confirmed,
 * %CONF_NONE when there is nothing to confirm (i.e. undo timer is not active).
 */
int
config_confirm(void)
{
  if (config_timer->expires == 0)
    return CONF_NOTHING;

  tm_stop(config_timer);

  return CONF_CONFIRM;
}

/**
 * config_undo - undo a configuration
 *
 * Function config_undo() can be used to change the current
 * configuration back to stored %old_config. If no reconfiguration is
 * running, this stored configuration is commited in the same way as a
 * new configuration in config_commit(). If there is already a
 * reconfiguration in progress and no next reconfiguration is
 * scheduled, then the undo is scheduled for later processing as
 * usual, but if another reconfiguration is already scheduled, then
 * such reconfiguration is removed instead (i.e. undo is applied on
 * the last commit that scheduled it).
 *
 * Result: %CONF_DONE if the configuration has been accepted immediately,
 * %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
 * if it's been queued due to another reconfiguration being in progress now,
 * %CONF_UNQUEUED if a scheduled reconfiguration is removed, %CONF_NOTHING
 * if there is no relevant configuration to undo (the previous config request
Ondřej Zajíček's avatar
Ondřej Zajíček committed
408
 * was config_undo() too)  or %CONF_SHUTDOWN if BIRD is in shutdown mode and
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
 * no new configuration changes  are accepted.
 */
int
config_undo(void)
{
  if (shutting_down)
    return CONF_SHUTDOWN;

  if (!undo_available || !old_config)
    return CONF_NOTHING;

  undo_available = 0;
  tm_stop(config_timer);

  if (configuring)
424
    {
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
      if (future_cftype)
	{
	  config_free(future_config);
	  future_config = NULL;

	  log(L_INFO "Removing queued configuration");
	  future_cftype = RECONFIG_NONE;
	  return CONF_UNQUEUED;
	}
      else
	{
	  log(L_INFO "Queueing undo configuration");
	  future_cftype = RECONFIG_UNDO;
	  return CONF_QUEUED;
	}
    }

  if (config_do_commit(NULL, RECONFIG_UNDO))
    {
      config_done(NULL);
      return CONF_DONE;
446 447
    }
  return CONF_PROGRESS;
448 449
}

450 451 452
extern void cmd_reconfig_undo_notify(void);

static void
453
config_timeout(struct timer *t UNUSED)
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
{
  log(L_INFO "Config timeout expired, starting undo");
  cmd_reconfig_undo_notify();

  int r = config_undo();
  if (r < 0)
    log(L_ERR "Undo request failed");
}

void
config_init(void)
{
  config_event = ev_new(&root_pool);
  config_event->hook = config_done;

  config_timer = tm_new(&root_pool);
  config_timer->hook = config_timeout;
}

Martin Mareš's avatar
Martin Mareš committed
473 474 475 476 477 478
/**
 * order_shutdown - order BIRD shutdown
 *
 * This function initiates shutdown of BIRD. It's accomplished by asking
 * for switching to an empty configuration.
 */
479 480 481 482 483 484 485
void
order_shutdown(void)
{
  struct config *c;

  if (shutting_down)
    return;
486

487 488 489 490 491 492
  log(L_INFO "Shutting down");
  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;
493 494

  config_commit(c, RECONFIG_HARD, 0);
495 496 497
  shutting_down = 1;
}

Martin Mareš's avatar
Martin Mareš committed
498 499 500 501 502 503 504 505
/**
 * cf_error - report a configuration error
 * @msg: printf-like format string
 *
 * cf_error() can be called during execution of config_parse(), that is
 * from the parser, a preconfig hook or a postconfig hook, to report an
 * error in the configuration.
 */
506 507 508 509 510 511 512 513 514
void
cf_error(char *msg, ...)
{
  char buf[1024];
  va_list args;

  va_start(args, msg);
  if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
    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_chno = ifs->chno - ifs->toklen + 1;
519
  new_config->err_file_name = ifs->file_name;
520
  cf_lex_unwind();
521 522 523
  longjmp(conf_jmpbuf, 1);
}

Martin Mareš's avatar
Martin Mareš committed
524 525 526 527 528 529 530 531 532
/**
 * cfg_strdup - copy a string to config memory
 * @c: string to copy
 *
 * cfg_strdup() creates a new copy of the string in the memory
 * pool associated with the configuration being currently parsed.
 * It's often used when a string literal occurs in the configuration
 * and we want to preserve it for further use.
 */
533
char *
Ondřej Zajíček's avatar
Ondřej Zajíček committed
534
cfg_strdup(const char *c)
535 536 537 538 539 540
{
  int l = strlen(c) + 1;
  char *z = cfg_allocu(l);
  memcpy(z, c, l);
  return z;
}
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555


void
cfg_copy_list(list *dest, list *src, unsigned node_size)
{
  node *dn, *sn;

  init_list(dest);
  WALK_LIST(sn, *src)
  {
    dn = cfg_alloc(node_size);
    memcpy(dn, sn, node_size);
    add_tail(dest, dn);
  }
}