summaryrefslogtreecommitdiff
path: root/proto/radv/radv.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/radv/radv.c')
-rw-r--r--proto/radv/radv.c77
1 files changed, 43 insertions, 34 deletions
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index d799dab5..d53b65e3 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -55,6 +55,9 @@ radv_timer(timer *tm)
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
+ if (ifa->valid_time <= now)
+ radv_invalidate(ifa);
+
if (ifa->prune_time <= now)
radv_prune_prefixes(ifa);
@@ -117,7 +120,6 @@ static void
radv_prepare_prefixes(struct radv_iface *ifa)
{
struct radv_proto *p = ifa->ra;
- struct radv_iface_config *cf = ifa->cf;
struct radv_prefix *pfx, *next;
/* First mark all the prefixes as unused */
@@ -157,20 +159,21 @@ radv_prepare_prefixes(struct radv_iface *ifa)
* Update the information (it may have changed, or even bring a prefix back
* to life).
*/
- existing->alive = 1;
+ existing->valid = 1;
+ existing->changed = now;
existing->mark = 1;
existing->cf = pc;
}
WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
{
- if (pfx->alive && !pfx->mark)
+ if (pfx->valid && !pfx->mark)
{
RADV_TRACE(D_EVENTS, "Invalidating prefix %I/$d on %s",
pfx->prefix, pfx->len, ifa->iface->name);
- pfx->alive = 0;
- pfx->expires = now + cf->linger_time;
+ pfx->valid = 0;
+ pfx->changed = now;
pfx->cf = &dead_prefix;
}
}
@@ -181,30 +184,28 @@ radv_prune_prefixes(struct radv_iface *ifa)
{
struct radv_proto *p = ifa->ra;
bird_clock_t next = TIME_INFINITY;
- int changed = 0;
+ bird_clock_t expires = 0;
struct radv_prefix *px, *pxn;
WALK_LIST_DELSAFE(px, pxn, ifa->prefixes)
{
- if (!px->alive)
+ if (!px->valid)
{
- if (px->expires <= now)
+ expires = px->changed + ifa->cf->prefix_linger_time;
+
+ if (expires <= now)
{
RADV_TRACE(D_EVENTS, "Removing prefix %I/%d on %s",
px->prefix, px->len, ifa->iface->name);
rem_node(NODE px);
mb_free(px);
- changed = 1;
}
else
- next = MIN(next, px->expires);
+ next = MIN(next, expires);
}
}
- if (changed)
- radv_invalidate(ifa);
-
ifa->prune_time = next;
}
@@ -424,6 +425,7 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (P->cf);
struct radv_route *rt;
+ eattr *ea;
if (radv_net_match_trigger(cf, n))
{
@@ -455,9 +457,14 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
if (new)
{
/* Update */
- uint preference = ea_get_int(attrs, EA_RA_PREFERENCE, RA_PREF_MEDIUM);
- uint lifetime = ea_get_int(attrs, EA_RA_LIFETIME, 0);
- uint lifetime_set = !!ea_find(attrs, EA_RA_LIFETIME);
+
+ ea = ea_find(attrs, EA_RA_PREFERENCE);
+ uint preference = ea ? ea->u.data : RA_PREF_MEDIUM;
+ uint preference_set = !!ea;
+
+ ea = ea_find(attrs, EA_RA_LIFETIME);
+ uint lifetime = ea ? ea->u.data : 0;
+ uint lifetime_set = !!ea;
if ((preference != RA_PREF_LOW) &&
(preference != RA_PREF_MEDIUM) &&
@@ -466,6 +473,7 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
log(L_WARN "%s: Invalid ra_preference value %u on route %I/%d",
p->p.name, preference, n->n.prefix, n->n.pxlen);
preference = RA_PREF_MEDIUM;
+ preference_set = 1;
lifetime = 0;
lifetime_set = 1;
}
@@ -473,8 +481,9 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
rt = fib_get(&p->routes, &n->n.prefix, n->n.pxlen);
/* Ignore update if nothing changed */
- if (rt->alive &&
+ if (rt->valid &&
(rt->preference == preference) &&
+ (rt->preference_set == preference_set) &&
(rt->lifetime == lifetime) &&
(rt->lifetime_set == lifetime_set))
return;
@@ -482,8 +491,10 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
if (p->routes.entries == 18)
log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name);
- rt->alive = 1;
+ rt->valid = 1;
+ rt->changed = now;
rt->preference = preference;
+ rt->preference_set = preference_set;
rt->lifetime = lifetime;
rt->lifetime_set = lifetime_set;
}
@@ -492,13 +503,16 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
/* Withdraw */
rt = fib_find(&p->routes, &n->n.prefix, n->n.pxlen);
- if (!rt || !rt->alive)
+ if (!rt || !rt->valid)
return;
/* Invalidate the route */
- rt->alive = 0;
- rt->expires = now + cf->route_linger_time;
- p->prune_time = MIN(p->prune_time, rt->expires);
+ rt->valid = 0;
+ rt->changed = now;
+
+ /* Invalidated route will be pruned eventually */
+ bird_clock_t expires = rt->changed + cf->max_linger_time;
+ p->prune_time = MIN(p->prune_time, expires);
}
radv_iface_notify_all(p, RA_EV_CHANGE);
@@ -511,8 +525,9 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U
static void
radv_prune_routes(struct radv_proto *p)
{
+ struct radv_config *cf = (struct radv_config *) (p->p.cf);
bird_clock_t next = TIME_INFINITY;
- int changed = 0;
+ bird_clock_t expires = 0;
/* Should not happen */
if (!p->fib_up)
@@ -526,29 +541,23 @@ again:
{
struct radv_route *rt = (void *) node;
- if (!rt->alive)
+ if (!rt->valid)
{
+ expires = rt->changed + cf->max_linger_time;
+
/* Delete expired nodes */
- if (rt->expires <= now)
+ if (expires <= now)
{
FIB_ITERATE_PUT(&fit, node);
fib_delete(&p->routes, node);
- changed = 1;
goto again;
}
else
- next = MIN(next, rt->expires);
+ next = MIN(next, expires);
}
}
FIB_ITERATE_END(node);
- if (changed)
- {
- struct radv_iface *ifa;
- WALK_LIST(ifa, p->iface_list)
- radv_invalidate(ifa);
- }
-
p->prune_time = next;
}