json_t *jlogthres = NULL;
json_t *jcfgpoll = NULL;
json_t *jcfgsettle = NULL;
+ json_t *jroutesweep = NULL;
if ((!trc) || (!jcfg))
return TR_CFG_BAD_PARAMS;
return TR_CFG_NOPARSE;
}
}
+ if (NULL != (jroutesweep = json_object_get(jint, "route_sweep_interval"))) {
+ if (json_is_number(jroutesweep)) {
+ trc->internal->route_sweep_interval = json_integer_value(jroutesweep);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, route_sweep_interval is not a number.");
+ return TR_CFG_NOPARSE;
+ }
+ }
if (NULL != (jlog = json_object_get(jint, "logging"))) {
if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) {
int console_threshold;
unsigned int cfg_poll_interval;
unsigned int cfg_settle_count;
+ unsigned int route_sweep_interval;
} TR_CFG_INTERNAL;
typedef struct tr_cfg {
typedef struct tr_trps_events {
struct tr_socket_event *listen_ev;
struct event *mq_ev;
+ struct event *sweep_ev;
} TR_TRPS_EVENTS;
/* prototypes */
TRP_RENTRY *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer);
TRP_RENTRY *trps_get_selected_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
TR_NAME *trps_get_next_hop(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
+TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps);
#endif /* TRP_INTERNAL_H */
TR_NAME *trust_router;
TR_NAME *next_hop;
int selected;
+ unsigned int interval; /* interval from route update */
struct timespec *expiry;
} TRP_RENTRY;
TR_NAME *trp_rentry_get_next_hop(TRP_RENTRY *entry);
void trp_rentry_set_selected(TRP_RENTRY *entry, int sel);
int trp_rentry_get_selected(TRP_RENTRY *entry);
+void trp_rentry_set_interval(TRP_RENTRY *entry, int interval);
+int trp_rentry_get_interval(TRP_RENTRY *entry);
void trp_rentry_set_expiry(TRP_RENTRY *entry, struct timespec *exp);
TRP_RENTRY *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm);
struct timespec *trp_rentry_get_expiry(TRP_RENTRY *entry);
#include <errno.h>
#include <unistd.h>
#include <string.h>
+#include <sys/time.h>
#include <gsscon.h>
#include <tr_rp.h>
}
}
+static void tr_trps_sweep(int listener, short event, void *arg)
+{
+ TRPS_INSTANCE *trps=talloc_get_type_abort(arg, TRPS_INSTANCE);
+ tr_debug("tr_trps_sweep: sweeping routes");
+ trps_sweep_routes(trps);
+}
+
static int tr_trps_events_destructor(void *obj)
{
TR_TRPS_EVENTS *ev=talloc_get_type_abort(obj, TR_TRPS_EVENTS);
if (ev->mq_ev!=NULL)
event_free(ev->mq_ev);
+ if (ev->sweep_ev!=NULL)
+ event_free(ev->sweep_ev);
return 0;
}
TR_TRPS_EVENTS *tr_trps_events_new(TALLOC_CTX *mem_ctx)
if (ev!=NULL) {
ev->listen_ev=talloc(ev, struct tr_socket_event);
ev->mq_ev=NULL;
+ ev->sweep_ev=NULL;
if (ev->listen_ev==NULL) {
talloc_free(ev);
ev=NULL;
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
struct tr_socket_event *listen_ev=NULL;
struct tr_trps_event_cookie *cookie;
+ struct timeval two_secs={2, 0};
TRP_RC retval=TRP_ERROR;
if (trps_ev == NULL) {
(void *)trps);
tr_mq_set_notify_cb(trps->mq, tr_trps_mq_cb, trps_ev->mq_ev);
+ /* now set up the route table sweep timer event */
+ trps_ev->sweep_ev=event_new(base, -1, EV_TIMEOUT|EV_PERSIST, tr_trps_sweep, (void *)trps);
+ /* todo: event_add(trps_ev->sweep_ev, &(cfg_mgr->active->internal->route_sweep_interval)); */
+ event_add(trps_ev->sweep_ev, &two_secs);
+
retval=TRP_SUCCESS;
cleanup:
entry->peer=NULL;
entry->next_hop=NULL;
entry->selected=0;
+ entry->interval=0;
entry->expiry=talloc(entry, struct timespec);
if (entry->expiry==NULL) {
talloc_free(entry);
return entry->selected;
}
+void trp_rentry_set_interval(TRP_RENTRY *entry, int interval)
+{
+ entry->interval=interval;
+}
+
+int trp_rentry_get_interval(TRP_RENTRY *entry)
+{
+ return entry->interval;
+}
+
/* copies incoming value, does not assume responsibility for freeing */
void trp_rentry_set_expiry(TRP_RENTRY *entry, struct timespec *exp)
{
* time unset on a new route entry. */
tr_debug("trps_accept_update: accepting route update.");
trp_rentry_set_metric(entry, trp_inforec_get_metric(rec));
+ trp_rentry_set_interval(entry, trp_inforec_get_interval(rec));
if (!trps_route_retracted(trps, entry)) {
tr_debug("trps_accept_update: route not retracted, setting expiry timer.");
trp_rentry_set_expiry(entry, trps_compute_expiry(trps,
- trp_inforec_get_interval(rec),
+ trp_rentry_get_interval(entry),
trp_rentry_get_expiry(entry)));
}
return TRP_SUCCESS;
return TRP_ERROR;
}
}
+
+/* true if curtime >= expiry */
+static int trps_expired(struct timespec *expiry, struct timespec *curtime)
+{
+ return ((curtime->tv_sec > expiry->tv_sec)
+ || ((curtime->tv_sec == expiry->tv_sec)
+ &&(curtime->tv_nsec > expiry->tv_nsec)));
+}
+
+/* Sweep for expired routes. For each expired route, if its metric is infinite, the route is flushed.
+ * If its metric is finite, the metric is set to infinite and the route's expiration time is updated. */
+TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps)
+{
+ struct timespec sweep_time={0,0};
+ TRP_RENTRY **entry=NULL;
+ size_t n_entry=0;
+ size_t ii=0;
+
+ /* use a single time for the entire sweep */
+ if (0!=clock_gettime(CLOCK_REALTIME, &sweep_time)) {
+ tr_err("trps_sweep_routes: could not read realtime clock.");
+ sweep_time.tv_sec=0;
+ sweep_time.tv_nsec=0;
+ return TRP_ERROR;
+ }
+
+ entry=trp_rtable_get_entries(trps->rtable, &n_entry); /* must talloc_free *entry */
+
+ /* loop over the entries */
+ for (ii=0; ii<n_entry; ii++) {
+ if (trps_expired(trp_rentry_get_expiry(entry[ii]), &sweep_time)) {
+ tr_debug("trps_sweep_routes: route expired.");
+ if (TRP_METRIC_INFINITY==trp_rentry_get_metric(entry[ii])) {
+ /* flush route */
+ tr_debug("trps_sweep_routes: metric was infinity, flushing route.");
+ trp_rtable_remove(trps->rtable, entry[ii]); /* entry[ii] is no longer valid */
+ entry[ii]=NULL;
+ } else {
+ /* set metric to infinity and reset timer */
+ tr_debug("trps_sweep_routes: setting metric to infinity and resetting expiry.");
+ trp_rentry_set_metric(entry[ii], TRP_METRIC_INFINITY);
+ trp_rentry_set_expiry(entry[ii], trps_compute_expiry(trps,
+ trp_rentry_get_interval(entry[ii]),
+ trp_rentry_get_expiry(entry[ii])));
+ }
+ }
+ }
+
+ talloc_free(entry);
+ return TRP_SUCCESS;
+}