summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2009-01-13 19:15:49 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2009-01-13 19:15:49 +0100
commit0844b65d13d7a5928d425e9adaf28de63550a542 (patch)
treefb0070a6eceefddb10ea6860fc0003fc71252290
parentf15cb99c79034fbd98d90b104bd6267e6c2fec81 (diff)
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.c4
-rw-r--r--proto/ospf/neighbor.c63
-rw-r--r--proto/ospf/neighbor.h3
-rw-r--r--proto/ospf/topology.c2
4 files changed, 51 insertions, 21 deletions
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index 2c5077b9..9f45dfdc 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 b904874d..ffb2df85 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 c3ecd6b6..67f7c57c 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 c3f70fd3..a15d2e35 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++)