blob: 159ba656592c651d069b2c1bafda9381747d418c [file] [log] [blame]
Paul Jakma57345092011-12-25 17:52:09 +01001/*
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
19Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21Permission is hereby granted, free of charge, to any person obtaining a copy
22of this software and associated documentation files (the "Software"), to deal
23in the Software without restriction, including without limitation the rights
24to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25copies of the Software, and to permit persons to whom the Software is
26furnished to do so, subject to the following conditions:
27
28The above copyright notice and this permission notice shall be included in
29all copies or substantial portions of the Software.
30
31THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37THE 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
66static void babel_init (int argc, char **argv);
Paul Jakma57345092011-12-25 17:52:09 +010067static char *babel_get_progname(char *argv_0);
68static void babel_fail(void);
69static void babel_init_random(void);
70static void babel_replace_by_null(int fd);
71static void babel_load_state_file(void);
72static void babel_init_signals(void);
73static void babel_exit_properly(void);
74static void babel_save_state_file(void);
75
76
77struct thread_master *master; /* quagga's threads handler */
78struct timeval babel_now; /* current time */
79
80unsigned char myid[8]; /* unique id (mac address of an interface) */
81int debug = BABEL_DEBUG_COMMON;
82
Paul Jakma57345092011-12-25 17:52:09 +010083int idle_time = 320;
Paul Jakma57345092011-12-25 17:52:09 +010084int wireless_hello_interval = -1;
85int wired_hello_interval = -1;
86int idle_hello_interval = -1;
Denis Ovsienko87c271c2012-01-10 15:58:04 +040087static const char *pidfile = PATH_BABELD_PID;
Paul Jakma57345092011-12-25 17:52:09 +010088
89const unsigned char zeroes[16] = {0};
90const unsigned char ones[16] =
91 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
92 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
93
Matthieu Boutier72db20b2012-01-18 22:06:10 +010094static const char *state_file = DAEMON_VTY_DIR "/babel-state";
Paul Jakma57345092011-12-25 17:52:09 +010095
96unsigned char protocol_group[16]; /* babel's link-local multicast address */
97int protocol_port; /* babel's port */
98int protocol_socket = -1; /* socket: communicate with others babeld */
99
100static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
101static char *babel_config_file = NULL;
102static char *babel_vty_addr = NULL;
103static int babel_vty_port = BABEL_VTY_PORT;
104
105/* Babeld options. */
106struct option longopts[] =
107{
108 { "daemon", no_argument, NULL, 'd'},
109 { "config_file", required_argument, NULL, 'f'},
110 { "pid_file", required_argument, NULL, 'i'},
Denis Ovsienko8f3607f2012-01-17 17:04:00 +0400111 { "socket", required_argument, NULL, 'z'},
Paul Jakma57345092011-12-25 17:52:09 +0100112 { "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 */
122static zebra_capabilities_t _caps_p [] =
123{
124 ZCAP_NET_RAW,
125 ZCAP_BIND
126};
127static 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
144int
145main(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
Denis Ovsienko446d73b2012-01-17 17:00:20 +0400156static void
157babel_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\
164Daemon 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\
Denis Ovsienko8f3607f2012-01-17 17:04:00 +0400168-z, --socket Set path of zebra socket\n\
Denis Ovsienko446d73b2012-01-17 17:00:20 +0400169-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\
176Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
177 }
178 exit (status);
179}
180
Paul Jakma57345092011-12-25 17:52:09 +0100181/* make initialisations witch don't need infos about kernel(interfaces, etc.) */
182static void
183babel_init(int argc, char **argv)
184{
185 int rc, opt;
186 int do_daemonise = 0;
187 char *progname = NULL;
Paul Jakma57345092011-12-25 17:52:09 +0100188
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) {
Denis Ovsienko8f3607f2012-01-17 17:04:00 +0400207 opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0);
Paul Jakma57345092011-12-25 17:52:09 +0100208 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;
Denis Ovsienko8f3607f2012-01-17 17:04:00 +0400223 case 'z':
224 zclient_serv_path_set (optarg);
225 break;
Paul Jakma57345092011-12-25 17:52:09 +0100226 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':
Denis Ovsienko446d73b2012-01-17 17:00:20 +0400246 babel_usage (progname, 0);
Paul Jakma57345092011-12-25 17:52:09 +0100247 break;
248 default:
Denis Ovsienko446d73b2012-01-17 17:00:20 +0400249 babel_usage (progname, 1);
Paul Jakma57345092011-12-25 17:52:09 +0100250 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") */
324static char *
325babel_get_progname(char *argv_0) {
326 char *p = strrchr (argv_0, '/');
327 return (p ? ++p : argv_0);
328}
329
330static void
Paul Jakma57345092011-12-25 17:52:09 +0100331babel_fail(void)
332{
333 exit(1);
334}
335
336/* initialize random value, and set 'babel_now' by the way. */
337static void
338babel_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 */
358static void
359babel_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 */
383static void
384babel_load_state_file(void)
385{
Matthieu Boutierb5d43c92012-01-19 22:38:56 +0100386 time_t reboot_time;
Paul Jakma57345092011-12-25 17:52:09 +0100387 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
440static void
441babel_sigexit(void)
442{
443 zlog_notice("Terminating on signal");
444
445 babel_exit_properly();
446}
447
448static void
449babel_sigusr1 (void)
450{
451 zlog_rotate (NULL);
452}
453
454static void
455babel_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
476static void
477babel_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
497static void
498babel_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}
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100529
530void
531show_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}