diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2009-01-13 19:15:49 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2009-01-13 19:15:49 +0100 |
commit | 0844b65d13d7a5928d425e9adaf28de63550a542 (patch) | |
tree | fb0070a6eceefddb10ea6860fc0003fc71252290 | |
parent | f15cb99c79034fbd98d90b104bd6267e6c2fec81 (diff) | |
download | bird-0844b65d13d7a5928d425e9adaf28de63550a542.tar bird-0844b65d13d7a5928d425e9adaf28de63550a542.zip |
Fix OSPF protocol error recovery behavior.
When OSPF neighbor state drops down to EXSTART,
clear LSA request and retransmit lists, as specified
by RFC. I hope that this will prevent oscillations
between EXSTART and LOADING states, which sometimes
happened.
It also contains related fix from Yury Shevchuk that
properly resets DB summary list iterator.
-rw-r--r-- | proto/ospf/dbdes.c | 4 | ||||
-rw-r--r-- | proto/ospf/neighbor.c | 63 | ||||
-rw-r--r-- | proto/ospf/neighbor.h | 3 | ||||
-rw-r--r-- | proto/ospf/topology.c | 2 |
4 files changed, 51 insertions, 21 deletions
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 2c5077b..9f45dfd 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -113,8 +113,8 @@ ospf_dbdes_send(struct ospf_neighbor *n) DBG("M bit unset.\n"); n->myimms.bit.m = 0; /* Unset more bit */ } - else - s_put(&(n->dbsi), sn); + + s_put(&(n->dbsi), sn); } pkt->imms.byte = n->myimms.byte; diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index b904874..ffb2df8 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -25,15 +25,42 @@ const char *ospf_inm[] = "inactivity timer", "line down" }; +static void neigh_chstate(struct ospf_neighbor *n, u8 state); +static struct ospf_neighbor *electbdr(list nl); +static struct ospf_neighbor *electdr(list nl); +static void neighbor_timer_hook(timer * timer); +static void rxmt_timer_hook(timer * timer); +static void ackd_timer_hook(timer * t); + +static void +init_lists(struct ospf_neighbor *n) +{ + s_init_list(&(n->lsrql)); + n->lsrqh = ospf_top_new(n->pool); + s_init(&(n->lsrqi), &(n->lsrql)); + + s_init_list(&(n->lsrtl)); + n->lsrth = ospf_top_new(n->pool); + s_init(&(n->lsrti), &(n->lsrtl)); +} -void neighbor_timer_hook(timer * timer); -void rxmt_timer_hook(timer * timer); -void ackd_timer_hook(timer * t); +/* Resets LSA request and retransmit list. + * We do not reset DB summary list iterator here, + * it is reset during entering EXCHANGE state. + */ +static void +reset_lists(struct ospf_neighbor *n) +{ + ospf_top_free(n->lsrqh); + ospf_top_free(n->lsrth); + init_lists(n); +} struct ospf_neighbor * ospf_neighbor_new(struct ospf_iface *ifa) { struct proto *p = (struct proto *) (ifa->oa->po); + struct proto_ospf *po = ifa->oa->po; struct pool *pool = rp_new(p->pool, "OSPF Neighbor"); struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor)); @@ -45,6 +72,9 @@ ospf_neighbor_new(struct ospf_iface *ifa) n->ldbdes = mb_allocz(pool, ifa->iface->mtu); n->state = NEIGHBOR_DOWN; + init_lists(n); + s_init(&(n->dbsi), &(po->lsal)); + n->inactim = tm_new(pool); n->inactim->data = n; n->inactim->randomize = 0; @@ -57,12 +87,6 @@ ospf_neighbor_new(struct ospf_iface *ifa) n->rxmt_timer->randomize = 0; n->rxmt_timer->hook = rxmt_timer_hook; n->rxmt_timer->recurrent = ifa->rxmtint; - s_init_list(&(n->lsrql)); - n->lsrqh = ospf_top_new(pool); - s_init_list(&(n->lsrtl)); - n->lsrth = ospf_top_new(pool); - s_init(&(n->lsrqi), &(n->lsrql)); - s_init(&(n->lsrti), &(n->lsrtl)); tm_start(n->rxmt_timer, n->ifa->rxmtint); DBG("%s: Installing rxmt timer.\n", p->name); @@ -88,7 +112,7 @@ ospf_neighbor_new(struct ospf_iface *ifa) * starts rxmt timers, call interface state machine etc. */ -void +static void neigh_chstate(struct ospf_neighbor *n, u8 state) { u8 oldstate; @@ -143,7 +167,7 @@ neigh_chstate(struct ospf_neighbor *n, u8 state) } } -struct ospf_neighbor * +static struct ospf_neighbor * electbdr(list nl) { struct ospf_neighbor *neigh, *n1, *n2; @@ -194,7 +218,7 @@ electbdr(list nl) return (n1); } -struct ospf_neighbor * +static struct ospf_neighbor * electdr(list nl) { struct ospf_neighbor *neigh, *n; @@ -323,7 +347,11 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) if (n->state == NEIGHBOR_EXSTART) { neigh_chstate(n, NEIGHBOR_EXCHANGE); + + /* Reset DB summary list iterator */ + s_get(&(n->dbsi)); s_init(&(n->dbsi), &po->lsal); + while (!EMPTY_LIST(n->ackl[ACKL_DELAY])) { struct lsah_n *no; @@ -355,6 +383,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) if (n->state >= NEIGHBOR_EXSTART) if (!can_do_adj(n)) { + reset_lists(n); neigh_chstate(n, NEIGHBOR_2WAY); } break; @@ -364,15 +393,18 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event) case INM_BADLSREQ: if (n->state >= NEIGHBOR_EXCHANGE) { + reset_lists(n); neigh_chstate(n, NEIGHBOR_EXSTART); } break; case INM_KILLNBR: case INM_LLDOWN: case INM_INACTTIM: + reset_lists(n); neigh_chstate(n, NEIGHBOR_DOWN); break; case INM_1WAYREC: + reset_lists(n); neigh_chstate(n, NEIGHBOR_INIT); break; default: @@ -539,7 +571,7 @@ ospf_find_area(struct proto_ospf *po, u32 aid) } /* Neighbor is inactive for a long time. Remove it. */ -void +static void neighbor_timer_hook(timer * timer) { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; @@ -558,6 +590,7 @@ ospf_neigh_remove(struct ospf_neighbor *n) struct ospf_iface *ifa = n->ifa; struct proto *p = &ifa->oa->po->proto; + s_get(&(n->dbsi)); neigh_chstate(n, NEIGHBOR_DOWN); rem_node(NODE n); rfree(n->pool); @@ -596,7 +629,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n) (ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name)); } -void +static void rxmt_timer_hook(timer * timer) { struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data; @@ -649,7 +682,7 @@ rxmt_timer_hook(timer * timer) } } -void +static void ackd_timer_hook(timer * t) { struct ospf_neighbor *n = t->data; diff --git a/proto/ospf/neighbor.h b/proto/ospf/neighbor.h index c3ecd6b..67f7c57 100644 --- a/proto/ospf/neighbor.h +++ b/proto/ospf/neighbor.h @@ -11,9 +11,6 @@ #define _BIRD_OSPF_NEIGHBOR_H_ struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa); -void neigh_chstate(struct ospf_neighbor *n, u8 state); -struct ospf_neighbor *electbdr(list nl); -struct ospf_neighbor *electdr(list nl); void ospf_neigh_sm(struct ospf_neighbor *n, int event); void bdr_election(struct ospf_iface *ifa); struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid); diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index c3f70fd..a15d2e3 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -908,7 +908,7 @@ ospf_dump_lsa(struct top_hash_entry *he, struct proto *p) case LSA_T_NET: ln = he->lsa_body; rts = (u32 *) (ln + 1); - max = (he->lsa.length - sizeof(struct ospf_lsa_header) - + max = (he->lsa.length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) / sizeof(u32); for (i = 0; i < max; i++) |