+ fix bug#326 by rib_lookup_and_pushup()
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 0aabc3c..d9cae28 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,9 @@
+2008-02-26 Denis Ovsienko
+	* zebra_rib.[ch]: (rib_lookup_and_pushup) New function, which makes sure,
+	  that if_set_prefix() has nothing in its way of assigning an address.
+	* ioctl.c: (if_set_prefix) Use rib_lookup_and_pushup() to resolve
+	  bug #326.
+
 2008-01-11 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
 
 	* ioctl.c: If HAVE_BSD_LINK_DETECT is defined, include <net/if_media.h>
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
index 7bb4da1..d536771 100644
--- a/zebra/ioctl.c
+++ b/zebra/ioctl.c
@@ -196,6 +196,7 @@
   struct prefix_ipv4 *p;
 
   p = (struct prefix_ipv4 *) ifc->address;
+  rib_lookup_and_pushup (p);
 
   memset (&addreq, 0, sizeof addreq);
   strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
diff --git a/zebra/rib.h b/zebra/rib.h
index 796a30e..9621f2c 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -212,6 +212,7 @@
 extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
 					 struct in_addr *);
 extern void rib_lookup_and_dump (struct prefix_ipv4 *);
+extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
 extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
 extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *);
 #define ZEBRA_RIB_LOOKUP_ERROR -1
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index e27c63b..c6af329 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1614,6 +1614,62 @@
   }
 }
 
+/* Check if requested address assignment will fail due to another
+ * route being installed by zebra in FIB already. Take necessary
+ * actions, if needed: remove such a route from FIB and deSELECT
+ * corresponding RIB entry. Then put affected RN into RIBQ head.
+ */
+void rib_lookup_and_pushup (struct prefix_ipv4 * p)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  unsigned changed = 0;
+
+  if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0)))
+  {
+    zlog_err ("%s: vrf_table() returned NULL", __func__);
+    return;
+  }
+
+  /* No matches would be the simplest case. */
+  if (NULL == (rn = route_node_lookup (table, (struct prefix *) p)))
+    return;
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+
+  /* Check all RIB entries. In case any changes have to be done, requeue
+   * the RN into RIBQ head. If the routing message about the new connected
+   * route (generated by the IP address we are going to assign very soon)
+   * comes before the RIBQ is processed, the new RIB entry will join
+   * RIBQ record already on head. This is necessary for proper revalidation
+   * of the rest of the RIB.
+   */
+  for (rib = rn->info; rib; rib = rib->next)
+  {
+    if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) &&
+      ! RIB_SYSTEM_ROUTE (rib))
+    {
+      changed = 1;
+      if (IS_ZEBRA_DEBUG_RIB)
+      {
+        char buf[INET_ADDRSTRLEN];
+        inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN);
+        zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen);
+        rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib);
+      }
+      rib_uninstall (rn, rib);
+    }
+  }
+  if (changed)
+  {
+    work_queue_aim_head (zebrad.ribq, 1);
+    rib_queue_add (&zebrad, rn);
+    work_queue_aim_head (zebrad.ribq, 0);
+  }
+}
+
 int
 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
 {