]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babel_main.c
2a40b4f894fa25d807770250a0f5fc805a07711b
[mirror_frr.git] / babeld / babel_main.c
1 /*
2 Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 /* include zebra library */
24 #include <zebra.h>
25 #include "getopt.h"
26 #include "if.h"
27 #include "log.h"
28 #include "thread.h"
29 #include "privs.h"
30 #include "sigevent.h"
31 #include "version.h"
32 #include "command.h"
33 #include "vty.h"
34 #include "memory.h"
35 #include "libfrr.h"
36 #include "lib_errors.h"
37
38 #include "babel_main.h"
39 #include "babeld.h"
40 #include "util.h"
41 #include "kernel.h"
42 #include "babel_interface.h"
43 #include "neighbour.h"
44 #include "route.h"
45 #include "xroute.h"
46 #include "message.h"
47 #include "resend.h"
48 #include "babel_zebra.h"
49 #include "babel_errors.h"
50
51 static void babel_fail(void);
52 static void babel_init_random(void);
53 static void babel_replace_by_null(int fd);
54 static void babel_exit_properly(void);
55 static void babel_save_state_file(void);
56
57
58 struct thread_master *master; /* quagga's threads handler */
59 struct timeval babel_now; /* current time */
60
61 unsigned char myid[8]; /* unique id (mac address of an interface) */
62 int debug = 0;
63
64 int resend_delay = -1;
65
66 const unsigned char zeroes[16] = {0};
67 const unsigned char ones[16] =
68 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
69 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
70
71 static const char *state_file = DAEMON_VTY_DIR "/babel-state";
72
73 unsigned char protocol_group[16]; /* babel's link-local multicast address */
74 int protocol_port; /* babel's port */
75 int protocol_socket = -1; /* socket: communicate with others babeld */
76
77 static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
78 static char *babel_vty_addr = NULL;
79 static int babel_vty_port = BABEL_VTY_PORT;
80
81 /* babeld privileges */
82 static zebra_capabilities_t _caps_p [] =
83 {
84 ZCAP_NET_RAW,
85 ZCAP_BIND
86 };
87
88 struct zebra_privs_t babeld_privs =
89 {
90 #if defined(FRR_USER)
91 .user = FRR_USER,
92 #endif
93 #if defined FRR_GROUP
94 .group = FRR_GROUP,
95 #endif
96 #ifdef VTY_GROUP
97 .vty_group = VTY_GROUP,
98 #endif
99 .caps_p = _caps_p,
100 .cap_num_p = array_size(_caps_p),
101 .cap_num_i = 0
102 };
103
104 static void
105 babel_sigexit(void)
106 {
107 zlog_notice("Terminating on signal");
108
109 babel_exit_properly();
110 }
111
112 static void
113 babel_sigusr1 (void)
114 {
115 zlog_rotate ();
116 }
117
118 static struct quagga_signal_t babel_signals[] =
119 {
120 {
121 .signal = SIGUSR1,
122 .handler = &babel_sigusr1,
123 },
124 {
125 .signal = SIGINT,
126 .handler = &babel_sigexit,
127 },
128 {
129 .signal = SIGTERM,
130 .handler = &babel_sigexit,
131 },
132 };
133
134 struct option longopts[] =
135 {
136 { 0 }
137 };
138
139 FRR_DAEMON_INFO(babeld, BABELD,
140 .vty_port = BABEL_VTY_PORT,
141 .proghelp = "Implementation of the BABEL routing protocol.",
142
143 .signals = babel_signals,
144 .n_signals = array_size(babel_signals),
145
146 .privs = &babeld_privs,
147 )
148
149 int
150 main(int argc, char **argv)
151 {
152 int rc;
153
154 frr_preinit (&babeld_di, argc, argv);
155 frr_opt_add ("", longopts, "");
156
157 babel_init_random();
158
159 /* set the Babel's default link-local multicast address and Babel's port */
160 parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
161 protocol_port = 6696;
162
163 /* get options */
164 while(1) {
165 int opt;
166
167 opt = frr_getopt (argc, argv, NULL);
168
169 if (opt == EOF)
170 break;
171
172 switch (opt)
173 {
174 case 0:
175 break;
176 default:
177 frr_help_exit (1);
178 break;
179 }
180 }
181
182 /* create the threads handler */
183 master = frr_init ();
184
185 /* Library inits. */
186 babel_error_init();
187 zprivs_init (&babeld_privs);
188 cmd_init (1);
189 vty_init (master);
190
191 resend_delay = BABEL_DEFAULT_RESEND_DELAY;
192 change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
193
194 babel_replace_by_null(STDIN_FILENO);
195
196 /* init some quagga's dependencies, and babeld's commands */
197 babeld_quagga_init();
198 /* init zebra client's structure and it's commands */
199 /* this replace kernel_setup && kernel_setup_socket */
200 babelz_zebra_init ();
201
202 /* init buffer */
203 rc = resize_receive_buffer(1500);
204 if(rc < 0)
205 babel_fail();
206
207 schedule_neighbours_check(5000, 1);
208
209 frr_config_fork();
210 frr_run(master);
211
212 return 0;
213 }
214
215 static void
216 babel_fail(void)
217 {
218 exit(1);
219 }
220
221 /* initialize random value, and set 'babel_now' by the way. */
222 static void
223 babel_init_random(void)
224 {
225 gettime(&babel_now);
226 int rc;
227 unsigned int seed;
228
229 rc = read_random_bytes(&seed, sizeof(seed));
230 if(rc < 0) {
231 zlog_ferr(LIB_ERR_SYSTEM_CALL, "read(random): %s",
232 safe_strerror(errno));
233 seed = 42;
234 }
235
236 seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
237 srandom(seed);
238 }
239
240 /*
241 close fd, and replace it by "/dev/null"
242 exit if error
243 */
244 static void
245 babel_replace_by_null(int fd)
246 {
247 int fd_null;
248 int rc;
249
250 fd_null = open("/dev/null", O_RDONLY);
251 if(fd_null < 0) {
252 zlog_ferr(LIB_ERR_SYSTEM_CALL, "open(null): %s", safe_strerror(errno));
253 exit(1);
254 }
255
256 rc = dup2(fd_null, fd);
257 if(rc < 0) {
258 zlog_ferr(LIB_ERR_SYSTEM_CALL, "dup2(null, 0): %s",
259 safe_strerror(errno));
260 exit(1);
261 }
262
263 close(fd_null);
264 }
265
266 /*
267 Load the state file: check last babeld's running state, usefull in case of
268 "/etc/init.d/babeld restart"
269 */
270 void
271 babel_load_state_file(void)
272 {
273 int fd;
274 int rc;
275
276 fd = open(state_file, O_RDONLY);
277 if(fd < 0 && errno != ENOENT)
278 zlog_ferr(LIB_ERR_SYSTEM_CALL, "open(babel-state: %s)",
279 safe_strerror(errno));
280 rc = unlink(state_file);
281 if(fd >= 0 && rc < 0) {
282 zlog_ferr(LIB_ERR_SYSTEM_CALL, "unlink(babel-state): %s",
283 safe_strerror(errno));
284 /* If we couldn't unlink it, it's probably stale. */
285 goto fini;
286 }
287 if(fd >= 0) {
288 char buf[100];
289 char buf2[100];
290 int s;
291 long t;
292 rc = read(fd, buf, 99);
293 if(rc < 0) {
294 zlog_ferr(LIB_ERR_SYSTEM_CALL, "read(babel-state): %s",
295 safe_strerror(errno));
296 } else {
297 buf[rc] = '\0';
298 rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
299 if(rc == 3 && s >= 0 && s <= 0xFFFF) {
300 unsigned char sid[8];
301 rc = parse_eui64(buf2, sid);
302 if(rc < 0) {
303 zlog_err("Couldn't parse babel-state.");
304 } else {
305 struct timeval realnow;
306 debugf(BABEL_DEBUG_COMMON,
307 "Got %s %d %ld from babel-state.",
308 format_eui64(sid), s, t);
309 gettimeofday(&realnow, NULL);
310 if(memcmp(sid, myid, 8) == 0)
311 myseqno = seqno_plus(s, 1);
312 else
313 zlog_err("ID mismatch in babel-state. id=%s; old=%s",
314 format_eui64(myid),
315 format_eui64(sid));
316 }
317 } else {
318 zlog_err("Couldn't parse babel-state.");
319 }
320 }
321 goto fini;
322 }
323 fini:
324 if (fd >= 0)
325 close(fd);
326 return ;
327 }
328
329 static void
330 babel_exit_properly(void)
331 {
332 debugf(BABEL_DEBUG_COMMON, "Exiting...");
333 usleep(roughly(10000));
334 gettime(&babel_now);
335
336 /* Uninstall and flush all routes. */
337 debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
338 flush_all_routes();
339 babel_interface_close_all();
340 babel_zebra_close_connexion();
341 babel_save_state_file();
342 debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
343 debugf(BABEL_DEBUG_COMMON, "Done.");
344 frr_fini();
345
346 exit(0);
347 }
348
349 static void
350 babel_save_state_file(void)
351 {
352 int fd;
353 int rc;
354
355 debugf(BABEL_DEBUG_COMMON, "Save state file.");
356 fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
357 if(fd < 0) {
358 zlog_ferr(LIB_ERR_SYSTEM_CALL, "creat(babel-state): %s",
359 safe_strerror(errno));
360 unlink(state_file);
361 } else {
362 struct timeval realnow;
363 char buf[100];
364 gettimeofday(&realnow, NULL);
365 rc = snprintf(buf, 100, "%s %d %ld\n",
366 format_eui64(myid), (int)myseqno,
367 (long)realnow.tv_sec);
368 if(rc < 0 || rc >= 100) {
369 zlog_err("write(babel-state): overflow.");
370 unlink(state_file);
371 } else {
372 rc = write(fd, buf, rc);
373 if(rc < 0) {
374 zlog_err("write(babel-state): %s", safe_strerror(errno));
375 unlink(state_file);
376 }
377 fsync(fd);
378 }
379 close(fd);
380 }
381 }
382
383 void
384 show_babel_main_configuration (struct vty *vty)
385 {
386 vty_out (vty,
387 "state file = %s\n"
388 "configuration file = %s\n"
389 "protocol informations:\n"
390 " multicast address = %s\n"
391 " port = %d\n"
392 "vty address = %s\n"
393 "vty port = %d\n"
394 "id = %s\n"
395 "kernel_metric = %d\n",
396 state_file,
397 babeld_di.config_file ? babeld_di.config_file : babel_config_default,
398 format_address(protocol_group),
399 protocol_port,
400 babel_vty_addr ? babel_vty_addr : "None",
401 babel_vty_port,
402 format_eui64(myid),
403 kernel_metric);
404 }