]>
Commit | Line | Data |
---|---|---|
ca10883e DS |
1 | /* |
2 | Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek | |
3 | ||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 | of this software and associated documentation files (the "Software"), to deal | |
6 | in the Software without restriction, including without limitation the rights | |
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | copies of the Software, and to permit persons to whom the Software is | |
9 | furnished to do so, subject to the following conditions: | |
10 | ||
11 | The above copyright notice and this permission notice shall be included in | |
12 | all copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 | THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | /* include zebra library */ | |
24 | #include <zebra.h> | |
25 | #include "getopt.h" | |
26 | #include "if.h" | |
27 | #include "log.h" | |
28 | #include "thread.h" | |
29 | #include "privs.h" | |
30 | #include "sigevent.h" | |
31 | #include "version.h" | |
32 | #include "command.h" | |
33 | #include "vty.h" | |
34 | #include "memory.h" | |
35 | #include "libfrr.h" | |
f135ba52 | 36 | #include "lib_errors.h" |
ca10883e DS |
37 | |
38 | #include "babel_main.h" | |
39 | #include "babeld.h" | |
40 | #include "util.h" | |
41 | #include "kernel.h" | |
42 | #include "babel_interface.h" | |
43 | #include "neighbour.h" | |
44 | #include "route.h" | |
45 | #include "xroute.h" | |
46 | #include "message.h" | |
47 | #include "resend.h" | |
48 | #include "babel_zebra.h" | |
f135ba52 | 49 | #include "babel_errors.h" |
ca10883e | 50 | |
ca10883e DS |
51 | static void babel_fail(void); |
52 | static void babel_init_random(void); | |
53 | static void babel_replace_by_null(int fd); | |
54 | static void babel_exit_properly(void); | |
55 | static void babel_save_state_file(void); | |
56 | ||
57 | ||
58 | struct thread_master *master; /* quagga's threads handler */ | |
59 | struct timeval babel_now; /* current time */ | |
60 | ||
61 | unsigned char myid[8]; /* unique id (mac address of an interface) */ | |
62 | int debug = 0; | |
63 | ||
64 | int resend_delay = -1; | |
65 | ||
66 | const unsigned char zeroes[16] = {0}; | |
67 | const unsigned char ones[16] = | |
68 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
69 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
70 | ||
43e587c1 | 71 | static char state_file[1024]; |
ca10883e DS |
72 | |
73 | unsigned char protocol_group[16]; /* babel's link-local multicast address */ | |
74 | int protocol_port; /* babel's port */ | |
75 | int protocol_socket = -1; /* socket: communicate with others babeld */ | |
76 | ||
77 | static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; | |
ca10883e DS |
78 | static char *babel_vty_addr = NULL; |
79 | static int babel_vty_port = BABEL_VTY_PORT; | |
80 | ||
81 | /* babeld privileges */ | |
82 | static zebra_capabilities_t _caps_p [] = | |
83 | { | |
84 | ZCAP_NET_RAW, | |
85 | ZCAP_BIND | |
86 | }; | |
900b8c58 | 87 | |
346526cc | 88 | struct zebra_privs_t babeld_privs = |
ca10883e | 89 | { |
dd329373 DS |
90 | #if defined(FRR_USER) |
91 | .user = FRR_USER, | |
ca10883e | 92 | #endif |
dd329373 DS |
93 | #if defined FRR_GROUP |
94 | .group = FRR_GROUP, | |
ca10883e DS |
95 | #endif |
96 | #ifdef VTY_GROUP | |
97 | .vty_group = VTY_GROUP, | |
98 | #endif | |
99 | .caps_p = _caps_p, | |
900b8c58 | 100 | .cap_num_p = array_size(_caps_p), |
ca10883e DS |
101 | .cap_num_i = 0 |
102 | }; | |
103 | ||
104 | static void | |
105 | babel_sigexit(void) | |
106 | { | |
107 | zlog_notice("Terminating on signal"); | |
108 | ||
109 | babel_exit_properly(); | |
110 | } | |
111 | ||
112 | static void | |
113 | babel_sigusr1 (void) | |
114 | { | |
115 | zlog_rotate (); | |
116 | } | |
117 | ||
118 | static struct quagga_signal_t babel_signals[] = | |
119 | { | |
120 | { | |
121 | .signal = SIGUSR1, | |
122 | .handler = &babel_sigusr1, | |
123 | }, | |
124 | { | |
125 | .signal = SIGINT, | |
126 | .handler = &babel_sigexit, | |
127 | }, | |
128 | { | |
129 | .signal = SIGTERM, | |
130 | .handler = &babel_sigexit, | |
131 | }, | |
132 | }; | |
133 | ||
134 | struct option longopts[] = | |
135 | { | |
136 | { 0 } | |
137 | }; | |
138 | ||
8fcdd0d6 RW |
139 | static const struct frr_yang_module_info *babeld_yang_modules[] = |
140 | { | |
a4bed468 | 141 | &frr_interface_info, |
8fcdd0d6 RW |
142 | }; |
143 | ||
ca10883e DS |
144 | FRR_DAEMON_INFO(babeld, BABELD, |
145 | .vty_port = BABEL_VTY_PORT, | |
146 | .proghelp = "Implementation of the BABEL routing protocol.", | |
147 | ||
148 | .signals = babel_signals, | |
149 | .n_signals = array_size(babel_signals), | |
150 | ||
151 | .privs = &babeld_privs, | |
8fcdd0d6 RW |
152 | |
153 | .yang_modules = babeld_yang_modules, | |
154 | .n_yang_modules = array_size(babeld_yang_modules), | |
ca10883e DS |
155 | ) |
156 | ||
157 | int | |
158 | main(int argc, char **argv) | |
159 | { | |
900b8c58 | 160 | int rc; |
ca10883e | 161 | |
900b8c58 DS |
162 | frr_preinit (&babeld_di, argc, argv); |
163 | frr_opt_add ("", longopts, ""); | |
f135ba52 | 164 | |
ca10883e DS |
165 | babel_init_random(); |
166 | ||
167 | /* set the Babel's default link-local multicast address and Babel's port */ | |
168 | parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); | |
169 | protocol_port = 6696; | |
170 | ||
171 | /* get options */ | |
172 | while(1) { | |
173 | int opt; | |
174 | ||
175 | opt = frr_getopt (argc, argv, NULL); | |
176 | ||
177 | if (opt == EOF) | |
178 | break; | |
179 | ||
180 | switch (opt) | |
181 | { | |
182 | case 0: | |
183 | break; | |
184 | default: | |
185 | frr_help_exit (1); | |
186 | break; | |
187 | } | |
188 | } | |
189 | ||
3c649c71 DS |
190 | snprintf(state_file, sizeof(state_file), "%s/%s", |
191 | frr_vtydir, "babel-state"); | |
192 | ||
ca10883e | 193 | /* create the threads handler */ |
900b8c58 | 194 | master = frr_init (); |
ca10883e DS |
195 | |
196 | /* Library inits. */ | |
f135ba52 | 197 | babel_error_init(); |
ca10883e DS |
198 | |
199 | resend_delay = BABEL_DEFAULT_RESEND_DELAY; | |
200 | change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE); | |
201 | ||
202 | babel_replace_by_null(STDIN_FILENO); | |
203 | ||
204 | /* init some quagga's dependencies, and babeld's commands */ | |
205 | babeld_quagga_init(); | |
206 | /* init zebra client's structure and it's commands */ | |
207 | /* this replace kernel_setup && kernel_setup_socket */ | |
208 | babelz_zebra_init (); | |
209 | ||
ca10883e DS |
210 | /* init buffer */ |
211 | rc = resize_receive_buffer(1500); | |
212 | if(rc < 0) | |
213 | babel_fail(); | |
214 | ||
215 | schedule_neighbours_check(5000, 1); | |
216 | ||
900b8c58 DS |
217 | frr_config_fork(); |
218 | frr_run(master); | |
219 | ||
220 | return 0; | |
ca10883e DS |
221 | } |
222 | ||
223 | static void | |
224 | babel_fail(void) | |
225 | { | |
226 | exit(1); | |
227 | } | |
228 | ||
229 | /* initialize random value, and set 'babel_now' by the way. */ | |
230 | static void | |
231 | babel_init_random(void) | |
232 | { | |
233 | gettime(&babel_now); | |
234 | int rc; | |
235 | unsigned int seed; | |
236 | ||
237 | rc = read_random_bytes(&seed, sizeof(seed)); | |
238 | if(rc < 0) { | |
450971aa | 239 | flog_err_sys(EC_LIB_SYSTEM_CALL, "read(random): %s", |
f135ba52 | 240 | safe_strerror(errno)); |
ca10883e DS |
241 | seed = 42; |
242 | } | |
243 | ||
244 | seed ^= (babel_now.tv_sec ^ babel_now.tv_usec); | |
245 | srandom(seed); | |
246 | } | |
247 | ||
248 | /* | |
249 | close fd, and replace it by "/dev/null" | |
250 | exit if error | |
251 | */ | |
252 | static void | |
253 | babel_replace_by_null(int fd) | |
254 | { | |
255 | int fd_null; | |
256 | int rc; | |
257 | ||
258 | fd_null = open("/dev/null", O_RDONLY); | |
259 | if(fd_null < 0) { | |
450971aa | 260 | flog_err_sys(EC_LIB_SYSTEM_CALL, "open(null): %s", safe_strerror(errno)); |
ca10883e DS |
261 | exit(1); |
262 | } | |
263 | ||
264 | rc = dup2(fd_null, fd); | |
265 | if(rc < 0) { | |
450971aa | 266 | flog_err_sys(EC_LIB_SYSTEM_CALL, "dup2(null, 0): %s", |
f135ba52 | 267 | safe_strerror(errno)); |
ca10883e DS |
268 | exit(1); |
269 | } | |
270 | ||
271 | close(fd_null); | |
272 | } | |
273 | ||
274 | /* | |
275 | Load the state file: check last babeld's running state, usefull in case of | |
276 | "/etc/init.d/babeld restart" | |
277 | */ | |
278 | void | |
279 | babel_load_state_file(void) | |
280 | { | |
281 | int fd; | |
282 | int rc; | |
283 | ||
284 | fd = open(state_file, O_RDONLY); | |
285 | if(fd < 0 && errno != ENOENT) | |
450971aa | 286 | flog_err_sys(EC_LIB_SYSTEM_CALL, "open(babel-state: %s)", |
f135ba52 | 287 | safe_strerror(errno)); |
ca10883e DS |
288 | rc = unlink(state_file); |
289 | if(fd >= 0 && rc < 0) { | |
450971aa | 290 | flog_err_sys(EC_LIB_SYSTEM_CALL, "unlink(babel-state): %s", |
f135ba52 | 291 | safe_strerror(errno)); |
ca10883e | 292 | /* If we couldn't unlink it, it's probably stale. */ |
c31a793b | 293 | goto fini; |
ca10883e DS |
294 | } |
295 | if(fd >= 0) { | |
296 | char buf[100]; | |
297 | char buf2[100]; | |
298 | int s; | |
299 | long t; | |
300 | rc = read(fd, buf, 99); | |
301 | if(rc < 0) { | |
450971aa | 302 | flog_err_sys(EC_LIB_SYSTEM_CALL, "read(babel-state): %s", |
f135ba52 | 303 | safe_strerror(errno)); |
ca10883e DS |
304 | } else { |
305 | buf[rc] = '\0'; | |
306 | rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t); | |
307 | if(rc == 3 && s >= 0 && s <= 0xFFFF) { | |
308 | unsigned char sid[8]; | |
309 | rc = parse_eui64(buf2, sid); | |
310 | if(rc < 0) { | |
5b003f31 | 311 | flog_err(EC_BABEL_CONFIG, "Couldn't parse babel-state."); |
ca10883e DS |
312 | } else { |
313 | struct timeval realnow; | |
314 | debugf(BABEL_DEBUG_COMMON, | |
315 | "Got %s %d %ld from babel-state.", | |
316 | format_eui64(sid), s, t); | |
317 | gettimeofday(&realnow, NULL); | |
318 | if(memcmp(sid, myid, 8) == 0) | |
319 | myseqno = seqno_plus(s, 1); | |
320 | else | |
5b003f31 | 321 | flog_err(EC_BABEL_CONFIG, |
e33b116c | 322 | "ID mismatch in babel-state. id=%s; old=%s", |
ca10883e DS |
323 | format_eui64(myid), |
324 | format_eui64(sid)); | |
325 | } | |
326 | } else { | |
5b003f31 | 327 | flog_err(EC_BABEL_CONFIG, "Couldn't parse babel-state."); |
ca10883e DS |
328 | } |
329 | } | |
c31a793b | 330 | goto fini; |
ca10883e | 331 | } |
c31a793b VJ |
332 | fini: |
333 | if (fd >= 0) | |
334 | close(fd); | |
335 | return ; | |
ca10883e DS |
336 | } |
337 | ||
338 | static void | |
339 | babel_exit_properly(void) | |
340 | { | |
341 | debugf(BABEL_DEBUG_COMMON, "Exiting..."); | |
342 | usleep(roughly(10000)); | |
343 | gettime(&babel_now); | |
344 | ||
345 | /* Uninstall and flush all routes. */ | |
346 | debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); | |
347 | flush_all_routes(); | |
348 | babel_interface_close_all(); | |
349 | babel_zebra_close_connexion(); | |
350 | babel_save_state_file(); | |
351 | debugf(BABEL_DEBUG_COMMON, "Remove pid file."); | |
352 | debugf(BABEL_DEBUG_COMMON, "Done."); | |
8879bd22 | 353 | frr_fini(); |
ca10883e DS |
354 | |
355 | exit(0); | |
356 | } | |
357 | ||
358 | static void | |
359 | babel_save_state_file(void) | |
360 | { | |
361 | int fd; | |
362 | int rc; | |
363 | ||
364 | debugf(BABEL_DEBUG_COMMON, "Save state file."); | |
365 | fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644); | |
366 | if(fd < 0) { | |
450971aa | 367 | flog_err_sys(EC_LIB_SYSTEM_CALL, "creat(babel-state): %s", |
f135ba52 | 368 | safe_strerror(errno)); |
ca10883e DS |
369 | unlink(state_file); |
370 | } else { | |
371 | struct timeval realnow; | |
372 | char buf[100]; | |
373 | gettimeofday(&realnow, NULL); | |
374 | rc = snprintf(buf, 100, "%s %d %ld\n", | |
375 | format_eui64(myid), (int)myseqno, | |
376 | (long)realnow.tv_sec); | |
377 | if(rc < 0 || rc >= 100) { | |
5b003f31 | 378 | flog_err(EC_BABEL_CONFIG, "write(babel-state): overflow."); |
ca10883e DS |
379 | unlink(state_file); |
380 | } else { | |
381 | rc = write(fd, buf, rc); | |
382 | if(rc < 0) { | |
5b003f31 | 383 | flog_err(EC_BABEL_CONFIG, "write(babel-state): %s", |
e33b116c | 384 | safe_strerror(errno)); |
ca10883e DS |
385 | unlink(state_file); |
386 | } | |
387 | fsync(fd); | |
388 | } | |
389 | close(fd); | |
390 | } | |
391 | } | |
392 | ||
393 | void | |
394 | show_babel_main_configuration (struct vty *vty) | |
395 | { | |
181039f3 | 396 | vty_out (vty, |
cdda2010 DL |
397 | "state file = %s\n" |
398 | "configuration file = %s\n" | |
0437e105 | 399 | "protocol information:\n" |
cdda2010 DL |
400 | " multicast address = %s\n" |
401 | " port = %d\n" | |
402 | "vty address = %s\n" | |
403 | "vty port = %d\n" | |
404 | "id = %s\n" | |
181039f3 | 405 | "kernel_metric = %d\n", |
cdda2010 | 406 | state_file, |
f714218e | 407 | babeld_di.config_file ? babeld_di.config_file : babel_config_default, |
cdda2010 DL |
408 | format_address(protocol_group), |
409 | protocol_port, | |
ca10883e | 410 | babel_vty_addr ? babel_vty_addr : "None", |
cdda2010 DL |
411 | babel_vty_port, |
412 | format_eui64(myid), | |
96ade3ed | 413 | kernel_metric); |
ca10883e | 414 | } |