]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes next hop calculation on NBMA and parallel PTP links.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 11 Apr 2010 10:22:47 +0000 (12:22 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 11 Apr 2010 10:22:47 +0000 (12:22 +0200)
proto/ospf/neighbor.c
proto/ospf/neighbor.h
proto/ospf/rt.c
proto/ospf/topology.h

index 69c5880664dc9b417f726015796dcdd1dfaa5233..2563abd480ebd1292d88bee0e7e8e61e4179d43a 100644 (file)
@@ -536,27 +536,6 @@ find_neigh(struct ospf_iface *ifa, u32 rid)
   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 *
 ospf_find_area(struct proto_ospf *po, u32 aid)
 {
index 67f7c57cf3d1bee0862cb8baae991c804509e326..5612eca1c8e27f7d77c7cbdb1201ee10bfefc053 100644 (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 bdr_election(struct ospf_iface *ifa);
 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);
 void ospf_neigh_remove(struct ospf_neighbor *n);
 void ospf_sh_neigh_info(struct ospf_neighbor *n);
index c3798e7d10daf2a5cdb4bfaff23eaa1b532f7d68..6a30c687f838cac914b2d2cb1659d01c2bd11bf8 100644 (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 */
   en->lb = IPA_NONE;
+#ifdef OSPFv3
+  en->lb_id = 0;
+#endif
   switch (en->lsa.type)
   {
     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
            en->lb = ipa_from_u32(rtl->data);
+#else /* OSPFv3 */
+           en->lb_id = rtl->lif;
 #endif
            return 1;
          }
@@ -1099,14 +1104,15 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
              struct top_hash_entry *par)
 {
   // struct proto *p = &oa->po->proto;
-  struct ospf_neighbor *neigh;
+  struct ospf_neighbor *neigh, *m;
   struct proto_ospf *po = oa->po;
   struct ospf_iface *ifa;
 
   /* 16.1.1. The next hop calculation */
   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",
        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;
     }
 
-    /* 
-     * Remaining cases - local neighbours.
-     * 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)))
+    /* The second case - ptp or ptmp neighbor */
+    if ((en->lsa.type == LSA_T_RT) && (par == oa->rt))
     {
-      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;
-         en->nhi = neigh->ifa;
-         return 1;
+         m = find_neigh(ifa, rid);
+         if (m && (m->state == NEIGHBOR_FULL))
+         {
+           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 */
     log(L_ERR "Unexpected case in next hop calculation");
-
     return 0;
   }
 
index f6ba01986ed237e92c8d7fcb2079098dcc247313..16d4c78f33469128c2b528a800ba8a292a02399c 100644 (file)
@@ -23,6 +23,9 @@ struct top_hash_entry
   ip_addr nh;                  /* Next hop */
   ip_addr lb;                  /* Link back */
   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 */
   u16 ini_age;
   u8 color;