]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes problem with source address selection in BGP and BFD.
authorOndrej Zajicek <santiago@crfreenet.org>
Mon, 2 Dec 2013 10:54:32 +0000 (11:54 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 2 Dec 2013 10:54:32 +0000 (11:54 +0100)
nest/iface.h
nest/neighbor.c
proto/bfd/bfd.c
proto/bgp/bgp.c

index 697ea543638ef0f828cadffe67e04b057c3e38ee..56710e4a4b219d9d6329a0d2b75bb7e9d1d47b85 100644 (file)
@@ -108,6 +108,7 @@ typedef struct neighbor {
   node n;                              /* Node in global neighbor list */
   node if_n;                           /* Node in per-interface neighbor list */
   ip_addr addr;                                /* Address of the neighbor */
+  struct ifa *ifa;                     /* Ifa on related iface */
   struct iface *iface;                 /* Interface it's connected to */
   struct proto *proto;                 /* Protocol this belongs to */
   void *data;                          /* Protocol-specific data */
index 11a980b25f9b3dafa9fccfe099c174b3bb624da3..48b6b6ac888805e3ea13f265e594e23f0b040838 100644 (file)
@@ -56,14 +56,20 @@ neigh_hash(struct proto *p, ip_addr *a)
 }
 
 static int
-if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
+if_connected(ip_addr *a, struct iface *i, struct ifa **ap)
 {
   struct ifa *b;
 
   if (!(i->flags & IF_UP))
+  {
+    *ap = NULL;
     return -1;
+  }
+
   WALK_LIST(b, i->addrs)
     {
+      *ap = b;
+
       if (ipa_equal(*a, b->ip))
        return SCOPE_HOST;
       if (b->flags & IA_PEER)
@@ -79,13 +85,18 @@ if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
              if ((b->pxlen < (BITS_PER_IP_ADDRESS - 1)) &&
                  (ipa_equal(*a, b->prefix) ||  /* Network address */
                   ipa_equal(*a, b->brd)))      /* Broadcast */
+             {
+               *ap = NULL;
                return -1;
+             }
 #endif
 
              return b->scope;
            }
        }
       }
+
+  *ap = NULL;
   return -1;
 }
 
@@ -117,6 +128,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
   int class, scope = -1;
   unsigned int h = neigh_hash(p, a);
   struct iface *i;
+  struct ifa *addr;
 
   WALK_LIST(n, neigh_hash_table[h])    /* Search the cache */
     if (n->proto == p && ipa_equal(*a, n->addr) && (!ifa || (ifa == n->iface)))
@@ -132,7 +144,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
 
   if (ifa)
     {
-      scope = if_connected(a, ifa);
+      scope = if_connected(a, ifa, &addr);
       flags |= NEF_BIND;
 
       if ((scope < 0) && (flags & NEF_ONLINK))
@@ -140,7 +152,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
     }
   else
     WALK_LIST(i, iface_list)
-      if ((scope = if_connected(a, i)) >= 0)
+      if ((scope = if_connected(a, i, &addr)) >= 0)
        {
          ifa = i;
          break;
@@ -165,6 +177,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
       scope = -1;
     }
   n->iface = ifa;
+  n->ifa = addr;
   n->proto = p;
   n->data = NULL;
   n->aux = 0;
@@ -216,9 +229,10 @@ neigh_dump_all(void)
 }
 
 static void
-neigh_up(neighbor *n, struct iface *i, int scope)
+neigh_up(neighbor *n, struct iface *i, int scope, struct ifa *a)
 {
   n->iface = i;
+  n->ifa = a;
   n->scope = scope;
   add_tail(&i->neighbors, &n->if_n);
   rem_node(&n->n);
@@ -235,6 +249,7 @@ neigh_down(neighbor *n)
   rem_node(&n->if_n);
   if (! (n->flags & NEF_BIND))
     n->iface = NULL;
+  n->ifa = NULL;
   n->scope = -1;
   if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
     n->proto->neigh_notify(n);
@@ -245,13 +260,14 @@ neigh_down(neighbor *n)
 
       /* Respawn neighbor if there is another matching prefix */
       struct iface *i;
+      struct ifa *a;
       int scope;
 
       if (!n->iface)
        WALK_LIST(i, iface_list)
-         if ((scope = if_connected(&n->addr, i)) >= 0)
+         if ((scope = if_connected(&n->addr, i, &a)) >= 0)
            {
-             neigh_up(n, i, scope);
+             neigh_up(n, i, scope, a);
              return;
            }
     }
@@ -272,13 +288,14 @@ neigh_down(neighbor *n)
 void
 neigh_if_up(struct iface *i)
 {
+  struct ifa *a;
   neighbor *n, *next;
   int scope;
 
   WALK_LIST_DELSAFE(n, next, sticky_neigh_list)
     if ((!n->iface || n->iface == i) &&
-       ((scope = if_connected(&n->addr, i)) >= 0))
-      neigh_up(n, i, scope);
+       ((scope = if_connected(&n->addr, i, &a)) >= 0))
+      neigh_up(n, i, scope, a);
 }
 
 /**
@@ -339,8 +356,9 @@ neigh_ifa_update(struct ifa *a)
   /* Remove all neighbors whose scope has changed */
   WALK_LIST_DELSAFE(x, y, i->neighbors)
     {
+      struct ifa *aa;
       neighbor *n = SKIP_BACK(neighbor, if_n, x);
-      if (if_connected(&n->addr, i) != n->scope)
+      if (if_connected(&n->addr, i, &aa) != n->scope)
        neigh_down(n);
     }
 
index 89355483134ab12e95cb1c252b919944f24a4319..b697e84c814993fc6ff673e306ab9ae01209e1d3 100644 (file)
@@ -740,7 +740,7 @@ bfd_neigh_notify(struct neighbor *nb)
 
   if ((nb->scope > 0) && !n->req)
   {
-    ip_addr local = ipa_nonzero(n->local) ? n->local : nb->iface->addr->ip;
+    ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip;
     n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, NULL, NULL);
   }
 
index f5b6b8fcca99c8a9f6336eaba1dc88c2b51b276c..7cd0b0ae3316a372ed60ce1df10f959c65bcec7e 100644 (file)
@@ -718,9 +718,8 @@ bgp_start_neighbor(struct bgp_proto *p)
 {
   /* Called only for single-hop BGP sessions */
 
-  /* Remove this ? */
   if (ipa_zero(p->source_addr))
-    p->source_addr = p->neigh->iface->addr->ip; 
+    p->source_addr = p->neigh->ifa->ip; 
 
 #ifdef IPV6
   {