]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babel_main.c
babeld: remove useless variable, make local another.
[mirror_frr.git] / babeld / babel_main.c
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);
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);
71 static void babel_load_state_file(void);
72 static void babel_init_signals(void);
73 static void babel_exit_properly(void);
74 static void babel_save_state_file(void);
75
76
77 struct thread_master *master; /* quagga's threads handler */
78 struct timeval babel_now; /* current time */
79
80 unsigned char myid[8]; /* unique id (mac address of an interface) */
81 int debug = BABEL_DEBUG_COMMON;
82
83 int idle_time = 320;
84 int wireless_hello_interval = -1;
85 int wired_hello_interval = -1;
86 int idle_hello_interval = -1;
87 static const char *pidfile = PATH_BABELD_PID;
88
89 const unsigned char zeroes[16] = {0};
90 const unsigned char ones[16] =
91 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
92 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
93
94 static const char *state_file = DAEMON_VTY_DIR "/babel-state";
95
96 unsigned char protocol_group[16]; /* babel's link-local multicast address */
97 int protocol_port; /* babel's port */
98 int protocol_socket = -1; /* socket: communicate with others babeld */
99
100 static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
101 static char *babel_config_file = NULL;
102 static char *babel_vty_addr = NULL;
103 static int babel_vty_port = BABEL_VTY_PORT;
104
105 /* Babeld options. */
106 struct option longopts[] =
107 {
108 { "daemon", no_argument, NULL, 'd'},
109 { "config_file", required_argument, NULL, 'f'},
110 { "pid_file", required_argument, NULL, 'i'},
111 { "socket", required_argument, NULL, 'z'},
112 { "help", no_argument, NULL, 'h'},
113 { "vty_addr", required_argument, NULL, 'A'},
114 { "vty_port", required_argument, NULL, 'P'},
115 { "user", required_argument, NULL, 'u'},
116 { "group", required_argument, NULL, 'g'},
117 { "version", no_argument, NULL, 'v'},
118 { 0 }
119 };
120
121 /* babeld privileges */
122 static zebra_capabilities_t _caps_p [] =
123 {
124 ZCAP_NET_RAW,
125 ZCAP_BIND
126 };
127 static struct zebra_privs_t babeld_privs =
128 {
129 #if defined(QUAGGA_USER)
130 .user = QUAGGA_USER,
131 #endif
132 #if defined QUAGGA_GROUP
133 .group = QUAGGA_GROUP,
134 #endif
135 #ifdef VTY_GROUP
136 .vty_group = VTY_GROUP,
137 #endif
138 .caps_p = _caps_p,
139 .cap_num_p = 2,
140 .cap_num_i = 0
141 };
142
143
144 int
145 main(int argc, char **argv)
146 {
147 struct thread thread;
148 /* and print banner too */
149 babel_init(argc, argv);
150 while (thread_fetch (master, &thread)) {
151 thread_call (&thread);
152 }
153 return 0;
154 }
155
156 static void
157 babel_usage (char *progname, int status)
158 {
159 if (status != 0)
160 fprintf (stderr, "Try `%s --help' for more information.\n", progname);
161 else
162 {
163 printf ("Usage : %s [OPTION...]\n\
164 Daemon which manages Babel routing protocol.\n\n\
165 -d, --daemon Runs in daemon mode\n\
166 -f, --config_file Set configuration file name\n\
167 -i, --pid_file Set process identifier file name\n\
168 -z, --socket Set path of zebra socket\n\
169 -A, --vty_addr Set vty's bind address\n\
170 -P, --vty_port Set vty's port number\n\
171 -u, --user User to run as\n\
172 -g, --group Group to run as\n\
173 -v, --version Print program version\n\
174 -h, --help Display this help and exit\n\
175 \n\
176 Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
177 }
178 exit (status);
179 }
180
181 /* make initialisations witch don't need infos about kernel(interfaces, etc.) */
182 static void
183 babel_init(int argc, char **argv)
184 {
185 int rc, opt;
186 int do_daemonise = 0;
187 char *progname = NULL;
188
189 /* Set umask before anything for security */
190 umask (0027);
191 progname = babel_get_progname(argv[0]);
192
193 /* set default log (lib/log.h) */
194 zlog_default = openzlog(progname, ZLOG_BABEL,
195 LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
196 /* set log destination as stdout until the config file is read */
197 zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING);
198
199 babel_init_random();
200
201 /* set the Babel's default link-local multicast address and Babel's port */
202 parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
203 protocol_port = 6696;
204
205 /* get options */
206 while(1) {
207 opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0);
208 if(opt < 0)
209 break;
210
211 switch(opt) {
212 case 0:
213 break;
214 case 'd':
215 do_daemonise = -1;
216 break;
217 case 'f':
218 babel_config_file = optarg;
219 break;
220 case 'i':
221 pidfile = optarg;
222 break;
223 case 'z':
224 zclient_serv_path_set (optarg);
225 break;
226 case 'A':
227 babel_vty_addr = optarg;
228 break;
229 case 'P':
230 babel_vty_port = atoi (optarg);
231 if (babel_vty_port < 0 || babel_vty_port > 0xffff
232 || (babel_vty_port == 0 && optarg[0] != '0'/*atoi error*/))
233 babel_vty_port = BABEL_VTY_PORT;
234 break;
235 case 'u':
236 babeld_privs.user = optarg;
237 break;
238 case 'g':
239 babeld_privs.group = optarg;
240 break;
241 case 'v':
242 print_version (progname);
243 exit (0);
244 break;
245 case 'h':
246 babel_usage (progname, 0);
247 break;
248 default:
249 babel_usage (progname, 1);
250 break;
251 }
252 }
253
254 /* create the threads handler */
255 master = thread_master_create ();
256
257 /* Library inits. */
258 zprivs_init (&babeld_privs);
259 babel_init_signals();
260 cmd_init (1);
261 vty_init (master);
262 memory_init ();
263
264 /* babeld inits (default options) */
265 /* set default interval's values */
266 if(wireless_hello_interval <= 0)
267 wireless_hello_interval = 4000;
268 wireless_hello_interval = MAX(wireless_hello_interval, 5);
269
270 if(wired_hello_interval <= 0)
271 wired_hello_interval = 4000;
272 wired_hello_interval = MAX(wired_hello_interval, 5);
273
274 /* an assertion */
275 if(parasitic && allow_duplicates >= 0) {
276 /* Too difficult to get right. */
277 zlog_err("Sorry, -P and -A are incompatible.");
278 exit(1);
279 }
280
281 babel_replace_by_null(STDIN_FILENO);
282
283 if (do_daemonise && daemonise() < 0) {
284 zlog_err("daemonise: %s", safe_strerror(errno));
285 exit (1);
286 }
287
288 /* write pid file */
289 if (pid_output(pidfile) < 0) {
290 zlog_err("error while writing pidfile");
291 exit (1);
292 };
293
294 /* init some quagga's dependencies, and babeld's commands */
295 babeld_quagga_init();
296 /* init zebra client's structure and it's commands */
297 /* this replace kernel_setup && kernel_setup_socket */
298 babelz_zebra_init ();
299
300 /* Sort all installed commands. */
301 sort_node ();
302
303 /* Get zebra configuration file. */
304 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
305 vty_read_config (babel_config_file, babel_config_default);
306
307 myseqno = (random() & 0xFFFF);
308 babel_load_state_file();
309
310 /* Create VTY socket */
311 vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH);
312
313 /* init buffer */
314 rc = resize_receive_buffer(1500);
315 if(rc < 0)
316 babel_fail();
317
318 schedule_neighbours_check(5000, 1);
319
320 zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port);
321 }
322
323 /* return the progname (without path, example: "./x/progname" --> "progname") */
324 static char *
325 babel_get_progname(char *argv_0) {
326 char *p = strrchr (argv_0, '/');
327 return (p ? ++p : argv_0);
328 }
329
330 static void
331 babel_fail(void)
332 {
333 exit(1);
334 }
335
336 /* initialize random value, and set 'babel_now' by the way. */
337 static void
338 babel_init_random(void)
339 {
340 gettime(&babel_now);
341 int rc;
342 unsigned int seed;
343
344 rc = read_random_bytes(&seed, sizeof(seed));
345 if(rc < 0) {
346 zlog_err("read(random): %s", safe_strerror(errno));
347 seed = 42;
348 }
349
350 seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
351 srandom(seed);
352 }
353
354 /*
355 close fd, and replace it by "/dev/null"
356 exit if error
357 */
358 static void
359 babel_replace_by_null(int fd)
360 {
361 int fd_null;
362 int rc;
363
364 fd_null = open("/dev/null", O_RDONLY);
365 if(fd_null < 0) {
366 zlog_err("open(null): %s", safe_strerror(errno));
367 exit(1);
368 }
369
370 rc = dup2(fd_null, fd);
371 if(rc < 0) {
372 zlog_err("dup2(null, 0): %s", safe_strerror(errno));
373 exit(1);
374 }
375
376 close(fd_null);
377 }
378
379 /*
380 Load the state file: check last babeld's running state, usefull in case of
381 "/etc/init.d/babeld restart"
382 */
383 static void
384 babel_load_state_file(void)
385 {
386 time_t reboot_time;
387 reboot_time = babel_now.tv_sec;
388 int fd;
389 int rc;
390
391 fd = open(state_file, O_RDONLY);
392 if(fd < 0 && errno != ENOENT)
393 zlog_err("open(babel-state: %s)", safe_strerror(errno));
394 rc = unlink(state_file);
395 if(fd >= 0 && rc < 0) {
396 zlog_err("unlink(babel-state): %s", safe_strerror(errno));
397 /* If we couldn't unlink it, it's probably stale. */
398 close(fd);
399 fd = -1;
400 }
401 if(fd >= 0) {
402 char buf[100];
403 char buf2[100];
404 int s;
405 long t;
406 rc = read(fd, buf, 99);
407 if(rc < 0) {
408 zlog_err("read(babel-state): %s", safe_strerror(errno));
409 } else {
410 buf[rc] = '\0';
411 rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
412 if(rc == 3 && s >= 0 && s <= 0xFFFF) {
413 unsigned char sid[8];
414 rc = parse_eui64(buf2, sid);
415 if(rc < 0) {
416 zlog_err("Couldn't parse babel-state.");
417 } else {
418 struct timeval realnow;
419 debugf(BABEL_DEBUG_COMMON,
420 "Got %s %d %ld from babel-state.",
421 format_eui64(sid), s, t);
422 gettimeofday(&realnow, NULL);
423 if(memcmp(sid, myid, 8) == 0)
424 myseqno = seqno_plus(s, 1);
425 else
426 zlog_err("ID mismatch in babel-state.");
427 /* Convert realtime into monotonic time. */
428 if(t >= 1176800000L && t <= realnow.tv_sec)
429 reboot_time = babel_now.tv_sec - (realnow.tv_sec - t);
430 }
431 } else {
432 zlog_err("Couldn't parse babel-state.");
433 }
434 }
435 close(fd);
436 fd = -1;
437 }
438 }
439
440 static void
441 babel_sigexit(void)
442 {
443 zlog_notice("Terminating on signal");
444
445 babel_exit_properly();
446 }
447
448 static void
449 babel_sigusr1 (void)
450 {
451 zlog_rotate (NULL);
452 }
453
454 static void
455 babel_init_signals(void)
456 {
457 static struct quagga_signal_t babel_signals[] =
458 {
459 {
460 .signal = SIGUSR1,
461 .handler = &babel_sigusr1,
462 },
463 {
464 .signal = SIGINT,
465 .handler = &babel_sigexit,
466 },
467 {
468 .signal = SIGTERM,
469 .handler = &babel_sigexit,
470 },
471 };
472
473 signal_init (master, Q_SIGC(babel_signals), babel_signals);
474 }
475
476 static void
477 babel_exit_properly(void)
478 {
479 debugf(BABEL_DEBUG_COMMON, "Exiting...");
480 usleep(roughly(10000));
481 gettime(&babel_now);
482
483 /* Uninstall and flush all routes. */
484 debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
485 babel_uninstall_all_routes();
486 babel_interface_close_all();
487 babel_zebra_close_connexion();
488 babel_save_state_file();
489 debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
490 if(pidfile)
491 unlink(pidfile);
492 debugf(BABEL_DEBUG_COMMON, "Done.");
493
494 exit(0);
495 }
496
497 static void
498 babel_save_state_file(void)
499 {
500 int fd;
501 int rc;
502
503 debugf(BABEL_DEBUG_COMMON, "Save state file.");
504 fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
505 if(fd < 0) {
506 zlog_err("creat(babel-state): %s", safe_strerror(errno));
507 unlink(state_file);
508 } else {
509 struct timeval realnow;
510 char buf[100];
511 gettimeofday(&realnow, NULL);
512 rc = snprintf(buf, 100, "%s %d %ld\n",
513 format_eui64(myid), (int)myseqno,
514 (long)realnow.tv_sec);
515 if(rc < 0 || rc >= 100) {
516 zlog_err("write(babel-state): overflow.");
517 unlink(state_file);
518 } else {
519 rc = write(fd, buf, rc);
520 if(rc < 0) {
521 zlog_err("write(babel-state): %s", safe_strerror(errno));
522 unlink(state_file);
523 }
524 fsync(fd);
525 }
526 close(fd);
527 }
528 }
529
530 void
531 show_babel_main_configuration (struct vty *vty)
532 {
533 #ifdef NO_DEBUG
534 vty_out(vty, "No debug.%s", VTY_NEWLINE);
535 #else
536 vty_out(vty, "Activated debug options:");
537 if (debug == BABEL_DEBUG_ALL) {
538 vty_out(vty, " all%s", VTY_NEWLINE);
539 } else {
540 vty_out(vty, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
541 debug & BABEL_DEBUG_COMMON ? VTY_NEWLINE : "",
542 debug & BABEL_DEBUG_COMMON ? " common" : "",
543 debug & BABEL_DEBUG_KERNEL ? VTY_NEWLINE : "",
544 debug & BABEL_DEBUG_KERNEL ? " kernel" : "",
545 debug & BABEL_DEBUG_FILTER ? VTY_NEWLINE : "",
546 debug & BABEL_DEBUG_FILTER ? " filter" : "",
547 debug & BABEL_DEBUG_TIMEOUT ? VTY_NEWLINE : "",
548 debug & BABEL_DEBUG_TIMEOUT ? " timeout" : "",
549 debug & BABEL_DEBUG_IF ? VTY_NEWLINE : "",
550 debug & BABEL_DEBUG_IF ? " interface": "",
551 debug & BABEL_DEBUG_ROUTE ? VTY_NEWLINE : "",
552 debug & BABEL_DEBUG_ROUTE ? " route" : "",
553 VTY_NEWLINE);
554 }
555 #endif
556
557 vty_out(vty,
558 "pid file = %s%s"
559 "state file = %s%s"
560 "configuration file = %s%s"
561 "protocol informations:%s"
562 " multicast address = %s%s"
563 " port = %d%s"
564 "vty address = %s%s"
565 "vty port = %d%s"
566 "id = %s%s"
567 "idle time = %d%s"
568 "wireless hello interval = %d%s"
569 "wired hello interval = %d%s"
570 "idle hello interval = %d%s"
571 "parasitic = %s%s"
572 "split-horizon = %s%s"
573 "allow_duplicates = %s%s"
574 "kernel_metric = %d%s",
575 pidfile, VTY_NEWLINE,
576 state_file, VTY_NEWLINE,
577 babel_config_file ? babel_config_file : babel_config_default,
578 VTY_NEWLINE,
579 VTY_NEWLINE,
580 format_address(protocol_group), VTY_NEWLINE,
581 protocol_port, VTY_NEWLINE,
582 babel_vty_addr ? babel_vty_addr : "None",
583 VTY_NEWLINE,
584 babel_vty_port, VTY_NEWLINE,
585 format_eui64(myid), VTY_NEWLINE,
586 idle_time, VTY_NEWLINE,
587 wireless_hello_interval, VTY_NEWLINE,
588 wired_hello_interval, VTY_NEWLINE,
589 idle_hello_interval, VTY_NEWLINE,
590 format_bool(parasitic), VTY_NEWLINE,
591 format_bool(split_horizon), VTY_NEWLINE,
592 format_bool(allow_duplicates), VTY_NEWLINE,
593 kernel_metric, VTY_NEWLINE);
594 }