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