Fixes next hop calculation on NBMA and parallel PTP links.

This commit is contained in:
Ondrej Zajicek 2010-04-11 12:22:47 +02:00
parent 7969ea3b41
commit 6e80676096
4 changed files with 71 additions and 43 deletions

View file

@ -536,27 +536,6 @@ find_neigh(struct ospf_iface *ifa, u32 rid)
return NULL; return NULL;
} }
/* Find a closest neighbor which is at least 2-Way */
struct ospf_neighbor *
find_neigh_noifa(struct proto_ospf *po, u32 rid)
{
struct ospf_neighbor *n = NULL, *m;
struct ospf_iface *ifa;
WALK_LIST(ifa, po->iface_list) if ((m = find_neigh(ifa, rid)) != NULL)
{
if (m->state >= NEIGHBOR_2WAY)
{
if (n == NULL)
n = m;
else if (m->ifa->cost < n->ifa->cost)
n = m;
}
}
return n;
}
struct ospf_area * struct ospf_area *
ospf_find_area(struct proto_ospf *po, u32 aid) ospf_find_area(struct proto_ospf *po, u32 aid)
{ {

View file

@ -14,7 +14,6 @@ struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
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);
struct ospf_neighbor *find_neigh_noifa(struct proto_ospf *po, u32 rid);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid); struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
void ospf_neigh_remove(struct ospf_neighbor *n); void ospf_neigh_remove(struct ospf_neighbor *n);
void ospf_sh_neigh_info(struct ospf_neighbor *n); void ospf_sh_neigh_info(struct ospf_neighbor *n);

View file

@ -477,6 +477,9 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
// FIXME lb should be properly set for vlinks */ // FIXME lb should be properly set for vlinks */
en->lb = IPA_NONE; en->lb = IPA_NONE;
#ifdef OSPFv3
en->lb_id = 0;
#endif
switch (en->lsa.type) switch (en->lsa.type)
{ {
case LSA_T_RT: case LSA_T_RT:
@ -500,6 +503,8 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
{ {
#ifdef OSPFv2 #ifdef OSPFv2
en->lb = ipa_from_u32(rtl->data); en->lb = ipa_from_u32(rtl->data);
#else /* OSPFv3 */
en->lb_id = rtl->lif;
#endif #endif
return 1; return 1;
} }
@ -1099,14 +1104,15 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par) struct top_hash_entry *par)
{ {
// struct proto *p = &oa->po->proto; // struct proto *p = &oa->po->proto;
struct ospf_neighbor *neigh; struct ospf_neighbor *neigh, *m;
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct ospf_iface *ifa; struct ospf_iface *ifa;
/* 16.1.1. The next hop calculation */ /* 16.1.1. The next hop calculation */
DBG(" Next hop called.\n"); DBG(" Next hop called.\n");
if (ipa_equal(par->nh, IPA_NONE)) if (ipa_zero(par->nh))
{ {
u32 rid = en->lsa.rt;
DBG(" Next hop calculating for id: %R rt: %R type: %u\n", DBG(" Next hop calculating for id: %R rt: %R type: %u\n",
en->lsa.id, en->lsa.rt, en->lsa.type); en->lsa.id, en->lsa.rt, en->lsa.type);
@ -1130,32 +1136,73 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
return 0; return 0;
} }
/* /* The second case - ptp or ptmp neighbor */
* Remaining cases - local neighbours. if ((en->lsa.type == LSA_T_RT) && (par == oa->rt))
* There are two problems with this code:
* 1) we use IP address from HELLO packet
* and not the one from LSA (router or link).
* This may break NBMA networks
* 2) we use find_neigh_noifa() and does not
* take into account associated iface.
* This breaks neighbors connected by more links.
*/
if ((en->lsa.type == LSA_T_RT) &&
((par == oa->rt) || (par->lsa.type == LSA_T_NET)))
{ {
if ((neigh = find_neigh_noifa(po, en->lsa.rt)) != NULL) /*
* We don't know which iface was used to reach this neighbor
* (there might be more parallel ifaces) so we will find
* the best PTP iface with given fully adjacent neighbor.
*/
neigh = NULL;
WALK_LIST(ifa, po->iface_list)
if (ifa->type == OSPF_IT_PTP)
{ {
en->nh = neigh->ip; m = find_neigh(ifa, rid);
en->nhi = neigh->ifa; if (m && (m->state == NEIGHBOR_FULL))
return 1; {
if (!neigh || (m->ifa->cost < neigh->ifa->cost))
neigh = m;
}
} }
return 0;
if (!neigh)
return 0;
en->nh = neigh->ip;
en->nhi = neigh->ifa;
return 1;
} }
/* The third case - bcast or nbma neighbor */
if ((en->lsa.type == LSA_T_RT) && (par->lsa.type == LSA_T_NET))
{
/* par->nhi should be defined from parent's calc_next_hop() */
if (!par->nhi)
goto bad;
#ifdef OSPFv2
/*
* In this case, next-hop is the same as link-back, which is
* already computed in link_back().
*/
if (ipa_zero(en->lb))
goto bad;
en->nh = en->lb;
en->nhi = par->nhi;
return 1;
#else /* OSPFv3 */
/*
* Next-hop is taken from lladdr field of Link-LSA, en->lb_id
* is computed in link_back().
*/
struct top_hash_entry *llsa;
llsa = ospf_hash_find(po->gr, par->nhi->iface->index, en->lb_id, rid, LSA_T_LINK);
if (!llsa)
return 0;
en->nh = llsa->lladdr;
en->nhi = par->nhi;
return 1;
#endif
}
bad:
/* Probably bug or some race condition, we log it */ /* Probably bug or some race condition, we log it */
log(L_ERR "Unexpected case in next hop calculation"); log(L_ERR "Unexpected case in next hop calculation");
return 0; return 0;
} }

View file

@ -23,6 +23,9 @@ struct top_hash_entry
ip_addr nh; /* Next hop */ ip_addr nh; /* Next hop */
ip_addr lb; /* Link back */ ip_addr lb; /* Link back */
struct ospf_iface *nhi; /* Next hop interface */ struct ospf_iface *nhi; /* Next hop interface */
#ifdef OSPFv3
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
#endif
u32 dist; /* Distance from the root */ u32 dist; /* Distance from the root */
u16 ini_age; u16 ini_age;
u8 color; u8 color;