summaryrefslogtreecommitdiff
path: root/proto/ospf/neighbor.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/neighbor.c')
-rw-r--r--proto/ospf/neighbor.c455
1 files changed, 226 insertions, 229 deletions
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index ee1e8d0f..c75b1b93 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -10,24 +10,19 @@
#include "ospf.h"
-char *ospf_ns[] = { " down",
- " attempt",
- " init",
- " 2way",
- " exstart",
- "exchange",
- " loading",
- " full"
+
+const char *ospf_ns_names[] = {
+ "Down", "Attempt", "Init", "2-Way", "ExStart", "Exchange", "Loading", "Full"
};
-const char *ospf_inm[] =
- { "hello received", "neighbor start", "2-way received",
- "negotiation done", "exstart done", "bad ls request", "load done",
- "adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor",
- "inactivity timer", "line down"
+const char *ospf_inm_names[] = {
+ "HelloReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone",
+ "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived",
+ "KillNbr", "InactivityTimer", "LLDown"
};
-static void neigh_chstate(struct ospf_neighbor *n, u8 state);
+
+static int can_do_adj(struct ospf_neighbor *n);
static void neighbor_timer_hook(timer * timer);
static void rxmt_timer_hook(timer * timer);
static void ackd_timer_hook(timer * t);
@@ -113,8 +108,29 @@ ospf_neighbor_new(struct ospf_iface *ifa)
return (n);
}
+static void
+ospf_neigh_down(struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_proto *p = ifa->oa->po;
+
+ if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
+ {
+ struct nbma_node *nn = find_nbma_node(ifa, n->ip);
+ if (nn)
+ nn->found = 0;
+ }
+
+ s_get(&(n->dbsi));
+ release_lsrtl(p, n);
+ rem_node(NODE n);
+ rfree(n->pool);
+
+ OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", n->rid, ifa->ifname);
+}
+
/**
- * neigh_chstate - handles changes related to new or lod state of neighbor
+ * ospf_neigh_chstate - handles changes related to new or lod state of neighbor
* @n: OSPF neighbor
* @state: new state
*
@@ -122,7 +138,7 @@ ospf_neighbor_new(struct ospf_iface *ifa)
* starts rxmt timers, call interface state machine etc.
*/
static void
-neigh_chstate(struct ospf_neighbor *n, u8 state)
+ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
{
struct ospf_iface *ifa = n->ifa;
struct ospf_proto *p = ifa->oa->po;
@@ -132,16 +148,11 @@ neigh_chstate(struct ospf_neighbor *n, u8 state)
if (state == old_state)
return;
- OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from %s to %s",
- n->ip, ospf_ns[old_state], ospf_ns[state]);
+ OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed state from %s to %s",
+ n->rid, ifa->ifname, ospf_ns_names[old_state], ospf_ns_names[state]);
n->state = state;
- if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY))
- ospf_iface_sm(ifa, ISM_NEICH);
- if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY))
- ospf_iface_sm(ifa, ISM_NEICH);
-
/* Increase number of partial adjacencies */
if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING))
p->padj++;
@@ -181,145 +192,12 @@ neigh_chstate(struct ospf_neighbor *n, u8 state)
if (state > NEIGHBOR_EXSTART)
n->myimms &= ~DBDES_I;
-}
-static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n)
-{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; }
-
-static struct ospf_neighbor *
-elect_bdr(struct ospf_proto *p, list nl)
-{
- struct ospf_neighbor *neigh, *n1, *n2;
- u32 nid;
-
- n1 = NULL;
- n2 = NULL;
- WALK_LIST(neigh, nl) /* First try those decl. themselves */
- {
- nid = neigh_get_id(p, neigh);
-
- if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
- if (neigh->priority > 0) /* Eligible */
- if (neigh->dr != nid) /* And not decl. itself DR */
- {
- if (neigh->bdr == nid) /* Declaring BDR */
- {
- if (n1 != NULL)
- {
- if (neigh->priority > n1->priority)
- n1 = neigh;
- else if (neigh->priority == n1->priority)
- if (neigh->rid > n1->rid)
- n1 = neigh;
- }
- else
- {
- n1 = neigh;
- }
- }
- else /* And NOT declaring BDR */
- {
- if (n2 != NULL)
- {
- if (neigh->priority > n2->priority)
- n2 = neigh;
- else if (neigh->priority == n2->priority)
- if (neigh->rid > n2->rid)
- n2 = neigh;
- }
- else
- {
- n2 = neigh;
- }
- }
- }
- }
- if (n1 == NULL)
- n1 = n2;
-
- return (n1);
-}
-
-static struct ospf_neighbor *
-elect_dr(struct ospf_proto *p, list nl)
-{
- struct ospf_neighbor *neigh, *n;
- u32 nid;
-
- n = NULL;
- WALK_LIST(neigh, nl) /* And now DR */
- {
- nid = neigh_get_id(p, neigh);
-
- if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
- if (neigh->priority > 0) /* Eligible */
- if (neigh->dr == nid) /* And declaring itself DR */
- {
- if (n != NULL)
- {
- if (neigh->priority > n->priority)
- n = neigh;
- else if (neigh->priority == n->priority)
- if (neigh->rid > n->rid)
- n = neigh;
- }
- else
- {
- n = neigh;
- }
- }
- }
-
- return (n);
-}
-
-static int
-can_do_adj(struct ospf_neighbor *n)
-{
- struct ospf_iface *ifa = n->ifa;
- struct ospf_proto *p = ifa->oa->po;
- int i = 0;
-
- switch (ifa->type)
- {
- case OSPF_IT_PTP:
- case OSPF_IT_PTMP:
- case OSPF_IT_VLINK:
- i = 1;
- break;
- case OSPF_IT_BCAST:
- case OSPF_IT_NBMA:
- switch (ifa->state)
- {
- case OSPF_IS_DOWN:
- case OSPF_IS_LOOP:
- bug("%s: Iface %s in down state?", p->p.name, ifa->ifname);
- break;
- case OSPF_IS_WAITING:
- DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname);
- break;
- case OSPF_IS_DROTHER:
- if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
- && (n->state >= NEIGHBOR_2WAY))
- i = 1;
- break;
- case OSPF_IS_PTP:
- case OSPF_IS_BACKUP:
- case OSPF_IS_DR:
- if (n->state >= NEIGHBOR_2WAY)
- i = 1;
- break;
- default:
- bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
- break;
- }
- break;
- default:
- bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
- break;
- }
- DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
- return i;
+ /* Generate NeighborChange event if needed, see RFC 2328 9.2 */
+ if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY))
+ ospf_iface_sm(ifa, ISM_NEICH);
+ if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY))
+ ospf_iface_sm(ifa, ISM_NEICH);
}
/**
@@ -339,20 +217,19 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
{
struct ospf_proto *p = n->ifa->oa->po;
- DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip,
- ospf_inm[event]);
+ DBG("Neighbor state machine for %R on %s, event %s\n",
+ n->rid, n->ifa->ifname, ospf_inm_names[event]);
switch (event)
{
case INM_START:
- neigh_chstate(n, NEIGHBOR_ATTEMPT);
+ ospf_neigh_chstate(n, NEIGHBOR_ATTEMPT);
/* NBMA are used different way */
break;
case INM_HELLOREC:
- if ((n->state == NEIGHBOR_DOWN) ||
- (n->state == NEIGHBOR_ATTEMPT))
- neigh_chstate(n, NEIGHBOR_INIT);
+ if (n->state < NEIGHBOR_INIT)
+ ospf_neigh_chstate(n, NEIGHBOR_INIT);
/* Restart inactivity timer */
tm_start(n->inactim, n->ifa->deadint);
@@ -360,15 +237,15 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
case INM_2WAYREC:
if (n->state < NEIGHBOR_2WAY)
- neigh_chstate(n, NEIGHBOR_2WAY);
+ ospf_neigh_chstate(n, NEIGHBOR_2WAY);
if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
- neigh_chstate(n, NEIGHBOR_EXSTART);
+ ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
break;
case INM_NEGDONE:
if (n->state == NEIGHBOR_EXSTART)
{
- neigh_chstate(n, NEIGHBOR_EXCHANGE);
+ ospf_neigh_chstate(n, NEIGHBOR_EXCHANGE);
/* Reset DB summary list iterator */
s_get(&(n->dbsi));
@@ -385,11 +262,11 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
break;
case INM_EXDONE:
- neigh_chstate(n, NEIGHBOR_LOADING);
+ ospf_neigh_chstate(n, NEIGHBOR_LOADING);
break;
case INM_LOADDONE:
- neigh_chstate(n, NEIGHBOR_FULL);
+ ospf_neigh_chstate(n, NEIGHBOR_FULL);
break;
case INM_ADJOK:
@@ -399,15 +276,15 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
/* Can In build adjacency? */
if (can_do_adj(n))
{
- neigh_chstate(n, NEIGHBOR_EXSTART);
+ ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
}
break;
default:
if (n->state >= NEIGHBOR_EXSTART)
if (!can_do_adj(n))
{
- reset_lists(p,n);
- neigh_chstate(n, NEIGHBOR_2WAY);
+ reset_lists(p, n);
+ ospf_neigh_chstate(n, NEIGHBOR_2WAY);
}
break;
}
@@ -418,20 +295,21 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
if (n->state >= NEIGHBOR_EXCHANGE)
{
reset_lists(p, n);
- neigh_chstate(n, NEIGHBOR_EXSTART);
+ ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
}
break;
case INM_KILLNBR:
case INM_LLDOWN:
case INM_INACTTIM:
- reset_lists(p, n);
- neigh_chstate(n, NEIGHBOR_DOWN);
+ /* No need for reset_lists() */
+ ospf_neigh_chstate(n, NEIGHBOR_DOWN);
+ ospf_neigh_down(n);
break;
case INM_1WAYREC:
reset_lists(p, n);
- neigh_chstate(n, NEIGHBOR_INIT);
+ ospf_neigh_chstate(n, NEIGHBOR_INIT);
break;
default:
@@ -440,14 +318,156 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
}
}
+static int
+can_do_adj(struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_proto *p = ifa->oa->po;
+ int i = 0;
+
+ switch (ifa->type)
+ {
+ case OSPF_IT_PTP:
+ case OSPF_IT_PTMP:
+ case OSPF_IT_VLINK:
+ i = 1;
+ break;
+ case OSPF_IT_BCAST:
+ case OSPF_IT_NBMA:
+ switch (ifa->state)
+ {
+ case OSPF_IS_DOWN:
+ case OSPF_IS_LOOP:
+ bug("%s: Iface %s in down state?", p->p.name, ifa->ifname);
+ break;
+ case OSPF_IS_WAITING:
+ DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname);
+ break;
+ case OSPF_IS_DROTHER:
+ if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
+ && (n->state >= NEIGHBOR_2WAY))
+ i = 1;
+ break;
+ case OSPF_IS_PTP:
+ case OSPF_IS_BACKUP:
+ case OSPF_IS_DR:
+ if (n->state >= NEIGHBOR_2WAY)
+ i = 1;
+ break;
+ default:
+ bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
+ break;
+ }
+ break;
+ default:
+ bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
+ break;
+ }
+ DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
+ return i;
+}
+
+
+static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n)
+{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; }
+
+static struct ospf_neighbor *
+elect_bdr(struct ospf_proto *p, list nl)
+{
+ struct ospf_neighbor *neigh, *n1, *n2;
+ u32 nid;
+
+ n1 = NULL;
+ n2 = NULL;
+ WALK_LIST(neigh, nl) /* First try those decl. themselves */
+ {
+ nid = neigh_get_id(p, neigh);
+
+ if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
+ if (neigh->priority > 0) /* Eligible */
+ if (neigh->dr != nid) /* And not decl. itself DR */
+ {
+ if (neigh->bdr == nid) /* Declaring BDR */
+ {
+ if (n1 != NULL)
+ {
+ if (neigh->priority > n1->priority)
+ n1 = neigh;
+ else if (neigh->priority == n1->priority)
+ if (neigh->rid > n1->rid)
+ n1 = neigh;
+ }
+ else
+ {
+ n1 = neigh;
+ }
+ }
+ else /* And NOT declaring BDR */
+ {
+ if (n2 != NULL)
+ {
+ if (neigh->priority > n2->priority)
+ n2 = neigh;
+ else if (neigh->priority == n2->priority)
+ if (neigh->rid > n2->rid)
+ n2 = neigh;
+ }
+ else
+ {
+ n2 = neigh;
+ }
+ }
+ }
+ }
+ if (n1 == NULL)
+ n1 = n2;
+
+ return (n1);
+}
+
+static struct ospf_neighbor *
+elect_dr(struct ospf_proto *p, list nl)
+{
+ struct ospf_neighbor *neigh, *n;
+ u32 nid;
+
+ n = NULL;
+ WALK_LIST(neigh, nl) /* And now DR */
+ {
+ nid = neigh_get_id(p, neigh);
+
+ if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
+ if (neigh->priority > 0) /* Eligible */
+ if (neigh->dr == nid) /* And declaring itself DR */
+ {
+ if (n != NULL)
+ {
+ if (neigh->priority > n->priority)
+ n = neigh;
+ else if (neigh->priority == n->priority)
+ if (neigh->rid > n->rid)
+ n = neigh;
+ }
+ else
+ {
+ n = neigh;
+ }
+ }
+ }
+
+ return (n);
+}
+
/**
* ospf_dr_election - (Backup) Designed Router election
* @ifa: actual interface
*
* When the wait timer fires, it is time to elect (Backup) Designated Router.
- * Structure describing me is added to this list so every electing router
- * has the same list. Backup Designated Router is elected before Designated
- * Router. This process is described in 9.4 of RFC 2328.
+ * Structure describing me is added to this list so every electing router has
+ * the same list. Backup Designated Router is elected before Designated
+ * Router. This process is described in 9.4 of RFC 2328. The function is
+ * supposed to be called only from ospf_iface_sm() as a part of the interface
+ * state machine.
*/
void
ospf_dr_election(struct ospf_iface *ifa)
@@ -506,6 +526,7 @@ ospf_dr_election(struct ospf_iface *ifa)
DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
+ /* We are part of the interface state machine */
if (ifa->drid == myid)
ospf_iface_chstate(ifa, OSPF_IS_DR);
else if (ifa->bdrid == myid)
@@ -544,39 +565,15 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
return NULL;
}
-/* Neighbor is inactive for a long time. Remove it. */
static void
neighbor_timer_hook(timer * timer)
{
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
- struct ospf_iface *ifa = n->ifa;
- struct ospf_proto *p = ifa->oa->po;
-
- OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I",
- ifa->ifname, n->ip);
- ospf_neigh_remove(n);
-}
-
-void
-ospf_neigh_remove(struct ospf_neighbor *n)
-{
- struct ospf_iface *ifa = n->ifa;
- struct ospf_proto *p = ifa->oa->po;
-
- if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
- {
- struct nbma_node *nn = find_nbma_node(ifa, n->ip);
- if (nn)
- nn->found = 0;
- }
-
- neigh_chstate(n, NEIGHBOR_DOWN);
+ struct ospf_proto *p = n->ifa->oa->po;
- s_get(&(n->dbsi));
- release_lsrtl(p, n);
- rem_node(NODE n);
- rfree(n->pool);
- OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid);
+ OSPF_TRACE(D_EVENTS, "Inactivity timer expired for neighbor %R on %s",
+ n->rid, n->ifa->ifname);
+ ospf_neigh_sm(n, INM_INACTTIM);
}
static void
@@ -587,8 +584,9 @@ ospf_neigh_bfd_hook(struct bfd_request *req)
if (req->down)
{
- OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname);
- ospf_neigh_remove(n);
+ OSPF_TRACE(D_EVENTS, "BFD session down for neighbor %R on %s",
+ n->rid, n->ifa->ifname);
+ ospf_neigh_sm(n, INM_INACTTIM);
}
}
@@ -611,7 +609,7 @@ void
ospf_sh_neigh_info(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
- char *pos = "other";
+ char *pos = "ptp ";
char etime[6];
int exp, sec, min;
@@ -627,16 +625,18 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
bsprintf(etime, "%02u:%02u", min, sec);
}
- if (n->rid == ifa->drid)
- pos = "dr ";
- else if (n->rid == ifa->bdrid)
- pos = "bdr ";
- else if ((n->ifa->type == OSPF_IT_PTP) || (n->ifa->type == OSPF_IT_PTMP) ||
- (n->ifa->type == OSPF_IT_VLINK))
- pos = "ptp ";
+ if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
+ {
+ if (n->rid == ifa->drid)
+ pos = "dr ";
+ else if (n->rid == ifa->bdrid)
+ pos = "bdr ";
+ else
+ pos = "other";
+ }
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
- ospf_ns[n->state], pos, etime, ifa->ifname, n->ip);
+ ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip);
}
static void
@@ -645,18 +645,18 @@ rxmt_timer_hook(timer *t)
struct ospf_neighbor *n = t->data;
struct ospf_proto *p = n->ifa->oa->po;
- DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
+ DBG("%s: RXMT timer fired on %s for neigh %I\n",
p->p.name, n->ifa->ifname, n->ip);
switch (n->state)
{
case NEIGHBOR_EXSTART:
- ospf_send_dbdes(p, n, 1);
+ ospf_send_dbdes(p, n);
return;
case NEIGHBOR_EXCHANGE:
- if (n->myimms & DBDES_MS)
- ospf_send_dbdes(p, n, 0);
+ if (n->myimms & DBDES_MS)
+ ospf_rxmt_dbdes(p, n);
case NEIGHBOR_LOADING:
ospf_send_lsreq(p, n);
return;
@@ -666,9 +666,6 @@ rxmt_timer_hook(timer *t)
if (!EMPTY_SLIST(n->lsrtl))
ospf_rxmt_lsupd(p, n);
return;
-
- default:
- return;
}
}
@@ -678,7 +675,7 @@ ackd_timer_hook(timer *t)
struct ospf_neighbor *n = t->data;
struct ospf_proto *p = n->ifa->oa->po;
- DBG("%s: ACKD timer fired on interface %s for neigh %I\n",
+ DBG("%s: ACKD timer fired on %s for neigh %I\n",
p->p.name, n->ifa->ifname, n->ip);
ospf_send_lsack(p, n, ACKL_DELAY);