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