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