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.
This commit is contained in:
parent
f15cb99c79
commit
0844b65d13
4 changed files with 51 additions and 21 deletions
|
@ -113,8 +113,8 @@ ospf_dbdes_send(struct ospf_neighbor *n)
|
||||||
DBG("M bit unset.\n");
|
DBG("M bit unset.\n");
|
||||||
n->myimms.bit.m = 0; /* Unset more bit */
|
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;
|
pkt->imms.byte = n->myimms.byte;
|
||||||
|
|
|
@ -25,15 +25,42 @@ const char *ospf_inm[] =
|
||||||
"inactivity timer", "line down"
|
"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);
|
||||||
|
|
||||||
void neighbor_timer_hook(timer * timer);
|
static void
|
||||||
void rxmt_timer_hook(timer * timer);
|
init_lists(struct ospf_neighbor *n)
|
||||||
void ackd_timer_hook(timer * t);
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 *
|
struct ospf_neighbor *
|
||||||
ospf_neighbor_new(struct ospf_iface *ifa)
|
ospf_neighbor_new(struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
struct proto *p = (struct proto *) (ifa->oa->po);
|
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 pool *pool = rp_new(p->pool, "OSPF Neighbor");
|
||||||
struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct 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->ldbdes = mb_allocz(pool, ifa->iface->mtu);
|
||||||
n->state = NEIGHBOR_DOWN;
|
n->state = NEIGHBOR_DOWN;
|
||||||
|
|
||||||
|
init_lists(n);
|
||||||
|
s_init(&(n->dbsi), &(po->lsal));
|
||||||
|
|
||||||
n->inactim = tm_new(pool);
|
n->inactim = tm_new(pool);
|
||||||
n->inactim->data = n;
|
n->inactim->data = n;
|
||||||
n->inactim->randomize = 0;
|
n->inactim->randomize = 0;
|
||||||
|
@ -57,12 +87,6 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||||
n->rxmt_timer->randomize = 0;
|
n->rxmt_timer->randomize = 0;
|
||||||
n->rxmt_timer->hook = rxmt_timer_hook;
|
n->rxmt_timer->hook = rxmt_timer_hook;
|
||||||
n->rxmt_timer->recurrent = ifa->rxmtint;
|
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);
|
tm_start(n->rxmt_timer, n->ifa->rxmtint);
|
||||||
DBG("%s: Installing rxmt timer.\n", p->name);
|
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.
|
* starts rxmt timers, call interface state machine etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
static void
|
||||||
neigh_chstate(struct ospf_neighbor *n, u8 state)
|
neigh_chstate(struct ospf_neighbor *n, u8 state)
|
||||||
{
|
{
|
||||||
u8 oldstate;
|
u8 oldstate;
|
||||||
|
@ -143,7 +167,7 @@ neigh_chstate(struct ospf_neighbor *n, u8 state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ospf_neighbor *
|
static struct ospf_neighbor *
|
||||||
electbdr(list nl)
|
electbdr(list nl)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *neigh, *n1, *n2;
|
struct ospf_neighbor *neigh, *n1, *n2;
|
||||||
|
@ -194,7 +218,7 @@ electbdr(list nl)
|
||||||
return (n1);
|
return (n1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ospf_neighbor *
|
static struct ospf_neighbor *
|
||||||
electdr(list nl)
|
electdr(list nl)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *neigh, *n;
|
struct ospf_neighbor *neigh, *n;
|
||||||
|
@ -323,7 +347,11 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
if (n->state == NEIGHBOR_EXSTART)
|
if (n->state == NEIGHBOR_EXSTART)
|
||||||
{
|
{
|
||||||
neigh_chstate(n, NEIGHBOR_EXCHANGE);
|
neigh_chstate(n, NEIGHBOR_EXCHANGE);
|
||||||
|
|
||||||
|
/* Reset DB summary list iterator */
|
||||||
|
s_get(&(n->dbsi));
|
||||||
s_init(&(n->dbsi), &po->lsal);
|
s_init(&(n->dbsi), &po->lsal);
|
||||||
|
|
||||||
while (!EMPTY_LIST(n->ackl[ACKL_DELAY]))
|
while (!EMPTY_LIST(n->ackl[ACKL_DELAY]))
|
||||||
{
|
{
|
||||||
struct lsah_n *no;
|
struct lsah_n *no;
|
||||||
|
@ -355,6 +383,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
if (n->state >= NEIGHBOR_EXSTART)
|
if (n->state >= NEIGHBOR_EXSTART)
|
||||||
if (!can_do_adj(n))
|
if (!can_do_adj(n))
|
||||||
{
|
{
|
||||||
|
reset_lists(n);
|
||||||
neigh_chstate(n, NEIGHBOR_2WAY);
|
neigh_chstate(n, NEIGHBOR_2WAY);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -364,15 +393,18 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
case INM_BADLSREQ:
|
case INM_BADLSREQ:
|
||||||
if (n->state >= NEIGHBOR_EXCHANGE)
|
if (n->state >= NEIGHBOR_EXCHANGE)
|
||||||
{
|
{
|
||||||
|
reset_lists(n);
|
||||||
neigh_chstate(n, NEIGHBOR_EXSTART);
|
neigh_chstate(n, NEIGHBOR_EXSTART);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case INM_KILLNBR:
|
case INM_KILLNBR:
|
||||||
case INM_LLDOWN:
|
case INM_LLDOWN:
|
||||||
case INM_INACTTIM:
|
case INM_INACTTIM:
|
||||||
|
reset_lists(n);
|
||||||
neigh_chstate(n, NEIGHBOR_DOWN);
|
neigh_chstate(n, NEIGHBOR_DOWN);
|
||||||
break;
|
break;
|
||||||
case INM_1WAYREC:
|
case INM_1WAYREC:
|
||||||
|
reset_lists(n);
|
||||||
neigh_chstate(n, NEIGHBOR_INIT);
|
neigh_chstate(n, NEIGHBOR_INIT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -539,7 +571,7 @@ ospf_find_area(struct proto_ospf *po, u32 aid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Neighbor is inactive for a long time. Remove it. */
|
/* Neighbor is inactive for a long time. Remove it. */
|
||||||
void
|
static void
|
||||||
neighbor_timer_hook(timer * timer)
|
neighbor_timer_hook(timer * timer)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
|
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 ospf_iface *ifa = n->ifa;
|
||||||
struct proto *p = &ifa->oa->po->proto;
|
struct proto *p = &ifa->oa->po->proto;
|
||||||
|
|
||||||
|
s_get(&(n->dbsi));
|
||||||
neigh_chstate(n, NEIGHBOR_DOWN);
|
neigh_chstate(n, NEIGHBOR_DOWN);
|
||||||
rem_node(NODE n);
|
rem_node(NODE n);
|
||||||
rfree(n->pool);
|
rfree(n->pool);
|
||||||
|
@ -596,7 +629,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
|
||||||
(ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name));
|
(ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rxmt_timer_hook(timer * timer)
|
rxmt_timer_hook(timer * timer)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
|
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)
|
ackd_timer_hook(timer * t)
|
||||||
{
|
{
|
||||||
struct ospf_neighbor *n = t->data;
|
struct ospf_neighbor *n = t->data;
|
||||||
|
|
|
@ -11,9 +11,6 @@
|
||||||
#define _BIRD_OSPF_NEIGHBOR_H_
|
#define _BIRD_OSPF_NEIGHBOR_H_
|
||||||
|
|
||||||
struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
|
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 ospf_neigh_sm(struct ospf_neighbor *n, int event);
|
||||||
void bdr_election(struct ospf_iface *ifa);
|
void bdr_election(struct ospf_iface *ifa);
|
||||||
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
|
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
|
||||||
|
|
Loading…
Reference in a new issue