// SPDX-License-Identifier: MIT /* Copyright (c) 2007, 2008 by Juliusz Chroboczek */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #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); } }