]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babel_main.c
*: Initial Import of Babeld into FRR
[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
37 #include "babel_main.h"
38 #include "babeld.h"
39 #include "util.h"
40 #include "kernel.h"
41 #include "babel_interface.h"
42 #include "neighbour.h"
43 #include "route.h"
44 #include "xroute.h"
45 #include "message.h"
46 #include "resend.h"
47 #include "babel_zebra.h"
48
49
50 static void babel_init (int argc, char **argv);
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_config_file = NULL;
79 static char *babel_vty_addr = NULL;
80 static int babel_vty_port = BABEL_VTY_PORT;
81
82 /* babeld privileges */
83 static zebra_capabilities_t _caps_p [] =
84 {
85 ZCAP_NET_RAW,
86 ZCAP_BIND
87 };
88 static struct zebra_privs_t babeld_privs =
89 {
90 #if defined(QUAGGA_USER)
91 .user = QUAGGA_USER,
92 #endif
93 #if defined QUAGGA_GROUP
94 .group = QUAGGA_GROUP,
95 #endif
96 #ifdef VTY_GROUP
97 .vty_group = VTY_GROUP,
98 #endif
99 .caps_p = _caps_p,
100 .cap_num_p = 2,
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 struct thread thread;
153 /* and print banner too */
154 babel_init(argc, argv);
155 while (thread_fetch (master, &thread)) {
156 thread_call (&thread);
157 }
158 return 0;
159 }
160
161 /* make initialisations witch don't need infos about kernel(interfaces, etc.) */
162 static void
163 babel_init(int argc, char **argv)
164 {
165 int rc;
166
167 frr_preinit (&babeld_di, argc, argv);
168 frr_opt_add ("", longopts, "");
169
170 babel_init_random();
171
172 /* set the Babel's default link-local multicast address and Babel's port */
173 parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
174 protocol_port = 6696;
175
176 /* get options */
177 while(1) {
178 int opt;
179
180 opt = frr_getopt (argc, argv, NULL);
181
182 if (opt == EOF)
183 break;
184
185 switch (opt)
186 {
187 case 0:
188 break;
189 default:
190 frr_help_exit (1);
191 break;
192 }
193 }
194
195 /* create the threads handler */
196 master = thread_master_create ();
197
198 /* Library inits. */
199 zprivs_init (&babeld_privs);
200 cmd_init (1);
201 vty_init (master);
202
203 resend_delay = BABEL_DEFAULT_RESEND_DELAY;
204 change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
205
206 babel_replace_by_null(STDIN_FILENO);
207
208 /* init some quagga's dependencies, and babeld's commands */
209 babeld_quagga_init();
210 /* init zebra client's structure and it's commands */
211 /* this replace kernel_setup && kernel_setup_socket */
212 babelz_zebra_init ();
213
214 /* Get zebra configuration file. */
215 vty_read_config (babel_config_file, babel_config_default);
216
217 /* init buffer */
218 rc = resize_receive_buffer(1500);
219 if(rc < 0)
220 babel_fail();
221
222 schedule_neighbours_check(5000, 1);
223
224 zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port);
225 }
226
227 static void
228 babel_fail(void)
229 {
230 exit(1);
231 }
232
233 /* initialize random value, and set 'babel_now' by the way. */
234 static void
235 babel_init_random(void)
236 {
237 gettime(&babel_now);
238 int rc;
239 unsigned int seed;
240
241 rc = read_random_bytes(&seed, sizeof(seed));
242 if(rc < 0) {
243 zlog_err("read(random): %s", safe_strerror(errno));
244 seed = 42;
245 }
246
247 seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
248 srandom(seed);
249 }
250
251 /*
252 close fd, and replace it by "/dev/null"
253 exit if error
254 */
255 static void
256 babel_replace_by_null(int fd)
257 {
258 int fd_null;
259 int rc;
260
261 fd_null = open("/dev/null", O_RDONLY);
262 if(fd_null < 0) {
263 zlog_err("open(null): %s", safe_strerror(errno));
264 exit(1);
265 }
266
267 rc = dup2(fd_null, fd);
268 if(rc < 0) {
269 zlog_err("dup2(null, 0): %s", safe_strerror(errno));
270 exit(1);
271 }
272
273 close(fd_null);
274 }
275
276 /*
277 Load the state file: check last babeld's running state, usefull in case of
278 "/etc/init.d/babeld restart"
279 */
280 void
281 babel_load_state_file(void)
282 {
283 int fd;
284 int rc;
285
286 fd = open(state_file, O_RDONLY);
287 if(fd < 0 && errno != ENOENT)
288 zlog_err("open(babel-state: %s)", safe_strerror(errno));
289 rc = unlink(state_file);
290 if(fd >= 0 && rc < 0) {
291 zlog_err("unlink(babel-state): %s", safe_strerror(errno));
292 /* If we couldn't unlink it, it's probably stale. */
293 close(fd);
294 fd = -1;
295 }
296 if(fd >= 0) {
297 char buf[100];
298 char buf2[100];
299 int s;
300 long t;
301 rc = read(fd, buf, 99);
302 if(rc < 0) {
303 zlog_err("read(babel-state): %s", safe_strerror(errno));
304 } else {
305 buf[rc] = '\0';
306 rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
307 if(rc == 3 && s >= 0 && s <= 0xFFFF) {
308 unsigned char sid[8];
309 rc = parse_eui64(buf2, sid);
310 if(rc < 0) {
311 zlog_err("Couldn't parse babel-state.");
312 } else {
313 struct timeval realnow;
314 debugf(BABEL_DEBUG_COMMON,
315 "Got %s %d %ld from babel-state.",
316 format_eui64(sid), s, t);
317 gettimeofday(&realnow, NULL);
318 if(memcmp(sid, myid, 8) == 0)
319 myseqno = seqno_plus(s, 1);
320 else
321 zlog_err("ID mismatch in babel-state. id=%s; old=%s",
322 format_eui64(myid),
323 format_eui64(sid));
324 }
325 } else {
326 zlog_err("Couldn't parse babel-state.");
327 }
328 }
329 close(fd);
330 fd = -1;
331 }
332 }
333
334 static void
335 babel_exit_properly(void)
336 {
337 debugf(BABEL_DEBUG_COMMON, "Exiting...");
338 usleep(roughly(10000));
339 gettime(&babel_now);
340
341 /* Uninstall and flush all routes. */
342 debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
343 flush_all_routes();
344 babel_interface_close_all();
345 babel_zebra_close_connexion();
346 babel_save_state_file();
347 debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
348 debugf(BABEL_DEBUG_COMMON, "Done.");
349
350 exit(0);
351 }
352
353 static void
354 babel_save_state_file(void)
355 {
356 int fd;
357 int rc;
358
359 debugf(BABEL_DEBUG_COMMON, "Save state file.");
360 fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
361 if(fd < 0) {
362 zlog_err("creat(babel-state): %s", safe_strerror(errno));
363 unlink(state_file);
364 } else {
365 struct timeval realnow;
366 char buf[100];
367 gettimeofday(&realnow, NULL);
368 rc = snprintf(buf, 100, "%s %d %ld\n",
369 format_eui64(myid), (int)myseqno,
370 (long)realnow.tv_sec);
371 if(rc < 0 || rc >= 100) {
372 zlog_err("write(babel-state): overflow.");
373 unlink(state_file);
374 } else {
375 rc = write(fd, buf, rc);
376 if(rc < 0) {
377 zlog_err("write(babel-state): %s", safe_strerror(errno));
378 unlink(state_file);
379 }
380 fsync(fd);
381 }
382 close(fd);
383 }
384 }
385
386 void
387 show_babel_main_configuration (struct vty *vty)
388 {
389 vty_out(vty,
390 "state file = %s%s"
391 "configuration file = %s%s"
392 "protocol informations:%s"
393 " multicast address = %s%s"
394 " port = %d%s"
395 "vty address = %s%s"
396 "vty port = %d%s"
397 "id = %s%s"
398 "kernel_metric = %d%s",
399 state_file, VTY_NEWLINE,
400 babel_config_file ? babel_config_file : babel_config_default,
401 VTY_NEWLINE,
402 VTY_NEWLINE,
403 format_address(protocol_group), VTY_NEWLINE,
404 protocol_port, VTY_NEWLINE,
405 babel_vty_addr ? babel_vty_addr : "None",
406 VTY_NEWLINE,
407 babel_vty_port, VTY_NEWLINE,
408 format_eui64(myid), VTY_NEWLINE,
409 kernel_metric, VTY_NEWLINE);
410 }