]>
Commit | Line | Data |
---|---|---|
5734509c PJ |
1 | /* |
2 | * This file is free software: you may copy, redistribute and/or modify it | |
3 | * under the terms of the GNU General Public License as published by the | |
4 | * Free Software Foundation, either version 2 of the License, or (at your | |
5 | * option) any later version. | |
6 | * | |
7 | * This file is distributed in the hope that it will be useful, but | |
8 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
10 | * General Public License for more details. | |
11 | * | |
12 | * You should have received a copy of the GNU General Public License | |
13 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
14 | * | |
15 | * This file incorporates work covered by the following copyright and | |
16 | * permission notice: | |
17 | * | |
18 | ||
19 | Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek | |
20 | ||
21 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
22 | of this software and associated documentation files (the "Software"), to deal | |
23 | in the Software without restriction, including without limitation the rights | |
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
25 | copies of the Software, and to permit persons to whom the Software is | |
26 | furnished to do so, subject to the following conditions: | |
27 | ||
28 | The above copyright notice and this permission notice shall be included in | |
29 | all copies or substantial portions of the Software. | |
30 | ||
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
37 | THE SOFTWARE. | |
38 | */ | |
39 | ||
40 | /* include zebra library */ | |
41 | #include <zebra.h> | |
42 | #include "getopt.h" | |
43 | #include "if.h" | |
44 | #include "log.h" | |
45 | #include "thread.h" | |
46 | #include "privs.h" | |
47 | #include "sigevent.h" | |
48 | #include "version.h" | |
49 | #include "command.h" | |
50 | #include "vty.h" | |
51 | #include "memory.h" | |
52 | ||
53 | #include "babel_main.h" | |
54 | #include "babeld.h" | |
55 | #include "util.h" | |
56 | #include "kernel.h" | |
57 | #include "babel_interface.h" | |
58 | #include "neighbour.h" | |
59 | #include "route.h" | |
60 | #include "xroute.h" | |
61 | #include "message.h" | |
62 | #include "resend.h" | |
63 | #include "babel_zebra.h" | |
64 | ||
65 | ||
66 | static void babel_init (int argc, char **argv); | |
5734509c PJ |
67 | static char *babel_get_progname(char *argv_0); |
68 | static void babel_fail(void); | |
69 | static void babel_init_random(void); | |
70 | static void babel_replace_by_null(int fd); | |
5734509c PJ |
71 | static void babel_init_signals(void); |
72 | static void babel_exit_properly(void); | |
73 | static void babel_save_state_file(void); | |
74 | ||
75 | ||
76 | struct thread_master *master; /* quagga's threads handler */ | |
77 | struct timeval babel_now; /* current time */ | |
78 | ||
79 | unsigned char myid[8]; /* unique id (mac address of an interface) */ | |
a14ef5ee | 80 | int debug = 0; |
5734509c | 81 | |
52d54422 JC |
82 | int default_wireless_hello_interval = -1; |
83 | int default_wired_hello_interval = -1; | |
84 | int resend_delay = -1; | |
87c271c6 | 85 | static const char *pidfile = PATH_BABELD_PID; |
5734509c PJ |
86 | |
87 | const unsigned char zeroes[16] = {0}; | |
88 | const unsigned char ones[16] = | |
89 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |
90 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
91 | ||
72db20bf | 92 | static const char *state_file = DAEMON_VTY_DIR "/babel-state"; |
5734509c PJ |
93 | |
94 | unsigned char protocol_group[16]; /* babel's link-local multicast address */ | |
95 | int protocol_port; /* babel's port */ | |
96 | int protocol_socket = -1; /* socket: communicate with others babeld */ | |
97 | ||
98 | static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; | |
99 | static char *babel_config_file = NULL; | |
100 | static char *babel_vty_addr = NULL; | |
101 | static int babel_vty_port = BABEL_VTY_PORT; | |
102 | ||
103 | /* Babeld options. */ | |
104 | struct option longopts[] = | |
105 | { | |
106 | { "daemon", no_argument, NULL, 'd'}, | |
107 | { "config_file", required_argument, NULL, 'f'}, | |
108 | { "pid_file", required_argument, NULL, 'i'}, | |
8f3607f8 | 109 | { "socket", required_argument, NULL, 'z'}, |
5734509c PJ |
110 | { "help", no_argument, NULL, 'h'}, |
111 | { "vty_addr", required_argument, NULL, 'A'}, | |
112 | { "vty_port", required_argument, NULL, 'P'}, | |
113 | { "user", required_argument, NULL, 'u'}, | |
114 | { "group", required_argument, NULL, 'g'}, | |
115 | { "version", no_argument, NULL, 'v'}, | |
116 | { 0 } | |
117 | }; | |
118 | ||
119 | /* babeld privileges */ | |
120 | static zebra_capabilities_t _caps_p [] = | |
121 | { | |
122 | ZCAP_NET_RAW, | |
123 | ZCAP_BIND | |
124 | }; | |
125 | static struct zebra_privs_t babeld_privs = | |
126 | { | |
127 | #if defined(QUAGGA_USER) | |
128 | .user = QUAGGA_USER, | |
129 | #endif | |
130 | #if defined QUAGGA_GROUP | |
131 | .group = QUAGGA_GROUP, | |
132 | #endif | |
133 | #ifdef VTY_GROUP | |
134 | .vty_group = VTY_GROUP, | |
135 | #endif | |
136 | .caps_p = _caps_p, | |
137 | .cap_num_p = 2, | |
138 | .cap_num_i = 0 | |
139 | }; | |
140 | ||
141 | ||
142 | int | |
143 | main(int argc, char **argv) | |
144 | { | |
145 | struct thread thread; | |
146 | /* and print banner too */ | |
147 | babel_init(argc, argv); | |
148 | while (thread_fetch (master, &thread)) { | |
149 | thread_call (&thread); | |
150 | } | |
151 | return 0; | |
152 | } | |
153 | ||
446d73b7 DO |
154 | static void |
155 | babel_usage (char *progname, int status) | |
156 | { | |
157 | if (status != 0) | |
158 | fprintf (stderr, "Try `%s --help' for more information.\n", progname); | |
159 | else | |
160 | { | |
161 | printf ("Usage : %s [OPTION...]\n\ | |
162 | Daemon which manages Babel routing protocol.\n\n\ | |
163 | -d, --daemon Runs in daemon mode\n\ | |
164 | -f, --config_file Set configuration file name\n\ | |
165 | -i, --pid_file Set process identifier file name\n\ | |
8f3607f8 | 166 | -z, --socket Set path of zebra socket\n\ |
446d73b7 DO |
167 | -A, --vty_addr Set vty's bind address\n\ |
168 | -P, --vty_port Set vty's port number\n\ | |
169 | -u, --user User to run as\n\ | |
170 | -g, --group Group to run as\n\ | |
171 | -v, --version Print program version\n\ | |
172 | -h, --help Display this help and exit\n\ | |
173 | \n\ | |
174 | Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); | |
175 | } | |
176 | exit (status); | |
177 | } | |
178 | ||
5734509c PJ |
179 | /* make initialisations witch don't need infos about kernel(interfaces, etc.) */ |
180 | static void | |
181 | babel_init(int argc, char **argv) | |
182 | { | |
183 | int rc, opt; | |
184 | int do_daemonise = 0; | |
185 | char *progname = NULL; | |
5734509c PJ |
186 | |
187 | /* Set umask before anything for security */ | |
188 | umask (0027); | |
189 | progname = babel_get_progname(argv[0]); | |
190 | ||
191 | /* set default log (lib/log.h) */ | |
192 | zlog_default = openzlog(progname, ZLOG_BABEL, | |
193 | LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); | |
194 | /* set log destination as stdout until the config file is read */ | |
195 | zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); | |
196 | ||
197 | babel_init_random(); | |
198 | ||
199 | /* set the Babel's default link-local multicast address and Babel's port */ | |
200 | parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); | |
201 | protocol_port = 6696; | |
202 | ||
203 | /* get options */ | |
204 | while(1) { | |
8f3607f8 | 205 | opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0); |
5734509c PJ |
206 | if(opt < 0) |
207 | break; | |
208 | ||
209 | switch(opt) { | |
210 | case 0: | |
211 | break; | |
212 | case 'd': | |
213 | do_daemonise = -1; | |
214 | break; | |
215 | case 'f': | |
216 | babel_config_file = optarg; | |
217 | break; | |
218 | case 'i': | |
219 | pidfile = optarg; | |
220 | break; | |
8f3607f8 DO |
221 | case 'z': |
222 | zclient_serv_path_set (optarg); | |
223 | break; | |
5734509c PJ |
224 | case 'A': |
225 | babel_vty_addr = optarg; | |
226 | break; | |
227 | case 'P': | |
228 | babel_vty_port = atoi (optarg); | |
38846de1 | 229 | if (babel_vty_port <= 0 || babel_vty_port > 0xffff) |
5734509c PJ |
230 | babel_vty_port = BABEL_VTY_PORT; |
231 | break; | |
232 | case 'u': | |
233 | babeld_privs.user = optarg; | |
234 | break; | |
235 | case 'g': | |
236 | babeld_privs.group = optarg; | |
237 | break; | |
238 | case 'v': | |
239 | print_version (progname); | |
240 | exit (0); | |
241 | break; | |
242 | case 'h': | |
446d73b7 | 243 | babel_usage (progname, 0); |
5734509c PJ |
244 | break; |
245 | default: | |
446d73b7 | 246 | babel_usage (progname, 1); |
5734509c PJ |
247 | break; |
248 | } | |
249 | } | |
250 | ||
251 | /* create the threads handler */ | |
252 | master = thread_master_create (); | |
253 | ||
254 | /* Library inits. */ | |
255 | zprivs_init (&babeld_privs); | |
256 | babel_init_signals(); | |
257 | cmd_init (1); | |
258 | vty_init (master); | |
259 | memory_init (); | |
260 | ||
52d54422 JC |
261 | if(default_wireless_hello_interval <= 0) |
262 | default_wireless_hello_interval = 4000; | |
263 | default_wireless_hello_interval = MAX(default_wireless_hello_interval, 5); | |
5734509c | 264 | |
52d54422 JC |
265 | if(default_wired_hello_interval <= 0) |
266 | default_wired_hello_interval = 4000; | |
267 | default_wired_hello_interval = MAX(default_wired_hello_interval, 5); | |
268 | ||
269 | resend_delay = 2000; | |
270 | resend_delay = MIN(resend_delay, default_wireless_hello_interval / 2); | |
271 | resend_delay = MIN(resend_delay, default_wired_hello_interval / 2); | |
272 | resend_delay = MAX(resend_delay, 20); | |
5734509c | 273 | |
5734509c PJ |
274 | if(parasitic && allow_duplicates >= 0) { |
275 | /* Too difficult to get right. */ | |
276 | zlog_err("Sorry, -P and -A are incompatible."); | |
277 | exit(1); | |
278 | } | |
279 | ||
280 | babel_replace_by_null(STDIN_FILENO); | |
281 | ||
282 | if (do_daemonise && daemonise() < 0) { | |
283 | zlog_err("daemonise: %s", safe_strerror(errno)); | |
284 | exit (1); | |
285 | } | |
286 | ||
287 | /* write pid file */ | |
288 | if (pid_output(pidfile) < 0) { | |
289 | zlog_err("error while writing pidfile"); | |
290 | exit (1); | |
291 | }; | |
292 | ||
293 | /* init some quagga's dependencies, and babeld's commands */ | |
294 | babeld_quagga_init(); | |
295 | /* init zebra client's structure and it's commands */ | |
296 | /* this replace kernel_setup && kernel_setup_socket */ | |
297 | babelz_zebra_init (); | |
298 | ||
299 | /* Sort all installed commands. */ | |
300 | sort_node (); | |
301 | ||
302 | /* Get zebra configuration file. */ | |
303 | zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); | |
304 | vty_read_config (babel_config_file, babel_config_default); | |
305 | ||
5734509c PJ |
306 | /* Create VTY socket */ |
307 | vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH); | |
308 | ||
309 | /* init buffer */ | |
310 | rc = resize_receive_buffer(1500); | |
311 | if(rc < 0) | |
312 | babel_fail(); | |
313 | ||
314 | schedule_neighbours_check(5000, 1); | |
315 | ||
316 | zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port); | |
317 | } | |
318 | ||
319 | /* return the progname (without path, example: "./x/progname" --> "progname") */ | |
320 | static char * | |
321 | babel_get_progname(char *argv_0) { | |
322 | char *p = strrchr (argv_0, '/'); | |
323 | return (p ? ++p : argv_0); | |
324 | } | |
325 | ||
5734509c PJ |
326 | static void |
327 | babel_fail(void) | |
328 | { | |
329 | exit(1); | |
330 | } | |
331 | ||
332 | /* initialize random value, and set 'babel_now' by the way. */ | |
333 | static void | |
334 | babel_init_random(void) | |
335 | { | |
336 | gettime(&babel_now); | |
337 | int rc; | |
338 | unsigned int seed; | |
339 | ||
340 | rc = read_random_bytes(&seed, sizeof(seed)); | |
341 | if(rc < 0) { | |
342 | zlog_err("read(random): %s", safe_strerror(errno)); | |
343 | seed = 42; | |
344 | } | |
345 | ||
346 | seed ^= (babel_now.tv_sec ^ babel_now.tv_usec); | |
347 | srandom(seed); | |
348 | } | |
349 | ||
350 | /* | |
351 | close fd, and replace it by "/dev/null" | |
352 | exit if error | |
353 | */ | |
354 | static void | |
355 | babel_replace_by_null(int fd) | |
356 | { | |
357 | int fd_null; | |
358 | int rc; | |
359 | ||
360 | fd_null = open("/dev/null", O_RDONLY); | |
361 | if(fd_null < 0) { | |
362 | zlog_err("open(null): %s", safe_strerror(errno)); | |
363 | exit(1); | |
364 | } | |
365 | ||
366 | rc = dup2(fd_null, fd); | |
367 | if(rc < 0) { | |
368 | zlog_err("dup2(null, 0): %s", safe_strerror(errno)); | |
369 | exit(1); | |
370 | } | |
371 | ||
372 | close(fd_null); | |
373 | } | |
374 | ||
375 | /* | |
376 | Load the state file: check last babeld's running state, usefull in case of | |
377 | "/etc/init.d/babeld restart" | |
378 | */ | |
69394543 | 379 | void |
5734509c PJ |
380 | babel_load_state_file(void) |
381 | { | |
5734509c PJ |
382 | int fd; |
383 | int rc; | |
384 | ||
385 | fd = open(state_file, O_RDONLY); | |
386 | if(fd < 0 && errno != ENOENT) | |
387 | zlog_err("open(babel-state: %s)", safe_strerror(errno)); | |
388 | rc = unlink(state_file); | |
389 | if(fd >= 0 && rc < 0) { | |
390 | zlog_err("unlink(babel-state): %s", safe_strerror(errno)); | |
391 | /* If we couldn't unlink it, it's probably stale. */ | |
392 | close(fd); | |
393 | fd = -1; | |
394 | } | |
395 | if(fd >= 0) { | |
396 | char buf[100]; | |
397 | char buf2[100]; | |
398 | int s; | |
399 | long t; | |
400 | rc = read(fd, buf, 99); | |
401 | if(rc < 0) { | |
402 | zlog_err("read(babel-state): %s", safe_strerror(errno)); | |
403 | } else { | |
404 | buf[rc] = '\0'; | |
405 | rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t); | |
406 | if(rc == 3 && s >= 0 && s <= 0xFFFF) { | |
407 | unsigned char sid[8]; | |
408 | rc = parse_eui64(buf2, sid); | |
409 | if(rc < 0) { | |
410 | zlog_err("Couldn't parse babel-state."); | |
411 | } else { | |
412 | struct timeval realnow; | |
413 | debugf(BABEL_DEBUG_COMMON, | |
414 | "Got %s %d %ld from babel-state.", | |
415 | format_eui64(sid), s, t); | |
416 | gettimeofday(&realnow, NULL); | |
417 | if(memcmp(sid, myid, 8) == 0) | |
418 | myseqno = seqno_plus(s, 1); | |
419 | else | |
210f6f66 MB |
420 | zlog_err("ID mismatch in babel-state. id=%s; old=%s", |
421 | format_eui64(myid), | |
422 | format_eui64(sid)); | |
5734509c PJ |
423 | } |
424 | } else { | |
425 | zlog_err("Couldn't parse babel-state."); | |
426 | } | |
427 | } | |
428 | close(fd); | |
429 | fd = -1; | |
430 | } | |
431 | } | |
432 | ||
433 | static void | |
434 | babel_sigexit(void) | |
435 | { | |
436 | zlog_notice("Terminating on signal"); | |
437 | ||
438 | babel_exit_properly(); | |
439 | } | |
440 | ||
441 | static void | |
442 | babel_sigusr1 (void) | |
443 | { | |
444 | zlog_rotate (NULL); | |
445 | } | |
446 | ||
447 | static void | |
448 | babel_init_signals(void) | |
449 | { | |
450 | static struct quagga_signal_t babel_signals[] = | |
451 | { | |
452 | { | |
453 | .signal = SIGUSR1, | |
454 | .handler = &babel_sigusr1, | |
455 | }, | |
456 | { | |
457 | .signal = SIGINT, | |
458 | .handler = &babel_sigexit, | |
459 | }, | |
460 | { | |
461 | .signal = SIGTERM, | |
462 | .handler = &babel_sigexit, | |
463 | }, | |
464 | }; | |
465 | ||
466 | signal_init (master, Q_SIGC(babel_signals), babel_signals); | |
467 | } | |
468 | ||
469 | static void | |
470 | babel_exit_properly(void) | |
471 | { | |
472 | debugf(BABEL_DEBUG_COMMON, "Exiting..."); | |
473 | usleep(roughly(10000)); | |
474 | gettime(&babel_now); | |
475 | ||
476 | /* Uninstall and flush all routes. */ | |
477 | debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); | |
c35fafdf | 478 | flush_all_routes(); |
5734509c PJ |
479 | babel_interface_close_all(); |
480 | babel_zebra_close_connexion(); | |
481 | babel_save_state_file(); | |
482 | debugf(BABEL_DEBUG_COMMON, "Remove pid file."); | |
483 | if(pidfile) | |
484 | unlink(pidfile); | |
485 | debugf(BABEL_DEBUG_COMMON, "Done."); | |
486 | ||
487 | exit(0); | |
488 | } | |
489 | ||
490 | static void | |
491 | babel_save_state_file(void) | |
492 | { | |
493 | int fd; | |
494 | int rc; | |
495 | ||
496 | debugf(BABEL_DEBUG_COMMON, "Save state file."); | |
497 | fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644); | |
498 | if(fd < 0) { | |
499 | zlog_err("creat(babel-state): %s", safe_strerror(errno)); | |
500 | unlink(state_file); | |
501 | } else { | |
502 | struct timeval realnow; | |
503 | char buf[100]; | |
504 | gettimeofday(&realnow, NULL); | |
505 | rc = snprintf(buf, 100, "%s %d %ld\n", | |
506 | format_eui64(myid), (int)myseqno, | |
507 | (long)realnow.tv_sec); | |
508 | if(rc < 0 || rc >= 100) { | |
509 | zlog_err("write(babel-state): overflow."); | |
510 | unlink(state_file); | |
511 | } else { | |
512 | rc = write(fd, buf, rc); | |
513 | if(rc < 0) { | |
514 | zlog_err("write(babel-state): %s", safe_strerror(errno)); | |
515 | unlink(state_file); | |
516 | } | |
517 | fsync(fd); | |
518 | } | |
519 | close(fd); | |
520 | } | |
521 | } | |
d3351d1e MB |
522 | |
523 | void | |
524 | show_babel_main_configuration (struct vty *vty) | |
525 | { | |
d3351d1e MB |
526 | vty_out(vty, |
527 | "pid file = %s%s" | |
528 | "state file = %s%s" | |
529 | "configuration file = %s%s" | |
530 | "protocol informations:%s" | |
531 | " multicast address = %s%s" | |
532 | " port = %d%s" | |
533 | "vty address = %s%s" | |
534 | "vty port = %d%s" | |
535 | "id = %s%s" | |
d3351d1e | 536 | "parasitic = %s%s" |
9c298c71 | 537 | "resend-delay = %d%s" |
d3351d1e MB |
538 | "allow_duplicates = %s%s" |
539 | "kernel_metric = %d%s", | |
540 | pidfile, VTY_NEWLINE, | |
541 | state_file, VTY_NEWLINE, | |
542 | babel_config_file ? babel_config_file : babel_config_default, | |
543 | VTY_NEWLINE, | |
544 | VTY_NEWLINE, | |
545 | format_address(protocol_group), VTY_NEWLINE, | |
546 | protocol_port, VTY_NEWLINE, | |
547 | babel_vty_addr ? babel_vty_addr : "None", | |
548 | VTY_NEWLINE, | |
549 | babel_vty_port, VTY_NEWLINE, | |
550 | format_eui64(myid), VTY_NEWLINE, | |
d3351d1e | 551 | format_bool(parasitic), VTY_NEWLINE, |
9c298c71 | 552 | resend_delay, VTY_NEWLINE, |
d3351d1e MB |
553 | format_bool(allow_duplicates), VTY_NEWLINE, |
554 | kernel_metric, VTY_NEWLINE); | |
555 | } |