frr/babeld/babel_main.c

371 lines
8.9 KiB
C

// SPDX-License-Identifier: MIT
/*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
*/
/* include zebra library */
#include <zebra.h>
#include "getopt.h"
#include "if.h"
#include "log.h"
#include "thread.h"
#include "privs.h"
#include "sigevent.h"
#include "lib/version.h"
#include "command.h"
#include "vty.h"
#include "memory.h"
#include "libfrr.h"
#include "lib_errors.h"
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "kernel.h"
#include "babel_interface.h"
#include "neighbour.h"
#include "route.h"
#include "xroute.h"
#include "message.h"
#include "resend.h"
#include "babel_zebra.h"
#include "babel_errors.h"
static void babel_fail(void);
static void babel_init_random(void);
static void babel_exit_properly(void);
static void babel_save_state_file(void);
struct thread_master *master; /* quagga's threads handler */
struct timeval babel_now; /* current time */
unsigned char myid[8]; /* unique id (mac address of an interface) */
int debug = 0;
int resend_delay = -1;
const unsigned char zeroes[16] = {0};
const unsigned char ones[16] =
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static char state_file[1024];
unsigned char protocol_group[16]; /* babel's link-local multicast address */
int protocol_port; /* babel's port */
int protocol_socket = -1; /* socket: communicate with others babeld */
static const char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
static char *babel_vty_addr = NULL;
static int babel_vty_port = BABEL_VTY_PORT;
/* babeld privileges */
static zebra_capabilities_t _caps_p [] =
{
ZCAP_NET_RAW,
ZCAP_BIND
};
struct zebra_privs_t babeld_privs =
{
#if defined(FRR_USER)
.user = FRR_USER,
#endif
#if defined FRR_GROUP
.group = FRR_GROUP,
#endif
#ifdef VTY_GROUP
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0
};
static void
babel_sigexit(void)
{
zlog_notice("Terminating on signal");
babel_exit_properly();
}
static void
babel_sigusr1 (void)
{
zlog_rotate ();
}
static struct frr_signal_t babel_signals[] =
{
{
.signal = SIGUSR1,
.handler = &babel_sigusr1,
},
{
.signal = SIGINT,
.handler = &babel_sigexit,
},
{
.signal = SIGTERM,
.handler = &babel_sigexit,
},
};
struct option longopts[] =
{
{ 0 }
};
static const struct frr_yang_module_info *const babeld_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_vrf_info,
};
FRR_DAEMON_INFO(babeld, BABELD,
.vty_port = BABEL_VTY_PORT,
.proghelp = "Implementation of the BABEL routing protocol.",
.signals = babel_signals,
.n_signals = array_size(babel_signals),
.privs = &babeld_privs,
.yang_modules = babeld_yang_modules,
.n_yang_modules = array_size(babeld_yang_modules),
);
int
main(int argc, char **argv)
{
int rc;
frr_preinit (&babeld_di, argc, argv);
frr_opt_add ("", longopts, "");
babel_init_random();
/* set the Babel's default link-local multicast address and Babel's port */
parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
protocol_port = 6696;
/* get options */
while(1) {
int opt;
opt = frr_getopt (argc, argv, NULL);
if (opt == EOF)
break;
switch (opt)
{
case 0:
break;
default:
frr_help_exit(1);
}
}
snprintf(state_file, sizeof(state_file), "%s/%s",
frr_vtydir, "babel-state");
/* create the threads handler */
master = frr_init ();
/* Library inits. */
babel_error_init();
resend_delay = BABEL_DEFAULT_RESEND_DELAY;
change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
/* init some quagga's dependencies, and babeld's commands */
if_zapi_callbacks(babel_ifp_create, babel_ifp_up,
babel_ifp_down, babel_ifp_destroy);
babeld_quagga_init();
/* init zebra client's structure and it's commands */
/* this replace kernel_setup && kernel_setup_socket */
babelz_zebra_init ();
/* init buffer */
rc = resize_receive_buffer(1500);
if(rc < 0)
babel_fail();
schedule_neighbours_check(5000, 1);
frr_config_fork();
frr_run(master);
return 0;
}
static void
babel_fail(void)
{
exit(1);
}
/* initialize random value, and set 'babel_now' by the way. */
static void
babel_init_random(void)
{
gettime(&babel_now);
int rc;
unsigned int seed;
rc = read_random_bytes(&seed, sizeof(seed));
if(rc < 0) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "read(random): %s",
safe_strerror(errno));
seed = 42;
}
seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
srandom(seed);
}
/*
Load the state file: check last babeld's running state, usefull in case of
"/etc/init.d/babeld restart"
*/
void
babel_load_state_file(void)
{
int fd;
int rc;
fd = open(state_file, O_RDONLY);
if(fd < 0 && errno != ENOENT)
flog_err_sys(EC_LIB_SYSTEM_CALL, "open(babel-state: %s)",
safe_strerror(errno));
rc = unlink(state_file);
if(fd >= 0 && rc < 0) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "unlink(babel-state): %s",
safe_strerror(errno));
/* If we couldn't unlink it, it's probably stale. */
goto fini;
}
if(fd >= 0) {
char buf[100];
char buf2[100];
int s;
long t;
rc = read(fd, buf, 99);
if(rc < 0) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "read(babel-state): %s",
safe_strerror(errno));
} else {
buf[rc] = '\0';
rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
if(rc == 3 && s >= 0 && s <= 0xFFFF) {
unsigned char sid[8];
rc = parse_eui64(buf2, sid);
if(rc < 0) {
flog_err(EC_BABEL_CONFIG, "Couldn't parse babel-state.");
} else {
struct timeval realnow;
debugf(BABEL_DEBUG_COMMON,
"Got %s %d %ld from babel-state.",
format_eui64(sid), s, t);
gettimeofday(&realnow, NULL);
if(memcmp(sid, myid, 8) == 0)
myseqno = seqno_plus(s, 1);
else
flog_err(EC_BABEL_CONFIG,
"ID mismatch in babel-state. id=%s; old=%s",
format_eui64(myid),
format_eui64(sid));
}
} else {
flog_err(EC_BABEL_CONFIG, "Couldn't parse babel-state.");
}
}
goto fini;
}
fini:
if (fd >= 0)
close(fd);
return ;
}
static void
babel_exit_properly(void)
{
debugf(BABEL_DEBUG_COMMON, "Exiting...");
usleep(roughly(10000));
gettime(&babel_now);
/* Uninstall and flush all routes. */
debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
flush_all_routes();
babel_interface_close_all();
babel_zebra_close_connexion();
babel_save_state_file();
debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
debugf(BABEL_DEBUG_COMMON, "Done.");
frr_fini();
exit(0);
}
static void
babel_save_state_file(void)
{
int fd;
int rc;
debugf(BABEL_DEBUG_COMMON, "Save state file.");
fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
if(fd < 0) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "creat(babel-state): %s",
safe_strerror(errno));
unlink(state_file);
} else {
struct timeval realnow;
char buf[100];
gettimeofday(&realnow, NULL);
rc = snprintf(buf, 100, "%s %d %ld\n",
format_eui64(myid), (int)myseqno,
(long)realnow.tv_sec);
if(rc < 0 || rc >= 100) {
flog_err(EC_BABEL_CONFIG, "write(babel-state): overflow.");
unlink(state_file);
} else {
rc = write(fd, buf, rc);
if(rc < 0) {
flog_err(EC_BABEL_CONFIG, "write(babel-state): %s",
safe_strerror(errno));
unlink(state_file);
}
fsync(fd);
}
close(fd);
}
}
void
show_babel_main_configuration (struct vty *vty)
{
vty_out (vty,
"state file = %s\n"
"configuration file = %s\n"
"protocol information:\n"
" multicast address = %s\n"
" port = %d\n"
"vty address = %s\n"
"vty port = %d\n"
"id = %s\n"
"kernel_metric = %d\n",
state_file,
babeld_di.config_file ? babeld_di.config_file : babel_config_default,
format_address(protocol_group),
protocol_port,
babel_vty_addr ? babel_vty_addr : "None",
babel_vty_port,
format_eui64(myid),
kernel_metric);
}