1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
// 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);
}
}
|