Statistics
| Branch: | Revision:

iof-bird-daemon / conf / conf.c @ 725270cb

History | View | Annotate | Download (9.29 KB)

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;
24
 * if it's non-%NULL and the user wants to reconfigure once again, we just
25
 * free the previous queued config and replace it with the new one) and
26
 * finally a config being parsed (@new_config).
27
 *
28
 * Loading of new configuration is very simple: just call config_alloc()
29
 * to get a new &config structure, then use config_parse() to parse a
30
 * configuration file and fill all fields of the structure
31
 * and finally ask the config manager to switch to the new
32
 * config by calling config_commit().
33
 *
34
 * CLI commands are parsed in a very similar way -- there is also a stripped-down
35
 * &config structure associated with them and they are lex-ed and parsed by the
36
 * same functions, only a special fake token is prepended before the command
37
 * text to make the parser recognize only the rules corresponding to CLI commands.
38
 */
39

    
40
#include <setjmp.h>
41
#include <stdarg.h>
42

    
43
#undef LOCAL_DEBUG
44

    
45
#include "nest/bird.h"
46
#include "nest/route.h"
47
#include "nest/protocol.h"
48
#include "nest/iface.h"
49
#include "lib/resource.h"
50
#include "lib/string.h"
51
#include "lib/event.h"
52
#include "lib/timer.h"
53
#include "conf/conf.h"
54
#include "filter/filter.h"
55

    
56
static jmp_buf conf_jmpbuf;
57

    
58
struct config *config, *new_config, *old_config, *future_config;
59
static event *config_event;
60
int shutting_down;
61
bird_clock_t boot_time;
62

    
63
/**
64
 * config_alloc - allocate a new configuration
65
 * @name: name of the config
66
 *
67
 * This function creates new &config structure, attaches a resource
68
 * pool and a linear memory pool to it and makes it available for
69
 * further use. Returns a pointer to the structure.
70
 */
71
struct config *
72
config_alloc(byte *name)
73
{
74
  pool *p = rp_new(&root_pool, "Config");
75
  linpool *l = lp_new(p, 4080);
76
  struct config *c = lp_allocz(l, sizeof(struct config));
77

    
78
  c->pool = p;
79
  cfg_mem = c->mem = l;
80
  c->file_name = cfg_strdup(name);
81
  c->load_time = now;
82
  if (!boot_time)
83
    boot_time = now;
84
  return c;
85
}
86

    
87
/**
88
 * config_parse - parse a configuration
89
 * @c: configuration
90
 *
91
 * config_parse() reads input by calling a hook function pointed to
92
 * by @cf_read_hook and parses it according to the configuration
93
 * grammar. It also calls all the preconfig and postconfig hooks
94
 * before, resp. after parsing.
95
 *
96
 * Result: 1 if the config has been parsed successfully, 0 if any
97
 * error has occurred (such as anybody calling cf_error()) and
98
 * the @err_msg field has been set to the error message.
99
 */
100
int
101
config_parse(struct config *c)
102
{
103
  DBG("Parsing configuration file `%s'\n", c->file_name);
104
  new_config = c;
105
  cfg_mem = c->mem;
106
  if (setjmp(conf_jmpbuf))
107
    return 0;
108
  cf_lex_init(0);
109
  sysdep_preconfig(c);
110
  protos_preconfig(c);
111
  rt_preconfig(c);
112
  cf_parse();
113
  protos_postconfig(c);
114
#ifdef IPV6
115
  if (!c->router_id)
116
    cf_error("Router ID must be configured manually on IPv6 routers");
117
#endif
118
  return 1;
119
}
120

    
121
/**
122
 * cli_parse - parse a CLI command
123
 * @c: temporary config structure
124
 *
125
 * cli_parse() is similar to config_parse(), but instead of a configuration,
126
 * it parses a CLI command. See the CLI module for more information.
127
 */
128
int
129
cli_parse(struct config *c)
130
{
131
  new_config = c;
132
  c->sym_fallback = config->sym_hash;
133
  cfg_mem = c->mem;
134
  if (setjmp(conf_jmpbuf))
135
    return 0;
136
  cf_lex_init(1);
137
  cf_parse();
138
  return 1;
139
}
140

    
141
/**
142
 * config_free - free a configuration
143
 * @c: configuration to be freed
144
 *
145
 * This function takes a &config structure and frees all resources
146
 * associated with it.
147
 */
148
void
149
config_free(struct config *c)
150
{
151
  rfree(c->pool);
152
}
153

    
154
void
155
config_add_obstacle(struct config *c)
156
{
157
  DBG("+++ adding obstacle %d\n", c->obstacle_count);
158
  c->obstacle_count++;
159
}
160

    
161
void
162
config_del_obstacle(struct config *c)
163
{
164
  DBG("+++ deleting obstacle %d\n", c->obstacle_count);
165
  c->obstacle_count--;
166
  if (!c->obstacle_count)
167
    {
168
      ASSERT(config_event);
169
      ev_schedule(config_event);
170
    }
171
}
172

    
173
static int
174
global_commit(struct config *new, struct config *old)
175
{
176
  if (!old)
177
    return 0;
178
  if (!new->router_id)
179
    new->router_id = old->router_id;
180
  if (new->router_id != old->router_id)
181
    return 1;
182
  return 0;
183
}
184

    
185
static int
186
config_do_commit(struct config *c)
187
{
188
  int force_restart, nobs;
189

    
190
  DBG("do_commit\n");
191
  old_config = config;
192
  config = new_config = c;
193
  if (old_config)
194
    old_config->obstacle_count++;
195
  DBG("sysdep_commit\n");
196
  force_restart = sysdep_commit(c, old_config);
197
  DBG("global_commit\n");
198
  force_restart |= global_commit(c, old_config);
199
  DBG("rt_commit\n");
200
  rt_commit(c, old_config);
201
  DBG("protos_commit\n");
202
  protos_commit(c, old_config, force_restart);
203
  new_config = NULL;                        /* Just to be sure nobody uses that now */
204
  if (old_config)
205
    nobs = --old_config->obstacle_count;
206
  else
207
    nobs = 0;
208
  DBG("do_commit finished with %d obstacles remaining\n", nobs);
209
  return !nobs;
210
}
211

    
212
static void
213
config_done(void *unused)
214
{
215
  struct config *c;
216

    
217
  DBG("config_done\n");
218
  for(;;)
219
    {
220
      if (config->shutdown)
221
        sysdep_shutdown_done();
222
      log(L_INFO "Reconfigured");
223
      if (old_config)
224
        {
225
          config_free(old_config);
226
          old_config = NULL;
227
        }
228
      if (!future_config)
229
        break;
230
      c = future_config;
231
      future_config = NULL;
232
      log(L_INFO "Switching to queued configuration...");
233
      if (!config_do_commit(c))
234
        break;
235
    }
236
}
237

    
238
/**
239
 * config_commit - commit a configuration
240
 * @c: new configuration
241
 *
242
 * When a configuration is parsed and prepared for use, the
243
 * config_commit() function starts the process of reconfiguration.
244
 * It checks whether there is already a reconfiguration in progress
245
 * in which case it just queues the new config for later processing.
246
 * Else it notifies all modules about the new configuration by calling
247
 * their commit() functions which can either accept it immediately
248
 * or call config_add_obstacle() to report that they need some time
249
 * to complete the reconfiguration. After all such obstacles are removed
250
 * using config_del_obstacle(), the old configuration is freed and
251
 * everything runs according to the new one.
252
 *
253
 * Result: %CONF_DONE if the configuration has been accepted immediately,
254
 * %CONF_PROGRESS if it will take some time to switch to it, %CONF_QUEUED
255
 * if it's been queued due to another reconfiguration being in progress now
256
 * or %CONF_SHUTDOWN if BIRD is in shutdown mode and no new configurations
257
 * are accepted.
258
 */
259
int
260
config_commit(struct config *c)
261
{
262
  if (!config)                                /* First-time configuration */
263
    {
264
      config_do_commit(c);
265
      return CONF_DONE;
266
    }
267
  if (old_config)                        /* Reconfiguration already in progress */
268
    {
269
      if (shutting_down)
270
        {
271
          log(L_INFO "New configuration discarded due to shutdown");
272
          config_free(c);
273
          return CONF_SHUTDOWN;
274
        }
275
      if (future_config)
276
        {
277
          log(L_INFO "Queueing new configuration, ignoring the one already queued");
278
          config_free(future_config);
279
        }
280
      else
281
        log(L_INFO "Queued new configuration");
282
      future_config = c;
283
      return CONF_QUEUED;
284
    }
285
  if (config_do_commit(c))
286
    {
287
      config_done(NULL);
288
      return CONF_DONE;
289
    }
290
  if (!config_event)
291
    {
292
      config_event = ev_new(&root_pool);
293
      config_event->hook = config_done;
294
    }
295
  return CONF_PROGRESS;
296
}
297

    
298
/**
299
 * order_shutdown - order BIRD shutdown
300
 *
301
 * This function initiates shutdown of BIRD. It's accomplished by asking
302
 * for switching to an empty configuration.
303
 */
304
void
305
order_shutdown(void)
306
{
307
  struct config *c;
308

    
309
  if (shutting_down)
310
    return;
311
  log(L_INFO "Shutting down");
312
  c = lp_alloc(config->mem, sizeof(struct config));
313
  memcpy(c, config, sizeof(struct config));
314
  init_list(&c->protos);
315
  init_list(&c->tables);
316
  c->shutdown = 1;
317
  config_commit(c);
318
  shutting_down = 1;
319
}
320

    
321
/**
322
 * cf_error - report a configuration error
323
 * @msg: printf-like format string
324
 *
325
 * cf_error() can be called during execution of config_parse(), that is
326
 * from the parser, a preconfig hook or a postconfig hook, to report an
327
 * error in the configuration.
328
 */
329
void
330
cf_error(char *msg, ...)
331
{
332
  char buf[1024];
333
  va_list args;
334

    
335
  va_start(args, msg);
336
  if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
337
    strcpy(buf, "<bug: error message too long>");
338
  new_config->err_msg = cfg_strdup(buf);
339
  new_config->err_lino = conf_lino;
340
  longjmp(conf_jmpbuf, 1);
341
}
342

    
343
/**
344
 * cfg_strdup - copy a string to config memory
345
 * @c: string to copy
346
 *
347
 * cfg_strdup() creates a new copy of the string in the memory
348
 * pool associated with the configuration being currently parsed.
349
 * It's often used when a string literal occurs in the configuration
350
 * and we want to preserve it for further use.
351
 */
352
char *
353
cfg_strdup(char *c)
354
{
355
  int l = strlen(c) + 1;
356
  char *z = cfg_allocu(l);
357
  memcpy(z, c, l);
358
  return z;
359
}