]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babel_main.c
babeld: add handling of "-z" cmdline arg
[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 time_t reboot_time;
84 int idle_time = 320;
85 int link_detect = 0;
86 int wireless_hello_interval = -1;
87 int wired_hello_interval = -1;
88 int idle_hello_interval = -1;
89 static const char *pidfile = PATH_BABELD_PID;
90
91 const unsigned char zeroes[16] = {0};
92 const unsigned char ones[16] =
93 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
94 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
95
96 static const char *state_file = "/var/lib/babeld/babel-state";
97
98 unsigned char protocol_group[16]; /* babel's link-local multicast address */
99 int protocol_port; /* babel's port */
100 int protocol_socket = -1; /* socket: communicate with others babeld */
101
102 static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
103 static char *babel_config_file = NULL;
104 static char *babel_vty_addr = NULL;
105 static int babel_vty_port = BABEL_VTY_PORT;
106
107 /* Babeld options. */
108 struct option longopts[] =
109 {
110 { "daemon", no_argument, NULL, 'd'},
111 { "config_file", required_argument, NULL, 'f'},
112 { "pid_file", required_argument, NULL, 'i'},
113 { "socket", required_argument, NULL, 'z'},
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 */
124 static zebra_capabilities_t _caps_p [] =
125 {
126 ZCAP_NET_RAW,
127 ZCAP_BIND
128 };
129 static 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
146 int
147 main(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
158 static void
159 babel_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\
166 Daemon 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\
170 -z, --socket Set path of zebra socket\n\
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\
178 Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
179 }
180 exit (status);
181 }
182
183 /* make initialisations witch don't need infos about kernel(interfaces, etc.) */
184 static void
185 babel_init(int argc, char **argv)
186 {
187 int rc, opt;
188 int do_daemonise = 0;
189 char *progname = NULL;
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) {
209 opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0);
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;
225 case 'z':
226 zclient_serv_path_set (optarg);
227 break;
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':
248 babel_usage (progname, 0);
249 break;
250 default:
251 babel_usage (progname, 1);
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") */
326 static char *
327 babel_get_progname(char *argv_0) {
328 char *p = strrchr (argv_0, '/');
329 return (p ? ++p : argv_0);
330 }
331
332 static void
333 babel_fail(void)
334 {
335 exit(1);
336 }
337
338 /* initialize random value, and set 'babel_now' by the way. */
339 static void
340 babel_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 */
360 static void
361 babel_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 */
385 static void
386 babel_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
441 static void
442 babel_sigexit(void)
443 {
444 zlog_notice("Terminating on signal");
445
446 babel_exit_properly();
447 }
448
449 static void
450 babel_sigusr1 (void)
451 {
452 zlog_rotate (NULL);
453 }
454
455 static void
456 babel_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
477 static void
478 babel_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
498 static void
499 babel_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 }