-/*
- * This file is free software: you may copy, redistribute and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 2 of the License, or (at your
- * option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *
-
+/*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
#include "command.h"
#include "prefix.h"
#include "memory.h"
-#include "memtypes.h"
#include "table.h"
#include "distribute.h"
#include "prefix.h"
#include "filter.h"
#include "plist.h"
+#include "lib_errors.h"
#include "babel_main.h"
#include "babeld.h"
#include "message.h"
#include "resend.h"
#include "babel_filter.h"
-
+#include "babel_zebra.h"
+#include "babel_memory.h"
+#include "babel_errors.h"
static int babel_init_routing_process(struct thread *thread);
static void babel_get_myid(void);
static int
babel_config_write (struct vty *vty)
{
- return 0;
+ int lines = 0;
+ int afi;
+ int i;
+
+ /* list enabled debug modes */
+ lines += debug_babel_config_write (vty);
+
+ if (!babel_routing_process)
+ return lines;
+ vty_out (vty, "router babel\n");
+ if (diversity_kind != DIVERSITY_NONE)
+ {
+ vty_out (vty, " babel diversity\n");
+ lines++;
+ }
+ if (diversity_factor != BABEL_DEFAULT_DIVERSITY_FACTOR)
+ {
+ vty_out (vty, " babel diversity-factor %d\n",diversity_factor);
+ lines++;
+ }
+ if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
+ {
+ vty_out (vty, " babel resend-delay %u\n", resend_delay);
+ lines++;
+ }
+ if (smoothing_half_life != BABEL_DEFAULT_SMOOTHING_HALF_LIFE)
+ {
+ vty_out (vty, " babel smoothing-half-life %u\n",
+ smoothing_half_life);
+ lines++;
+ }
+ /* list enabled interfaces */
+ lines = 1 + babel_enable_if_config_write (vty);
+ /* list redistributed protocols */
+ for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+ if (i != zclient->redist_default &&
+ vrf_bitmap_check (zclient->redist[afi][i], VRF_DEFAULT)) {
+ vty_out (vty, " redistribute %s %s\n",
+ (afi == AFI_IP) ? "ipv4" : "ipv6",
+ zebra_route_string(i));
+ lines++;
+ }
+ }
+ }
+
+ lines += config_write_distribute (vty);
+
+ return lines;
}
/* Make socket for Babel protocol. */
protocol_socket = babel_socket(protocol_port);
if (protocol_socket < 0) {
- zlog_err("Couldn't create link local socket: %s", safe_strerror(errno));
+ zlog_ferr(LIB_ERR_SOCKET, "Couldn't create link local socket: %s",
+ safe_strerror(errno));
goto fail;
}
/* Threads. */
- babel_routing_process->t_read =
- thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
+ thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
/* wait a little: zebra will announce interfaces, addresses, routes... */
- babel_routing_process->t_update =
- thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L);
+ thread_add_timer_msec(master, babel_init_routing_process, NULL, 200L, &babel_routing_process->t_update);
return 0;
fail:
babel_read_protocol (struct thread *thread)
{
int rc;
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp = NULL;
struct sockaddr_in6 sin6;
- struct listnode *linklist_node = NULL;
assert(babel_routing_process != NULL);
assert(protocol_socket >= 0);
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0) {
if(errno != EAGAIN && errno != EINTR) {
- zlog_err("recv: %s", safe_strerror(errno));
+ zlog_ferr(LIB_ERR_SOCKET, "recv: %s", safe_strerror(errno));
}
} else {
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
if(!if_up(ifp))
continue;
- if(ifp->ifindex == sin6.sin6_scope_id) {
+ if(ifp->ifindex == (ifindex_t)sin6.sin6_scope_id) {
parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
receive_buffer, rc);
break;
}
/* re-add thread */
- babel_routing_process->t_read =
- thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
+ thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
return 0;
}
static void
babel_get_myid(void)
{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp = NULL;
- struct listnode *linklist_node = NULL;
int rc;
int i;
return;
}
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
/* ifp->ifindex is not necessarily valid at this point */
int ifindex = if_nametoindex(ifp->name);
if(ifindex > 0) {
unsigned char eui[8];
- rc = if_eui64(ifp->name, ifindex, eui);
+ rc = if_eui64(ifindex, eui);
if(rc < 0)
continue;
memcpy(myid, eui, 8);
ifname = if_indextoname(i, buf);
if(ifname == NULL)
continue;
- rc = if_eui64(ifname, i, eui);
+ rc = if_eui64(i, eui);
if(rc < 0)
continue;
memcpy(myid, eui, 8);
return;
}
- zlog_err("Warning: couldn't find router id -- using random value.");
+ zlog_ferr(BABEL_ERR_CONFIG,
+ "Warning: couldn't find router id -- using random value.");
rc = read_random_bytes(myid, 8);
if(rc < 0) {
- zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno));
+ zlog_ferr(BABEL_ERR_CONFIG, "read(random): %s (cannot assign an ID)",
+ safe_strerror(errno));
exit(1);
}
/* Clear group and global bits */
static void
babel_initial_noise(void)
{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp = NULL;
- struct listnode *linklist_node = NULL;
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
if(!if_up(ifp))
continue;
/* Apply jitter before we send the first message. */
send_wildcard_retraction(ifp);
}
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
if(!if_up(ifp))
continue;
usleep(roughly(10000));
babel_main_loop(struct thread *thread)
{
struct timeval tv;
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp = NULL;
- struct listnode *linklist_node = NULL;
while(1) {
gettime(&babel_now);
/* if there is no timeout, we must wait. */
if(timeval_compare(&tv, &babel_now) > 0) {
timeval_minus(&tv, &tv, &babel_now);
- debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs",
- tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs",
+ (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000);
/* it happens often to have less than 1 ms, it's bad. */
timeval_add_msec(&tv, &tv, 300);
babel_set_timer(&tv);
if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
int msecs;
msecs = check_neighbours();
- msecs = MAX(msecs, 10);
+ /* Multiply by 3/2 to allow neighbours to expire. */
+ msecs = MAX(3 * msecs / 2, 10);
schedule_neighbours_check(msecs, 1);
}
source_expiry_time = babel_now.tv_sec + roughly(300);
}
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
babel_interface_nfo *babel_ifp = NULL;
if(!if_up(ifp))
continue;
flush_unicast(1);
}
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
babel_interface_nfo *babel_ifp = NULL;
if(!if_up(ifp))
continue;
#define printIfMin(a,b,c,d) \
if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp = NULL;
- struct listnode *linklist_node = NULL;
*tv = check_neighbours_timeout;
printIfMin(tv, 0, "check_neighbours_timeout", NULL);
printIfMin(tv, 1, "source_expiry_time", NULL);
timeval_min(tv, &resend_time);
printIfMin(tv, 1, "resend_time", NULL);
- FOR_ALL_INTERFACES(ifp, linklist_node) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
babel_interface_nfo *babel_ifp = NULL;
if(!if_up(ifp))
continue;
if (babel_routing_process->t_update != NULL) {
thread_cancel(babel_routing_process->t_update);
}
- babel_routing_process->t_update =
- thread_add_timer_msec(master, &babel_main_loop, NULL, msecs);
+ thread_add_timer_msec(master, babel_main_loop, NULL, msecs, &babel_routing_process->t_update);
}
-/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */
void
schedule_neighbours_check(int msecs, int override)
{
struct timeval timeout;
- timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2));
+ timeval_add_msec(&timeout, &babel_now, msecs);
if(override)
check_neighbours_timeout = timeout;
else
if(receive_buffer == NULL) {
receive_buffer = malloc(size);
if(receive_buffer == NULL) {
- zlog_err("malloc(receive_buffer): %s", safe_strerror(errno));
+ zlog_ferr(BABEL_ERR_MEMORY, "malloc(receive_buffer): %s",
+ safe_strerror(errno));
return -1;
}
receive_buffer_size = size;
unsigned char *new;
new = realloc(receive_buffer, size);
if(new == NULL) {
- zlog_err("realloc(receive_buffer): %s", safe_strerror(errno));
+ zlog_ferr(BABEL_ERR_MEMORY, "realloc(receive_buffer): %s",
+ safe_strerror(errno));
return -1;
}
receive_buffer = new;
{
struct interface *ifp;
babel_interface_nfo *babel_ifp;
- struct access_list *alist;
- struct prefix_list *plist;
+ int type;
+ int family;
if (! dist->ifname)
return;
- ifp = if_lookup_by_name (dist->ifname);
+ ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
if (ifp == NULL)
return;
babel_ifp = babel_get_if_nfo(ifp);
- if (dist->list[DISTRIBUTE_IN]) {
- alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
- if (alist)
- babel_ifp->list[BABEL_FILTER_IN] = alist;
+ for (type = 0; type < DISTRIBUTE_MAX; type++) {
+ family = type == DISTRIBUTE_V4_IN || type == DISTRIBUTE_V4_OUT ?
+ AFI_IP : AFI_IP6;
+ if (dist->list[type])
+ babel_ifp->list[type] = access_list_lookup (family,
+ dist->list[type]);
else
- babel_ifp->list[BABEL_FILTER_IN] = NULL;
- } else {
- babel_ifp->list[BABEL_FILTER_IN] = NULL;
- }
-
- if (dist->list[DISTRIBUTE_OUT]) {
- alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
- if (alist)
- babel_ifp->list[BABEL_FILTER_OUT] = alist;
- else
- babel_ifp->list[BABEL_FILTER_OUT] = NULL;
- } else {
- babel_ifp->list[BABEL_FILTER_OUT] = NULL;
- }
-
- if (dist->prefix[DISTRIBUTE_IN]) {
- plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
- if (plist)
- babel_ifp->prefix[BABEL_FILTER_IN] = plist;
+ babel_ifp->list[type] = NULL;
+ if (dist->prefix[type])
+ babel_ifp->prefix[type] = prefix_list_lookup (family,
+ dist->prefix[type]);
else
- babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
- } else {
- babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
- }
-
- if (dist->prefix[DISTRIBUTE_OUT]) {
- plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
- if (plist)
- babel_ifp->prefix[BABEL_FILTER_OUT] = plist;
- else
- babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
- } else {
- babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
+ babel_ifp->prefix[type] = NULL;
}
}
static void
babel_distribute_update_all (struct prefix_list *notused)
{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct interface *ifp;
- struct listnode *node;
- for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+ FOR_ALL_INTERFACES (vrf, ifp)
babel_distribute_update_interface (ifp);
}
/* [Command] */
-DEFUN (router_babel,
- router_babel_cmd,
- "router babel",
- "Enable a routing process\n"
- "Make Babel instance command\n"
- "No attributes\n")
+DEFUN_NOSH (router_babel,
+ router_babel_cmd,
+ "router babel",
+ "Enable a routing process\n"
+ "Make Babel instance command\n")
{
int ret;
"no router babel",
NO_STR
"Disable a routing process\n"
- "Remove Babel instance command\n"
- "No attributes\n")
+ "Remove Babel instance command\n")
{
if(babel_routing_process)
babel_clean_routing_process();
return CMD_SUCCESS;
}
+/* [Babel Command] */
+DEFUN (babel_diversity,
+ babel_diversity_cmd,
+ "babel diversity",
+ "Babel commands\n"
+ "Enable diversity-aware routing.\n")
+{
+ diversity_kind = DIVERSITY_CHANNEL;
+ return CMD_SUCCESS;
+}
+
+/* [Babel Command] */
+DEFUN (no_babel_diversity,
+ no_babel_diversity_cmd,
+ "no babel diversity",
+ NO_STR
+ "Babel commands\n"
+ "Disable diversity-aware routing.\n")
+{
+ diversity_kind = DIVERSITY_NONE;
+ return CMD_SUCCESS;
+}
+
+/* [Babel Command] */
+DEFUN (babel_diversity_factor,
+ babel_diversity_factor_cmd,
+ "babel diversity-factor (1-256)",
+ "Babel commands\n"
+ "Set the diversity factor.\n"
+ "Factor in units of 1/256.\n")
+{
+ int factor;
+
+ factor = strtoul(argv[2]->arg, NULL, 10);
+
+ diversity_factor = factor;
+ return CMD_SUCCESS;
+}
+
/* [Babel Command] */
DEFUN (babel_set_resend_delay,
babel_set_resend_delay_cmd,
- "babel resend-delay <20-655340>",
+ "babel resend-delay (20-655340)",
"Babel commands\n"
"Time before resending a message\n"
"Milliseconds\n")
{
int interval;
- VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
+ interval = strtoul(argv[2]->arg, NULL, 10);
resend_delay = interval;
return CMD_SUCCESS;
}
+/* [Babel Command] */
+DEFUN (babel_set_smoothing_half_life,
+ babel_set_smoothing_half_life_cmd,
+ "babel smoothing-half-life (0-65534)",
+ "Babel commands\n"
+ "Smoothing half-life\n"
+ "Seconds (0 to disable)\n")
+{
+ int seconds;
+
+ seconds = strtoul(argv[2]->arg, NULL, 10);
+
+ change_smoothing_half_life(seconds);
+ return CMD_SUCCESS;
+}
+
void
babeld_quagga_init(void)
{
install_element(CONFIG_NODE, &no_router_babel_cmd);
install_default(BABEL_NODE);
+ install_element(BABEL_NODE, &babel_diversity_cmd);
+ install_element(BABEL_NODE, &no_babel_diversity_cmd);
+ install_element(BABEL_NODE, &babel_diversity_factor_cmd);
install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
+ install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd);
babel_if_init();
return 0;
}
-void
-show_babeld_configuration (struct vty *vty)
-{
- vty_out(vty, "babeld running process %s.%s",
- babel_routing_process ? "enable" : "disable", VTY_NEWLINE);
-}