frr/babeld/source.c

153 lines
3.4 KiB
C

// SPDX-License-Identifier: MIT
/*
Copyright (c) 2007, 2008 by Juliusz Chroboczek
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "babel_main.h"
#include "babeld.h"
#include "util.h"
#include "source.h"
#include "babel_interface.h"
#include "route.h"
#include "babel_errors.h"
struct source *srcs = NULL;
struct source*
find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
int create, unsigned short seqno)
{
struct source *src;
for(src = srcs; src; src = src->next) {
/* This should really be a hash table. For now, check the
last byte first. */
if(src->id[7] != id[7])
continue;
if(memcmp(src->id, id, 8) != 0)
continue;
if(src->plen != plen)
continue;
if(memcmp(src->prefix, p, 16) == 0)
return src;
}
if(!create)
return NULL;
src = malloc(sizeof(struct source));
if(src == NULL) {
flog_err(EC_BABEL_MEMORY, "malloc(source): %s", safe_strerror(errno));
return NULL;
}
memcpy(src->id, id, 8);
memcpy(src->prefix, p, 16);
src->plen = plen;
src->seqno = seqno;
src->metric = INFINITY;
src->time = babel_now.tv_sec;
src->route_count = 0;
src->next = srcs;
srcs = src;
return src;
}
struct source *
retain_source(struct source *src)
{
assert(src->route_count < 0xffff);
src->route_count++;
return src;
}
void
release_source(struct source *src)
{
assert(src->route_count > 0);
src->route_count--;
}
int
flush_source(struct source *src)
{
if(src->route_count > 0)
/* The source is in use by a route. */
return 0;
if(srcs == src) {
srcs = src->next;
} else {
struct source *previous = srcs;
while(previous->next != src)
previous = previous->next;
previous->next = src->next;
}
free(src);
return 1;
}
void
update_source(struct source *src,
unsigned short seqno, unsigned short metric)
{
if(metric >= INFINITY)
return;
/* If a source is expired, pretend that it doesn't exist and update
it unconditionally. This makes ensures that old data will
eventually be overridden, and prevents us from getting stuck if
a router loses its sequence number. */
if(src->time < babel_now.tv_sec - SOURCE_GC_TIME ||
seqno_compare(src->seqno, seqno) < 0 ||
(src->seqno == seqno && src->metric > metric)) {
src->seqno = seqno;
src->metric = metric;
}
src->time = babel_now.tv_sec;
}
void
expire_sources(void)
{
struct source *src;
src = srcs;
while(src) {
if(src->time > babel_now.tv_sec)
/* clock stepped */
src->time = babel_now.tv_sec;
if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) {
struct source *old = src;
src = src->next;
flush_source(old);
continue;
}
src = src->next;
}
}
void
check_sources_released(void)
{
struct source *src;
for(src = srcs; src; src = src->next) {
if(src->route_count != 0)
fprintf(stderr, "Warning: source %s %s has refcount %d.\n",
format_eui64(src->id),
format_prefix(src->prefix, src->plen),
(int)src->route_count);
}
}