diff options
Diffstat (limited to 'sysdep/unix/krt.c')
-rw-r--r-- | sysdep/unix/krt.c | 175 |
1 files changed, 75 insertions, 100 deletions
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 84207251..42dd12f6 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -625,19 +625,17 @@ krt_same_dest(rte *k, rte *e) void krt_got_route(struct krt_proto *p, rte *e) { - net *net = e->net; - int verdict; + rte *new = NULL, *rt_free = NULL; + net *n = e->net; #ifdef KRT_ALLOW_LEARN switch (e->u.krt.src) { case KRT_SRC_KERNEL: - verdict = KRF_IGNORE; - goto sentenced; + goto ignore; case KRT_SRC_REDIRECT: - verdict = KRF_DELETE; - goto sentenced; + goto delete; case KRT_SRC_ALIEN: if (KRT_CF->learn) @@ -652,58 +650,68 @@ krt_got_route(struct krt_proto *p, rte *e) #endif /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */ - if (net->n.flags & KRF_VERDICT_MASK) - { - /* Route to this destination was already seen. Strange, but it happens... */ - krt_trace_in(p, e, "already seen"); - rte_free(e); - return; - } + /* We wait for the initial feed to have correct installed state */ if (!p->ready) - { - /* We wait for the initial feed to have correct installed state */ - verdict = KRF_IGNORE; - goto sentenced; - } + goto ignore; - if (krt_is_installed(p, net)) - { - rte *new, *rt_free; + if (!krt_is_installed(p, n)) + goto delete; - new = krt_export_net(p, net, &rt_free); + new = krt_export_net(p, n, &rt_free); - /* TODO: There also may be changes in route eattrs, we ignore that for now. */ + /* Rejected by filters */ + if (!new) + goto delete; - if (!new) - verdict = KRF_DELETE; - else if (!bmap_test(&p->sync_map, new->id) || !krt_same_dest(e, new)) - verdict = KRF_UPDATE; - else - verdict = KRF_SEEN; + /* Route to this destination was already seen. Strange, but it happens... */ + if (bmap_test(&p->seen_map, new->id)) + goto aseen; - if (rt_free) - rte_free(rt_free); + /* Mark route as seen */ + bmap_set(&p->seen_map, new->id); - lp_flush(krt_filter_lp); - } - else - verdict = KRF_DELETE; + /* TODO: There also may be changes in route eattrs, we ignore that for now. */ + if (!bmap_test(&p->sync_map, new->id) || !krt_same_dest(e, new)) + goto update; - sentenced: - krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]); - net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict; - if (verdict == KRF_UPDATE || verdict == KRF_DELETE) - { - /* Get a cached copy of attributes and temporarily link the route */ - rta *a = e->attrs; - a->source = RTS_DUMMY; - e->attrs = rta_lookup(a); - e->next = net->routes; - net->routes = e; - } - else - rte_free(e); + goto seen; + +seen: + krt_trace_in(p, e, "seen"); + goto done; + +aseen: + krt_trace_in(p, e, "already seen"); + goto done; + +ignore: + krt_trace_in(p, e, "ignored"); + goto done; + +update: + krt_trace_in(p, new, "updating"); + krt_replace_rte(p, n, new, e); + goto done; + +delete: + krt_trace_in(p, e, "deleting"); + krt_replace_rte(p, n, NULL, e); + goto done; + +done: + rte_free(e); + + if (rt_free) + rte_free(rt_free); + + lp_flush(krt_filter_lp); +} + +static void +krt_init_scan(struct krt_proto *p) +{ + bmap_reset(&p->seen_map, 1024); } static void @@ -713,59 +721,24 @@ krt_prune(struct krt_proto *p) KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); FIB_WALK(&t->fib, net, n) + { + if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id)) { - int verdict = n->n.flags & KRF_VERDICT_MASK; - rte *new, *old, *rt_free = NULL; + rte *rt_free = NULL; + rte *new = krt_export_net(p, n, &rt_free); - if (verdict == KRF_UPDATE || verdict == KRF_DELETE) - { - /* Get a dummy route from krt_got_route() */ - old = n->routes; - n->routes = old->next; - } - else - old = NULL; - - if (verdict == KRF_CREATE || verdict == KRF_UPDATE) - { - /* We have to run export filter to get proper 'new' route */ - new = krt_export_net(p, n, &rt_free); - - if (!new) - verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; - } - else - new = NULL; - - switch (verdict) - { - case KRF_CREATE: - krt_trace_in(p, new, "reinstalling"); - krt_replace_rte(p, n, new, NULL); - break; - case KRF_SEEN: - case KRF_IGNORE: - /* Nothing happens */ - break; - case KRF_UPDATE: - krt_trace_in(p, new, "updating"); - krt_replace_rte(p, n, new, old); - break; - case KRF_DELETE: - krt_trace_in(p, old, "deleting"); - krt_replace_rte(p, n, NULL, old); - break; - default: - bug("krt_prune: invalid route status"); - } + if (new) + { + krt_trace_in(p, new, "installing"); + krt_replace_rte(p, n, new, NULL); + } - if (old) - rte_free(old); if (rt_free) rte_free(rt_free); + lp_flush(krt_filter_lp); - n->n.flags &= ~KRF_VERDICT_MASK; } + } FIB_WALK_END; #ifdef KRT_ALLOW_LEARN @@ -823,6 +796,7 @@ static void krt_scan(timer *t UNUSED) { struct krt_proto *p; + node *n; kif_force_scan(); @@ -830,14 +804,13 @@ krt_scan(timer *t UNUSED) p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list)); KRT_TRACE(p, D_EVENTS, "Scanning routing table"); + WALK_LIST2(p, n, krt_proto_list, krt_node) + krt_init_scan(p); + krt_do_scan(NULL); - void *q; - WALK_LIST(q, krt_proto_list) - { - p = SKIP_BACK(struct krt_proto, krt_node, q); + WALK_LIST2(p, n, krt_proto_list, krt_node) krt_prune(p); - } } static void @@ -879,6 +852,7 @@ krt_scan(timer *t) kif_force_scan(); KRT_TRACE(p, D_EVENTS, "Scanning routing table"); + krt_init_scan(p); krt_do_scan(p); krt_prune(p); } @@ -1095,6 +1069,7 @@ krt_start(struct proto *P) } bmap_init(&p->sync_map, p->p.pool, 1024); + bmap_init(&p->seen_map, p->p.pool, 1024); add_tail(&krt_proto_list, &p->krt_node); #ifdef KRT_ALLOW_LEARN |