]> git.ipfire.org Git - thirdparty/bird.git/blob - conf/conf.c
Got rid of startup functions and filters_postconfig().
[thirdparty/bird.git] / conf / conf.c
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 #include <setjmp.h>
10 #include <stdarg.h>
11
12 #undef LOCAL_DEBUG
13
14 #include "nest/bird.h"
15 #include "nest/route.h"
16 #include "nest/protocol.h"
17 #include "nest/iface.h"
18 #include "lib/resource.h"
19 #include "lib/string.h"
20 #include "lib/event.h"
21 #include "lib/timer.h"
22 #include "conf/conf.h"
23 #include "filter/filter.h"
24
25 static jmp_buf conf_jmpbuf;
26
27 struct config *config, *new_config, *old_config, *future_config;
28 static event *config_event;
29 int shutting_down;
30 bird_clock_t boot_time;
31
32 struct config *
33 config_alloc(byte *name)
34 {
35 pool *p = rp_new(&root_pool, "Config");
36 linpool *l = lp_new(p, 4080);
37 struct config *c = lp_allocz(l, sizeof(struct config));
38
39 c->pool = p;
40 cfg_mem = c->mem = l;
41 c->file_name = cfg_strdup(name);
42 c->load_time = now;
43 if (!boot_time)
44 boot_time = now;
45 return c;
46 }
47
48 int
49 config_parse(struct config *c)
50 {
51 DBG("Parsing configuration file `%s'\n", c->file_name);
52 new_config = c;
53 cfg_mem = c->mem;
54 if (setjmp(conf_jmpbuf))
55 return 0;
56 cf_lex_init(0);
57 sysdep_preconfig(c);
58 protos_preconfig(c);
59 rt_preconfig(c);
60 cf_parse();
61 protos_postconfig(c);
62 #ifdef IPV6
63 if (!c->router_id)
64 cf_error("Router ID must be configured manually on IPv6 routers");
65 #endif
66 return 1;
67 }
68
69 int
70 cli_parse(struct config *c)
71 {
72 new_config = c;
73 c->sym_fallback = config->sym_hash;
74 cfg_mem = c->mem;
75 if (setjmp(conf_jmpbuf))
76 return 0;
77 cf_lex_init(1);
78 cf_parse();
79 return 1;
80 }
81
82 void
83 config_free(struct config *c)
84 {
85 rfree(c->pool);
86 }
87
88 void
89 config_add_obstacle(struct config *c)
90 {
91 DBG("+++ adding obstacle %d\n", c->obstacle_count);
92 c->obstacle_count++;
93 }
94
95 void
96 config_del_obstacle(struct config *c)
97 {
98 DBG("+++ deleting obstacle %d\n", c->obstacle_count);
99 c->obstacle_count--;
100 if (!c->obstacle_count)
101 {
102 ASSERT(config_event);
103 ev_schedule(config_event);
104 }
105 }
106
107 static int
108 global_commit(struct config *new, struct config *old)
109 {
110 if (!old)
111 return 0;
112 if (!new->router_id)
113 new->router_id = old->router_id;
114 if (new->router_id != old->router_id)
115 return 1;
116 return 0;
117 }
118
119 static int
120 config_do_commit(struct config *c)
121 {
122 int force_restart, nobs;
123
124 DBG("do_commit\n");
125 old_config = config;
126 config = new_config = c;
127 if (old_config)
128 old_config->obstacle_count++;
129 DBG("sysdep_commit\n");
130 force_restart = sysdep_commit(c, old_config);
131 DBG("global_commit\n");
132 force_restart |= global_commit(c, old_config);
133 DBG("rt_commit\n");
134 rt_commit(c, old_config);
135 DBG("protos_commit\n");
136 protos_commit(c, old_config, force_restart);
137 new_config = NULL; /* Just to be sure nobody uses that now */
138 if (old_config)
139 nobs = --old_config->obstacle_count;
140 else
141 nobs = 0;
142 DBG("do_commit finished with %d obstacles remaining\n", nobs);
143 return !nobs;
144 }
145
146 static void
147 config_done(void *unused)
148 {
149 struct config *c;
150
151 DBG("config_done\n");
152 for(;;)
153 {
154 if (config->shutdown)
155 sysdep_shutdown_done();
156 log(L_INFO "Reconfigured");
157 if (old_config)
158 {
159 config_free(old_config);
160 old_config = NULL;
161 }
162 if (!future_config)
163 break;
164 c = future_config;
165 future_config = NULL;
166 log(L_INFO "Switching to queued configuration...");
167 if (!config_do_commit(c))
168 break;
169 }
170 }
171
172 int
173 config_commit(struct config *c)
174 {
175 if (!config) /* First-time configuration */
176 {
177 config_do_commit(c);
178 return CONF_DONE;
179 }
180 if (old_config) /* Reconfiguration already in progress */
181 {
182 if (shutting_down)
183 {
184 log(L_INFO "New configuration discarded due to shutdown");
185 config_free(c);
186 return CONF_SHUTDOWN;
187 }
188 if (future_config)
189 {
190 log(L_INFO "Queueing new configuration, ignoring the one already queued");
191 config_free(future_config);
192 }
193 else
194 log(L_INFO "Queued new configuration");
195 future_config = c;
196 return CONF_QUEUED;
197 }
198 if (config_do_commit(c))
199 {
200 config_done(NULL);
201 return CONF_DONE;
202 }
203 if (!config_event)
204 {
205 config_event = ev_new(&root_pool);
206 config_event->hook = config_done;
207 }
208 return CONF_PROGRESS;
209 }
210
211 void
212 order_shutdown(void)
213 {
214 struct config *c;
215
216 if (shutting_down)
217 return;
218 log(L_INFO "Shutting down");
219 c = lp_alloc(config->mem, sizeof(struct config));
220 memcpy(c, config, sizeof(struct config));
221 init_list(&c->protos);
222 init_list(&c->tables);
223 c->shutdown = 1;
224 config_commit(c);
225 shutting_down = 1;
226 }
227
228 void
229 cf_error(char *msg, ...)
230 {
231 char buf[1024];
232 va_list args;
233
234 va_start(args, msg);
235 if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
236 strcpy(buf, "<bug: error message too long>");
237 new_config->err_msg = cfg_strdup(buf);
238 new_config->err_lino = conf_lino;
239 longjmp(conf_jmpbuf, 1);
240 }
241
242 char *
243 cfg_strdup(char *c)
244 {
245 int l = strlen(c) + 1;
246 char *z = cfg_allocu(l);
247 memcpy(z, c, l);
248 return z;
249 }