blob: c039c880e3f527dfac97caf9e3852c639a9e4fe0 [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
Matthieu Boutier210f6f62012-01-28 00:07:14 +0100426 zlog_err("ID mismatch in babel-state. id=%s; old=%s",
427 format_eui64(myid),
428 format_eui64(sid));
Paul Jakma57345092011-12-25 17:52:09 +0100429 /* Convert realtime into monotonic time. */
430 if(t >= 1176800000L && t <= realnow.tv_sec)
431 reboot_time = babel_now.tv_sec - (realnow.tv_sec - t);
432 }
433 } else {
434 zlog_err("Couldn't parse babel-state.");
435 }
436 }
437 close(fd);
438 fd = -1;
439 }
440}
441
442static void
443babel_sigexit(void)
444{
445 zlog_notice("Terminating on signal");
446
447 babel_exit_properly();
448}
449
450static void
451babel_sigusr1 (void)
452{
453 zlog_rotate (NULL);
454}
455
456static void
457babel_init_signals(void)
458{
459 static struct quagga_signal_t babel_signals[] =
460 {
461 {
462 .signal = SIGUSR1,
463 .handler = &babel_sigusr1,
464 },
465 {
466 .signal = SIGINT,
467 .handler = &babel_sigexit,
468 },
469 {
470 .signal = SIGTERM,
471 .handler = &babel_sigexit,
472 },
473 };
474
475 signal_init (master, Q_SIGC(babel_signals), babel_signals);
476}
477
478static void
479babel_exit_properly(void)
480{
481 debugf(BABEL_DEBUG_COMMON, "Exiting...");
482 usleep(roughly(10000));
483 gettime(&babel_now);
484
485 /* Uninstall and flush all routes. */
486 debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100487 flush_all_routes();
Paul Jakma57345092011-12-25 17:52:09 +0100488 babel_interface_close_all();
489 babel_zebra_close_connexion();
490 babel_save_state_file();
491 debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
492 if(pidfile)
493 unlink(pidfile);
494 debugf(BABEL_DEBUG_COMMON, "Done.");
495
496 exit(0);
497}
498
499static void
500babel_save_state_file(void)
501{
502 int fd;
503 int rc;
504
505 debugf(BABEL_DEBUG_COMMON, "Save state file.");
506 fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
507 if(fd < 0) {
508 zlog_err("creat(babel-state): %s", safe_strerror(errno));
509 unlink(state_file);
510 } else {
511 struct timeval realnow;
512 char buf[100];
513 gettimeofday(&realnow, NULL);
514 rc = snprintf(buf, 100, "%s %d %ld\n",
515 format_eui64(myid), (int)myseqno,
516 (long)realnow.tv_sec);
517 if(rc < 0 || rc >= 100) {
518 zlog_err("write(babel-state): overflow.");
519 unlink(state_file);
520 } else {
521 rc = write(fd, buf, rc);
522 if(rc < 0) {
523 zlog_err("write(babel-state): %s", safe_strerror(errno));
524 unlink(state_file);
525 }
526 fsync(fd);
527 }
528 close(fd);
529 }
530}
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100531
532void
533show_babel_main_configuration (struct vty *vty)
534{
535#ifdef NO_DEBUG
536 vty_out(vty, "No debug.%s", VTY_NEWLINE);
537#else
538 vty_out(vty, "Activated debug options:");
539 if (debug == BABEL_DEBUG_ALL) {
540 vty_out(vty, " all%s", VTY_NEWLINE);
541 } else {
542 vty_out(vty, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
543 debug & BABEL_DEBUG_COMMON ? VTY_NEWLINE : "",
544 debug & BABEL_DEBUG_COMMON ? " common" : "",
545 debug & BABEL_DEBUG_KERNEL ? VTY_NEWLINE : "",
546 debug & BABEL_DEBUG_KERNEL ? " kernel" : "",
547 debug & BABEL_DEBUG_FILTER ? VTY_NEWLINE : "",
548 debug & BABEL_DEBUG_FILTER ? " filter" : "",
549 debug & BABEL_DEBUG_TIMEOUT ? VTY_NEWLINE : "",
550 debug & BABEL_DEBUG_TIMEOUT ? " timeout" : "",
551 debug & BABEL_DEBUG_IF ? VTY_NEWLINE : "",
552 debug & BABEL_DEBUG_IF ? " interface": "",
553 debug & BABEL_DEBUG_ROUTE ? VTY_NEWLINE : "",
554 debug & BABEL_DEBUG_ROUTE ? " route" : "",
555 VTY_NEWLINE);
556 }
557#endif
558
559 vty_out(vty,
560 "pid file = %s%s"
561 "state file = %s%s"
562 "configuration file = %s%s"
563 "protocol informations:%s"
564 " multicast address = %s%s"
565 " port = %d%s"
566 "vty address = %s%s"
567 "vty port = %d%s"
568 "id = %s%s"
569 "idle time = %d%s"
570 "wireless hello interval = %d%s"
571 "wired hello interval = %d%s"
572 "idle hello interval = %d%s"
573 "parasitic = %s%s"
574 "split-horizon = %s%s"
575 "allow_duplicates = %s%s"
576 "kernel_metric = %d%s",
577 pidfile, VTY_NEWLINE,
578 state_file, VTY_NEWLINE,
579 babel_config_file ? babel_config_file : babel_config_default,
580 VTY_NEWLINE,
581 VTY_NEWLINE,
582 format_address(protocol_group), VTY_NEWLINE,
583 protocol_port, VTY_NEWLINE,
584 babel_vty_addr ? babel_vty_addr : "None",
585 VTY_NEWLINE,
586 babel_vty_port, VTY_NEWLINE,
587 format_eui64(myid), VTY_NEWLINE,
588 idle_time, VTY_NEWLINE,
589 wireless_hello_interval, VTY_NEWLINE,
590 wired_hello_interval, VTY_NEWLINE,
591 idle_hello_interval, VTY_NEWLINE,
592 format_bool(parasitic), VTY_NEWLINE,
593 format_bool(split_horizon), VTY_NEWLINE,
594 format_bool(allow_duplicates), VTY_NEWLINE,
595 kernel_metric, VTY_NEWLINE);
596}