]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospfd/ospf_zebra.c
lib: Check prefix length from zebra is sensible
[mirror_frr.git] / ospfd / ospf_zebra.c
index 06916aee8188aed5fc244c89a47d13ad4700dbd3..0938ce8d1ec97b490585e715dc4193d0ecd310c8 100644 (file)
 #include "memory.h"
 #include "zclient.h"
 #include "filter.h"
+#include "plist.h"
 #include "log.h"
+#include "lib/bfd.h"
+#include "nexthop.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
 #include "ospfd/ospf_lsa.h"
 #include "ospfd/ospf_dump.h"
 #include "ospfd/ospf_route.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
 #include "ospfd/ospf_zebra.h"
 #ifdef HAVE_SNMP
 #include "ospfd/ospf_snmp.h"
 #endif /* HAVE_SNMP */
+#include "ospfd/ospf_te.h"
 
 /* Zebra structure to hold current status. */
 struct zclient *zclient = NULL;
 
 /* For registering threads. */
 extern struct thread_master *master;
+struct in_addr router_id_zebra;
+
+/* Router-id update message from zebra. */
+static int
+ospf_router_id_update_zebra (int command, struct zclient *zclient,
+                            zebra_size_t length, vrf_id_t vrf_id)
+{
+  struct ospf *ospf;
+  struct prefix router_id;
+  zebra_router_id_update_read(zclient->ibuf,&router_id);
+
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str(&router_id, buf, sizeof(buf));
+      zlog_debug("Zebra rcvd: router id update %s", buf);
+    }
+
+  router_id_zebra = router_id.u.prefix4;
+
+  ospf = ospf_lookup ();
+  
+  if (ospf != NULL)
+    ospf_router_id_update (ospf);
+  
+  return 0;
+}
 
 /* Inteface addition message from zebra. */
-int
-ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+static int
+ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length,
+    vrf_id_t vrf_id)
 {
   struct interface *ifp;
-  struct ospf *ospf;
 
-  ifp = zebra_interface_add_read (zclient->ibuf);
+  ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
-    zlog_info ("Zebra: interface add %s index %d flags %ld metric %d mtu %d",
-               ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+    zlog_debug ("Zebra: interface add %s[%u] index %d flags %llx metric %d mtu %d",
+               ifp->name, ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags,
+               ifp->metric, ifp->mtu);
 
   assert (ifp->info);
 
   if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
     {
       SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
-      IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
-
-      if (if_is_broadcast (ifp))
-        IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST;
-      else if (if_is_pointopoint (ifp))
-        IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT;
-      else if (if_is_loopback (ifp))
-        IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_LOOPBACK;
+      IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp);
     }
 
-  ospf = ospf_lookup ();
-  if (ospf != NULL)
-    ospf_if_update (ospf);
+  ospf_if_update (NULL, ifp);
 
 #ifdef HAVE_SNMP
   ospf_snmp_if_update (ifp);
@@ -93,9 +119,9 @@ ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length)
   return 0;
 }
 
-int
+static int
 ospf_interface_delete (int command, struct zclient *zclient,
-                       zebra_size_t length)
+                       zebra_size_t length, vrf_id_t vrf_id)
 {
   struct interface *ifp;
   struct stream *s;
@@ -103,7 +129,7 @@ ospf_interface_delete (int command, struct zclient *zclient,
 
   s = zclient->ibuf;
   /* zebra_interface_state_read() updates interface structure in iflist */
-  ifp = zebra_interface_state_read (s);
+  ifp = zebra_interface_state_read (s, vrf_id);
 
   if (ifp == NULL)
     return 0;
@@ -113,9 +139,9 @@ ospf_interface_delete (int command, struct zclient *zclient,
                ifp->name);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
-    zlog_info
-      ("Zebra: interface delete %s index %d flags %ld metric %d mtu %d",
-       ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+    zlog_debug
+      ("Zebra: interface delete %s[%u] index %d flags %llx metric %d mtu %d",
+       ifp->name, ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
 
 #ifdef HAVE_SNMP
   ospf_snmp_if_delete (ifp);
@@ -125,58 +151,32 @@ ospf_interface_delete (int command, struct zclient *zclient,
     if (rn->info)
       ospf_if_free ((struct ospf_interface *) rn->info);
 
-  for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
-    if (rn->info)
-      ospf_del_if_params (rn->info);
-
-  if_delete (ifp);
-
+  ifp->ifindex = IFINDEX_DELETED;
   return 0;
 }
 
-struct interface *
-zebra_interface_if_lookup (struct stream *s)
+static struct interface *
+zebra_interface_if_lookup (struct stream *s, vrf_id_t vrf_id)
 {
-  struct interface *ifp;
-  u_char ifname_tmp[INTERFACE_NAMSIZ];
+  char ifname_tmp[INTERFACE_NAMSIZ];
 
   /* Read interface name. */
   stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
 
-  /* Lookup this by interface index. */
-  ifp = if_lookup_by_name (ifname_tmp);
-
-  /* If such interface does not exist, indicate an error */
-  if (!ifp)
-    return NULL;
-
-  return ifp;
+  /* And look it up. */
+  return if_lookup_by_name_len(ifname_tmp,
+                              strnlen(ifname_tmp, INTERFACE_NAMSIZ));
 }
 
-void
-zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
-{
-  /* Read interface's index. */
-  ifp->ifindex = stream_getl (s);
-
-  /* Read interface's value. */
-  ifp->status = stream_getc (s);
-  ifp->flags = stream_getl (s);
-  ifp->metric = stream_getl (s);
-  ifp->mtu = stream_getl (s);
-  ifp->bandwidth = stream_getl (s);
-}
-
-int
+static int
 ospf_interface_state_up (int command, struct zclient *zclient,
-                         zebra_size_t length)
+                         zebra_size_t length, vrf_id_t vrf_id)
 {
   struct interface *ifp;
-  struct interface if_tmp;
   struct ospf_interface *oi;
   struct route_node *rn;
 
-  ifp = zebra_interface_if_lookup (zclient->ibuf);
+  ifp = zebra_interface_if_lookup (zclient->ibuf, vrf_id);
 
   if (ifp == NULL)
     return 0;
@@ -185,28 +185,39 @@ ospf_interface_state_up (int command, struct zclient *zclient,
   if (if_is_operative (ifp))
     {
       /* Temporarily keep ifp values. */
+      struct interface if_tmp;
       memcpy (&if_tmp, ifp, sizeof (struct interface));
 
       zebra_interface_if_set_value (zclient->ibuf, ifp);
 
       if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
-        zlog_info ("Zebra: Interface[%s] state update.", ifp->name);
+        zlog_debug ("Zebra: Interface[%s] state update.", ifp->name);
 
       if (if_tmp.bandwidth != ifp->bandwidth)
         {
           if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
-            zlog_info ("Zebra: Interface[%s] bandwidth change %d -> %d.",
+            zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.",
                        ifp->name, if_tmp.bandwidth, ifp->bandwidth);
 
           ospf_if_recalculate_output_cost (ifp);
         }
+
+      if (if_tmp.mtu != ifp->mtu)
+        {
+          if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+            zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.",
+                       ifp->name, if_tmp.mtu, ifp->mtu);
+
+         /* Must reset the interface (simulate down/up) when MTU changes. */
+          ospf_if_reset(ifp);
+       }
       return 0;
     }
 
   zebra_interface_if_set_value (zclient->ibuf, ifp);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
-    zlog_info ("Zebra: Interface[%s] state change to up.", ifp->name);
+    zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name);
 
   for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
     {
@@ -219,21 +230,21 @@ ospf_interface_state_up (int command, struct zclient *zclient,
   return 0;
 }
 
-int
+static int
 ospf_interface_state_down (int command, struct zclient *zclient,
-                           zebra_size_t length)
+                           zebra_size_t length, vrf_id_t vrf_id)
 {
   struct interface *ifp;
   struct ospf_interface *oi;
   struct route_node *node;
 
-  ifp = zebra_interface_state_read (zclient->ibuf);
+  ifp = zebra_interface_state_read (zclient->ibuf, vrf_id);
 
   if (ifp == NULL)
     return 0;
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
-    zlog_info ("Zebra: Interface[%s] state change to down.", ifp->name);
+    zlog_debug ("Zebra: Interface[%s] state change to down.", ifp->name);
 
   for (node = route_top (IF_OIFS (ifp)); node; node = route_next (node))
     {
@@ -245,21 +256,25 @@ ospf_interface_state_down (int command, struct zclient *zclient,
   return 0;
 }
 
-int
+static int
 ospf_interface_address_add (int command, struct zclient *zclient,
-                            zebra_size_t length)
+                            zebra_size_t length, vrf_id_t vrf_id)
 {
-  struct ospf *ospf;
   struct connected *c;
 
-  c = zebra_interface_address_add_read (zclient->ibuf);
+  c = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
 
   if (c == NULL)
     return 0;
 
-  ospf = ospf_lookup ();
-  if (ospf != NULL)
-    ospf_if_update (ospf);
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str(c->address, buf, sizeof(buf));
+      zlog_debug("Zebra: interface %s address add %s", c->ifp->name, buf);
+    }
+
+  ospf_if_update (NULL, c->ifp);
 
 #ifdef HAVE_SNMP
   ospf_snmp_if_update (c->ifp);
@@ -268,32 +283,42 @@ ospf_interface_address_add (int command, struct zclient *zclient,
   return 0;
 }
 
-int
+static int
 ospf_interface_address_delete (int command, struct zclient *zclient,
-                               zebra_size_t length)
+                               zebra_size_t length, vrf_id_t vrf_id)
 {
-  struct ospf *ospf;
   struct connected *c;
   struct interface *ifp;
   struct ospf_interface *oi;
   struct route_node *rn;
   struct prefix p;
 
-  c = zebra_interface_address_delete_read (zclient->ibuf);
+  c = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
 
   if (c == NULL)
     return 0;
 
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    {
+      char buf[PREFIX2STR_BUFFER];
+      prefix2str(c->address, buf, sizeof(buf));
+      zlog_debug("Zebra: interface %s address delete %s", c->ifp->name, buf);
+    }
+
   ifp = c->ifp;
   p = *c->address;
   p.prefixlen = IPV4_MAX_PREFIXLEN;
 
   rn = route_node_lookup (IF_OIFS (ifp), &p);
   if (!rn)
-    return 0;
+    {
+      connected_free (c);
+      return 0;
+    }
 
   assert (rn->info);
   oi = rn->info;
+  route_unlock_node (rn);
 
   /* Call interface hook functions to clean up */
   ospf_if_free (oi);
@@ -304,13 +329,27 @@ ospf_interface_address_delete (int command, struct zclient *zclient,
 
   connected_free (c);
 
-  ospf = ospf_lookup ();
-  if (ospf != NULL)
-    ospf_if_update (ospf);
+  return 0;
+}
+
+static int
+ospf_interface_link_params (int command, struct zclient *zclient,
+                        zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_link_params_read (zclient->ibuf);
+
+  if (ifp == NULL)
+    return 0;
+
+  /* Update TE TLV */
+  ospf_mpls_te_update_if (ifp);
 
   return 0;
 }
 
+
 void
 ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
 {
@@ -320,9 +359,13 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
   int psize;
   struct stream *s;
   struct ospf_path *path;
-  listnode node;
+  struct listnode *node;
+  struct ospf *ospf = ospf_lookup ();
 
-  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+  if ((ospf->instance &&
+      redist_check_instance(&zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF], ospf->instance))
+    ||
+     vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF], VRF_DEFAULT))
     {
       message = 0;
       flags = 0;
@@ -336,18 +379,23 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
       if (distance)
         SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
 
+      /* Check if path type is ASE and use only 16bit tags */
+      if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) ||
+          (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) &&
+           (or->u.ext.tag > 0) && (or->u.ext.tag < UINT16_MAX))
+        SET_FLAG (message, ZAPI_MESSAGE_TAG);
+
       /* Make packet. */
       s = zclient->obuf;
       stream_reset (s);
 
-      /* Length place holder. */
-      stream_putw (s, 0);
-
       /* Put command, type, flags, message. */
-      stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+      zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT);
       stream_putc (s, ZEBRA_ROUTE_OSPF);
+      stream_putw (s, ospf->instance);
       stream_putc (s, flags);
       stream_putc (s, message);
+      stream_putw (s, SAFI_UNICAST);
 
       /* Put prefix information. */
       psize = PSIZE (p->prefixlen);
@@ -358,29 +406,63 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
       stream_putc (s, or->paths->count);
 
       /* Nexthop, ifindex, distance and metric information. */
-      for (node = listhead (or->paths); node; nextnode (node))
+      for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
         {
-          path = getdata (node);
-
-          if (path->nexthop.s_addr != INADDR_ANY)
+#ifdef HAVE_NETLINK
+         if (path->unnumbered ||
+             (path->nexthop.s_addr != INADDR_ANY &&
+              path->ifindex != 0))
+           {
+             stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+             stream_put_in_addr (s, &path->nexthop);
+             stream_putl (s, path->ifindex);
+           }
+         else if (path->nexthop.s_addr != INADDR_ANY)
+           {
+             stream_putc (s, NEXTHOP_TYPE_IPV4);
+             stream_put_in_addr (s, &path->nexthop);
+           }
+         else
+           {
+             stream_putc (s, NEXTHOP_TYPE_IFINDEX);
+             if (path->ifindex)
+               stream_putl (s, path->ifindex);
+             else
+               stream_putl (s, 0);
+           }
+#else  /* HAVE_NETLINK */
+          if (path->nexthop.s_addr != INADDR_ANY &&
+             path->ifindex != 0)
+            {
+              stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+              stream_put_in_addr (s, &path->nexthop);
+             stream_putl (s, path->ifindex);
+            }
+          else if (path->nexthop.s_addr != INADDR_ANY)
             {
-              stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+              stream_putc (s, NEXTHOP_TYPE_IPV4);
               stream_put_in_addr (s, &path->nexthop);
             }
           else
             {
-              stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
-              if (path->oi)
-                stream_putl (s, path->oi->ifp->ifindex);
+              stream_putc (s, NEXTHOP_TYPE_IFINDEX);
+              if (path->ifindex)
+                stream_putl (s, path->ifindex);
               else
                 stream_putl (s, 0);
             }
+#endif /* HAVE_NETLINK */
 
           if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
             {
-              zlog_info ("Zebra: Route add %s/%d nexthop %s",
-                         inet_ntoa (p->prefix),
-                         p->prefixlen, inet_ntoa (path->nexthop));
+             char buf[2][INET_ADDRSTRLEN];
+             zlog_debug("Zebra: Route add %s/%d nexthop %s, ifindex=%d",
+                        inet_ntop(AF_INET, &p->prefix,
+                                  buf[0], sizeof(buf[0])),
+                        p->prefixlen,
+                        inet_ntop(AF_INET, &path->nexthop,
+                                  buf[1], sizeof(buf[1])),
+                        path->ifindex);
             }
         }
 
@@ -396,67 +478,104 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
             stream_putl (s, or->cost);
         }
 
+      if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+         stream_putw (s, (u_short)or->u.ext.tag);
+
       stream_putw_at (s, 0, stream_get_endp (s));
 
-      writen (zclient->sock, s->data, stream_get_endp (s));
+      zclient_send_message(zclient);
     }
 }
 
 void
 ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or)
 {
-  struct zapi_ipv4 api;
+  u_char message;
+  u_char distance;
+  u_char flags;
+  int psize;
+  struct stream *s;
   struct ospf_path *path;
-  struct in_addr *nexthop;
-  listnode node;
+  struct listnode *node;
+  struct ospf *ospf = ospf_lookup ();
 
-  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+  if ((ospf->instance &&
+      redist_check_instance(&zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF], ospf->instance))
+    ||
+     vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF], VRF_DEFAULT))
     {
-      api.type = ZEBRA_ROUTE_OSPF;
-      api.flags = 0;
-      api.message = 0;
-      api.ifindex_num = 0;
-      api.nexthop_num = 0;
+      message = 0;
+      flags = 0;
+      /* Distance value. */
+      distance = ospf_distance_apply (p, or);
+      /* Make packet. */
+      s = zclient->obuf;
+      stream_reset (s);
 
-      for (node = listhead (or->paths); node; nextnode (node))
-        {
-          path = getdata (node);
+      /* Put command, type, flags, message. */
+      zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT);
+      stream_putc (s, ZEBRA_ROUTE_OSPF);
+      stream_putw (s, ospf->instance);
+      stream_putc (s, flags);
+      stream_putc (s, message);
+      stream_putw (s, SAFI_UNICAST);
 
-          if (path->nexthop.s_addr != INADDR_ANY)
-            {
-              SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
-              api.nexthop_num = 1;
-              nexthop = &path->nexthop;
-              api.nexthop = &nexthop;
-            }
-          else if (ospf_if_exists(path->oi) && (path->oi->ifp))
-            {
-              SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
-              api.ifindex_num = 1;
-              api.ifindex = &path->oi->ifp->ifindex;
-            }
-          else if ( IS_DEBUG_OSPF(zebra,ZEBRA_REDISTRIBUTE) )
-            {
-              zlog_info("Zebra: no ifp %s %d",
-                         inet_ntoa(p->prefix),
-                         p->prefixlen);
-            }
+      /* Put prefix information. */
+      psize = PSIZE (p->prefixlen);
+      stream_putc (s, p->prefixlen);
+      stream_write (s, (u_char *) & p->prefix, psize);
 
-          zapi_ipv4_delete (zclient, p, &api);
+      /* Nexthop count. */
+      stream_putc (s, or->paths->count);
 
-          if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE) && api.nexthop_num)
-            {
-              zlog_info ("Zebra: Route delete %s/%d nexthop %s",
-                         inet_ntoa (p->prefix),
-                         p->prefixlen, inet_ntoa (**api.nexthop));
-            }
-          if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE) && api.ifindex_num)
-            {
-              zlog_info ("Zebra: Route delete %s/%d ifindex %d",
-                         inet_ntoa (p->prefix),
-                         p->prefixlen, *api.ifindex);
-            }
-        }
+      /* Nexthop, ifindex, distance and metric information. */
+      for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
+       {
+         if (path->nexthop.s_addr != INADDR_ANY &&
+             path->ifindex != 0)
+           {
+             stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+             stream_put_in_addr (s, &path->nexthop);
+             stream_putl (s, path->ifindex);
+           }
+         else if (path->nexthop.s_addr != INADDR_ANY)
+           {
+             stream_putc (s, NEXTHOP_TYPE_IPV4);
+             stream_put_in_addr (s, &path->nexthop);
+           }
+         else
+           {
+             stream_putc (s, NEXTHOP_TYPE_IFINDEX);
+             stream_putl (s, path->ifindex);
+           }
+
+         if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+           {
+             char buf[2][INET_ADDRSTRLEN];
+             zlog_debug("Zebra: Route delete %s/%d nexthop %s",
+                        inet_ntop(AF_INET, &p->prefix,
+                                  buf[0], sizeof(buf[0])),
+                        p->prefixlen,
+                        inet_ntop(AF_INET, &path->nexthop,
+                                  buf[1], sizeof(buf[1])));
+           }
+       }
+
+      if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+       stream_putc (s, distance);
+      if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+       {
+         if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
+           stream_putl (s, or->cost + or->u.ext.type2_cost);
+         else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
+           stream_putl (s, or->u.ext.type2_cost);
+         else
+           stream_putl (s, or->cost);
+       }
+
+      stream_putw_at (s, 0, stream_get_endp (s));
+
+      zclient_send_message(zclient);
     }
 }
 
@@ -464,17 +583,29 @@ void
 ospf_zebra_add_discard (struct prefix_ipv4 *p)
 {
   struct zapi_ipv4 api;
+  struct ospf *ospf = ospf_lookup ();
 
-  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+  if ((ospf->instance &&
+      redist_check_instance(&zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF], ospf->instance))
+    ||
+     vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF], VRF_DEFAULT))
     {
+      api.vrf_id = VRF_DEFAULT;
       api.type = ZEBRA_ROUTE_OSPF;
+      api.instance = ospf->instance;
       api.flags = ZEBRA_FLAG_BLACKHOLE;
       api.message = 0;
+      api.safi = SAFI_UNICAST;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
       api.nexthop_num = 0;
       api.ifindex_num = 0;
+      api.tag = 0;
 
-      zapi_ipv4_add (zclient, p, &api);
+      zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api);
+
+      if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+        zlog_debug ("Zebra: Route add discard %s/%d",
+                   inet_ntoa (p->prefix), p->prefixlen);
     }
 }
 
@@ -482,69 +613,209 @@ void
 ospf_zebra_delete_discard (struct prefix_ipv4 *p)
 {
   struct zapi_ipv4 api;
+  struct ospf *ospf = ospf_lookup ();
 
-  if (zclient->redist[ZEBRA_ROUTE_OSPF])
+  if ((ospf->instance &&
+      redist_check_instance(&zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF], ospf->instance))
+    ||
+     vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF], VRF_DEFAULT))
     {
+      api.vrf_id = VRF_DEFAULT;
       api.type = ZEBRA_ROUTE_OSPF;
+      api.instance = ospf->instance;
       api.flags = ZEBRA_FLAG_BLACKHOLE;
       api.message = 0;
+      api.safi = SAFI_UNICAST;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
       api.nexthop_num = 0;
       api.ifindex_num = 0;
+      api.tag = 0;
 
-      zapi_ipv4_delete (zclient, p, &api);
+      zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
 
       if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-        zlog_info ("Zebra: Route delete discard %s/%d",
+        zlog_debug ("Zebra: Route delete discard %s/%d",
                    inet_ntoa (p->prefix), p->prefixlen);
 
     }
 }
 
+struct ospf_external *
+ospf_external_lookup (u_char type, u_short instance)
+{
+  struct list *ext_list;
+  struct listnode *node;
+  struct ospf_external *ext;
+
+  ext_list = om->external[type];
+  if (!ext_list)
+    return(NULL);
+
+  for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext))
+    if (ext->instance == instance)
+      return ext;
+
+  return NULL;
+}
+
+struct ospf_external *
+ospf_external_add (u_char type, u_short instance)
+{
+  struct list *ext_list;
+  struct ospf_external *ext;
+
+  ext = ospf_external_lookup(type, instance);
+  if (ext)
+    return ext;
+
+  if (!om->external[type])
+    om->external[type] = list_new();
+
+  ext_list = om->external[type];
+  ext = (struct ospf_external *)calloc (1, sizeof(struct ospf_external));
+  ext->instance = instance;
+  EXTERNAL_INFO (ext) = route_table_init ();
+
+  listnode_add(ext_list, ext);
+
+  return ext;
+}
+
+void
+ospf_external_del (u_char type, u_short instance)
+{
+  struct ospf_external *ext;
+
+  ext = ospf_external_lookup(type, instance);
+
+  if (ext)
+    {
+      if (EXTERNAL_INFO (ext))
+        route_table_finish(EXTERNAL_INFO (ext));
+
+      listnode_delete(om->external[type], ext);
+      if (!om->external[type]->count)
+        {
+          list_free(om->external[type]);
+          om->external[type] = NULL;
+        }
+    }
+}
+
+struct ospf_redist *
+ospf_redist_lookup (struct ospf *ospf, u_char type, u_short instance)
+{
+  struct list *red_list;
+  struct listnode *node;
+  struct ospf_redist *red;
+
+  red_list = ospf->redist[type];
+  if (!red_list)
+    return(NULL);
+
+  for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
+    if (red->instance == instance)
+      return red;
+
+  return NULL;
+}
+
+struct ospf_redist *
+ospf_redist_add (struct ospf *ospf, u_char type, u_short instance)
+{
+  struct list *red_list;
+  struct ospf_redist *red;
+
+  red = ospf_redist_lookup(ospf, type, instance);
+  if (red)
+    return red;
+
+  if (!ospf->redist[type])
+    ospf->redist[type] = list_new();
+
+  red_list = ospf->redist[type];
+  red = (struct ospf_redist *)calloc (1, sizeof(struct ospf_redist));
+  red->instance = instance;
+  red->dmetric.type = -1;
+  red->dmetric.value = -1;
+
+  listnode_add(red_list, red);
+
+  return red;
+}
+
+void
+ospf_redist_del (struct ospf *ospf, u_char type, u_short instance)
+{
+  struct ospf_redist *red;
+
+  red = ospf_redist_lookup(ospf, type, instance);
+
+  if (red)
+    {
+      listnode_delete(ospf->redist[type], red);
+      if (!ospf->redist[type]->count)
+        {
+          list_free(ospf->redist[type]);
+          ospf->redist[type] = NULL;
+        }
+    }
+}
+
+
 int
-ospf_is_type_redistributed (int type)
+ospf_is_type_redistributed (int type, u_short instance)
 {
-  return (DEFAULT_ROUTE_TYPE (type)) ?
-    zclient->default_information : zclient->redist[type];
+  return (DEFAULT_ROUTE_TYPE (type) ?
+    vrf_bitmap_check (zclient->default_information, VRF_DEFAULT) :
+    ((instance && redist_check_instance(&zclient->mi_redist[AFI_IP][type], instance))
+     || (!instance && vrf_bitmap_check (zclient->redist[AFI_IP][type], VRF_DEFAULT))));
 }
 
 int
-ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue)
+ospf_redistribute_set (struct ospf *ospf, int type, u_short instance, int mtype,
+                       int mvalue)
 {
   int force = 0;
+  struct ospf_redist *red;
 
-  if (ospf_is_type_redistributed (type))
+  red = ospf_redist_lookup(ospf, type, instance);
+  if (ospf_is_type_redistributed (type, instance))
     {
-      if (mtype != ospf->dmetric[type].type)
+      if (mtype != red->dmetric.type)
         {
-          ospf->dmetric[type].type = mtype;
+          red->dmetric.type = mtype;
           force = LSA_REFRESH_FORCE;
         }
-      if (mvalue != ospf->dmetric[type].value)
+      if (mvalue != red->dmetric.value)
         {
-          ospf->dmetric[type].value = mvalue;
+          red->dmetric.value = mvalue;
           force = LSA_REFRESH_FORCE;
         }
 
-      ospf_external_lsa_refresh_type (ospf, type, force);
+      ospf_external_lsa_refresh_type (ospf, type, instance, force);
 
       if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-        zlog_info ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
-                   LOOKUP (ospf_redistributed_proto, type),
-                   metric_type (ospf, type), metric_value (ospf, type));
+        zlog_debug ("Redistribute[%s][%d]: Refresh  Type[%d], Metric[%d]",
+                   ospf_redist_string(type), instance,
+                   metric_type (ospf, type, instance),
+                   metric_value (ospf, type, instance));
 
       return CMD_SUCCESS;
     }
 
-  ospf->dmetric[type].type = mtype;
-  ospf->dmetric[type].value = mvalue;
+  red->dmetric.type = mtype;
+  red->dmetric.value = mvalue;
+
+  ospf_external_add(type, instance);
 
-  zclient_redistribute_set (zclient, type);
+  zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
+                        instance, VRF_DEFAULT);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-    zlog_info ("Redistribute[%s]: Start  Type[%d], Metric[%d]",
-               LOOKUP (ospf_redistributed_proto, type),
-               metric_type (ospf, type), metric_value (ospf, type));
+    zlog_debug ("Redistribute[%s][%d]: Start  Type[%d], Metric[%d]",
+               ospf_redist_string(type), instance,
+               metric_type (ospf, type, instance), metric_value (ospf, type, instance));
 
   ospf_asbr_status_update (ospf, ++ospf->redistribute);
 
@@ -552,25 +823,27 @@ ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue)
 }
 
 int
-ospf_redistribute_unset (struct ospf *ospf, int type)
+ospf_redistribute_unset (struct ospf *ospf, int type, u_short instance)
 {
-  if (type == zclient->redist_default)
+  if (type == zclient->redist_default && instance == zclient->instance)
     return CMD_SUCCESS;
 
-  if (!ospf_is_type_redistributed (type))
+  if (!ospf_is_type_redistributed (type, instance))
     return CMD_SUCCESS;
 
-  zclient_redistribute_unset (zclient, type);
+  zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP, type,
+                        instance, VRF_DEFAULT);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-    zlog_info ("Redistribute[%s]: Stop",
-               LOOKUP (ospf_redistributed_proto, type));
+    zlog_debug ("Redistribute[%s][%d]: Stop",
+               ospf_redist_string(type), instance);
 
-  ospf->dmetric[type].type = -1;
-  ospf->dmetric[type].value = -1;
+  ospf_redist_del (ospf, type, instance);
 
   /* Remove the routes from OSPF table. */
-  ospf_redistribute_withdraw (type);
+  ospf_redistribute_withdraw (ospf, type, instance);
+
+  ospf_external_del(type, instance);
 
   ospf_asbr_status_update (ospf, --ospf->redistribute);
 
@@ -581,47 +854,43 @@ int
 ospf_redistribute_default_set (struct ospf *ospf, int originate,
                                int mtype, int mvalue)
 {
-  int force = 0;
+  struct ospf_redist *red;
 
-  if (ospf_is_type_redistributed (DEFAULT_ROUTE))
-    {
-      if (mtype != ospf->dmetric[DEFAULT_ROUTE].type)
-        {
-          ospf->dmetric[DEFAULT_ROUTE].type = mtype;
-          force = 1;
-        }
-      if (mvalue != ospf->dmetric[DEFAULT_ROUTE].value)
-        {
-          force = 1;
-          ospf->dmetric[DEFAULT_ROUTE].value = mvalue;
-        }
+  ospf->default_originate = originate;
+
+  red = ospf_redist_add(ospf, DEFAULT_ROUTE, 0);
+  red->dmetric.type = mtype;
+  red->dmetric.value = mvalue;
+
+  ospf_external_add(DEFAULT_ROUTE, 0);
 
+  if (ospf_is_type_redistributed (DEFAULT_ROUTE, 0))
+    {
+      /* if ospf->default_originate changes value, is calling
+        ospf_external_lsa_refresh_default sufficient to implement
+        the change? */
       ospf_external_lsa_refresh_default (ospf);
 
       if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-        zlog_info ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
-                   LOOKUP (ospf_redistributed_proto, DEFAULT_ROUTE),
-                   metric_type (ospf, DEFAULT_ROUTE),
-                   metric_value (ospf, DEFAULT_ROUTE));
+        zlog_debug ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
+                   ospf_redist_string(DEFAULT_ROUTE),
+                   metric_type (ospf, DEFAULT_ROUTE, 0),
+                   metric_value (ospf, DEFAULT_ROUTE, 0));
       return CMD_SUCCESS;
     }
 
-  ospf->default_originate = originate;
-  ospf->dmetric[DEFAULT_ROUTE].type = mtype;
-  ospf->dmetric[DEFAULT_ROUTE].value = mvalue;
-
-  zclient_redistribute_default_set (zclient);
+  zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient,
+                                VRF_DEFAULT);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-    zlog_info ("Redistribute[DEFAULT]: Start  Type[%d], Metric[%d]",
-               metric_type (ospf, DEFAULT_ROUTE),
-               metric_value (ospf, DEFAULT_ROUTE));
+    zlog_debug ("Redistribute[DEFAULT]: Start  Type[%d], Metric[%d]",
+               metric_type (ospf, DEFAULT_ROUTE, 0),
+               metric_value (ospf, DEFAULT_ROUTE, 0));
 
   if (ospf->router_id.s_addr == 0)
     ospf->external_origin |= (1 << DEFAULT_ROUTE);
   else
-    thread_add_timer (master, ospf_default_originate_timer,
-                      &ospf->default_originate, 1);
+    thread_add_timer (master, ospf_default_originate_timer, ospf, 1);
 
   ospf_asbr_status_update (ospf, ++ospf->redistribute);
 
@@ -631,24 +900,26 @@ ospf_redistribute_default_set (struct ospf *ospf, int originate,
 int
 ospf_redistribute_default_unset (struct ospf *ospf)
 {
-  if (!ospf_is_type_redistributed (DEFAULT_ROUTE))
+  if (!ospf_is_type_redistributed (DEFAULT_ROUTE, 0))
     return CMD_SUCCESS;
 
   ospf->default_originate = DEFAULT_ORIGINATE_NONE;
-  ospf->dmetric[DEFAULT_ROUTE].type = -1;
-  ospf->dmetric[DEFAULT_ROUTE].value = -1;
+  ospf_redist_del(ospf, DEFAULT_ROUTE, 0);
 
-  zclient_redistribute_default_unset (zclient);
+  zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient,
+                                VRF_DEFAULT);
 
   if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-    zlog_info ("Redistribute[DEFAULT]: Stop");
+    zlog_debug ("Redistribute[DEFAULT]: Stop");
+
+  //Pending: how does the external_info cleanup work in this case?
 
   ospf_asbr_status_update (ospf, --ospf->redistribute);
 
   return CMD_SUCCESS;
 }
 
-int
+static int
 ospf_external_lsa_originate_check (struct ospf *ospf,
                                    struct external_info *ei)
 {
@@ -664,7 +935,7 @@ ospf_external_lsa_originate_check (struct ospf *ospf,
   if (is_prefix_default (&ei->p))
     if (ospf->default_originate == DEFAULT_ORIGINATE_NONE)
       {
-        zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-exntenal-LSA "
+        zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-external-LSA "
                    "for default");
         return 0;
       }
@@ -676,16 +947,13 @@ ospf_external_lsa_originate_check (struct ospf *ospf,
 int
 ospf_distribute_check_connected (struct ospf *ospf, struct external_info *ei)
 {
-  struct route_node *rn;
+  struct listnode *node;
+  struct ospf_interface *oi;
 
-  for (rn = route_top (ospf->networks); rn; rn = route_next (rn))
-    if (rn->info != NULL)
-      if (prefix_match (&rn->p, (struct prefix *) &ei->p))
-        {
-          route_unlock_node (rn);
-          return 0;
-        }
 
+  for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
+      if (prefix_match (oi->address, (struct prefix *) &ei->p))
+          return 0;
   return 1;
 }
 
@@ -696,7 +964,9 @@ ospf_redistribute_check (struct ospf *ospf,
 {
   struct route_map_set_values save_values;
   struct prefix_ipv4 *p = &ei->p;
+  struct ospf_redist *red;
   u_char type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
+  u_short instance = is_prefix_default (&ei->p) ? 0 : ei->instance;
 
   if (changed)
     *changed = 0;
@@ -715,8 +985,8 @@ ospf_redistribute_check (struct ospf *ospf,
       if (access_list_apply (DISTRIBUTE_LIST (ospf, type), p) == FILTER_DENY)
         {
           if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-            zlog_info ("Redistribute[%s]: %s/%d filtered by ditribute-list.",
-                       LOOKUP (ospf_redistributed_proto, type),
+            zlog_debug ("Redistribute[%s]: %s/%d filtered by ditribute-list.",
+                       ospf_redist_string(type),
                        inet_ntoa (p->prefix), p->prefixlen);
           return 0;
         }
@@ -725,19 +995,20 @@ ospf_redistribute_check (struct ospf *ospf,
   ospf_reset_route_map_set_values (&ei->route_map_set);
 
   /* apply route-map if needed */
-  if (ROUTEMAP_NAME (ospf, type))
+  red = ospf_redist_lookup (ospf, type, instance);
+  if (red && ROUTEMAP_NAME(red))
     {
       int ret;
 
-      ret = route_map_apply (ROUTEMAP (ospf, type), (struct prefix *) p,
+      ret = route_map_apply (ROUTEMAP (red), (struct prefix *) p,
                              RMAP_OSPF, ei);
 
       if (ret == RMAP_DENYMATCH)
         {
           ei->route_map_set = save_values;
           if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
-            zlog_info ("Redistribute[%s]: %s/%d filtered by route-map.",
-                       LOOKUP (ospf_redistributed_proto, type),
+            zlog_debug ("Redistribute[%s]: %s/%d filtered by route-map.",
+                       ospf_redist_string(type),
                        inet_ntoa (p->prefix), p->prefixlen);
           return 0;
         }
@@ -753,29 +1024,29 @@ ospf_redistribute_check (struct ospf *ospf,
 
 /* OSPF route-map set for redistribution */
 void
-ospf_routemap_set (struct ospf *ospf, int type, char *name)
+ospf_routemap_set (struct ospf_redist *red, const char *name)
 {
-  if (ROUTEMAP_NAME (ospf, type))
-    free (ROUTEMAP_NAME (ospf, type));
+  if (ROUTEMAP_NAME (red))
+    free (ROUTEMAP_NAME (red));
 
-  ROUTEMAP_NAME (ospf, type) = strdup (name);
-  ROUTEMAP (ospf, type) = route_map_lookup_by_name (name);
+  ROUTEMAP_NAME (red) = strdup (name);
+  ROUTEMAP (red) = route_map_lookup_by_name (name);
 }
 
 void
-ospf_routemap_unset (struct ospf *ospf, int type)
+ospf_routemap_unset (struct ospf_redist *red)
 {
-  if (ROUTEMAP_NAME (ospf, type))
-    free (ROUTEMAP_NAME (ospf, type));
+  if (ROUTEMAP_NAME (red))
+    free (ROUTEMAP_NAME (red));
 
-  ROUTEMAP_NAME (ospf, type) = NULL;
-  ROUTEMAP (ospf, type) = NULL;
+  ROUTEMAP_NAME (red) = NULL;
+  ROUTEMAP (red) = NULL;
 }
 
 /* Zebra route add and delete treatment. */
-int
+static int
 ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
-                      zebra_size_t length)
+                      zebra_size_t length, vrf_id_t vrf_id)
 {
   struct stream *s;
   struct zapi_ipv4 api;
@@ -784,6 +1055,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
   struct prefix_ipv4 p;
   struct external_info *ei;
   struct ospf *ospf;
+  int i;
 
   s = zclient->ibuf;
   ifindex = 0;
@@ -791,15 +1063,19 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
 
   /* Type, flags, message. */
   api.type = stream_getc (s);
+  api.instance = stream_getw (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv4));
   p.family = AF_INET;
-  p.prefixlen = stream_getc (s);
+  p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s));
   stream_get (&p.prefix, s, PSIZE (p.prefixlen));
 
+  if (IPV4_NET127(ntohl(p.prefix.s_addr)))
+    return 0;
+
   /* Nexthop, ifindex, distance, metric. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
     {
@@ -809,30 +1085,55 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
     {
       api.ifindex_num = stream_getc (s);
+      /* XXX assert(api.ifindex_num == 1); */
       ifindex = stream_getl (s);
     }
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+    api.tag = stream_getw (s);
+  else
+    api.tag = 0;
 
   ospf = ospf_lookup ();
   if (ospf == NULL)
     return 0;
 
-  if (command == ZEBRA_IPV4_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
     {
       /* XXX|HACK|TODO|FIXME:
-       * ignore reject/blackhole routes 
-       * need a better generalised solution for these types
-       * really.
+       * Maybe we should ignore reject/blackhole routes? Testing shows that
+       * there is no problems though and this is only way to "summarize"
+       * routes in ASBR at the moment. Maybe we need just a better generalised
+       * solution for these types?
+       *
+       * if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE)
+       *     || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT))
+       * return 0;
        */
-      if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE)
-           || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT))
-        return 0;
-        
-      ei = ospf_external_info_add (api.type, p, ifindex, nexthop);
 
+      /* Protocol tag overwrites all other tag value send by zebra */
+      if (ospf->dtag[api.type] > 0)
+       api.tag = ospf->dtag[api.type];
+
+      /*
+       * Given zebra sends update for a prefix via ADD message, it should
+       * be considered as an implicit DEL for that prefix with other source
+       * types.
+       */
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+        if (i != api.type)
+          ospf_external_info_delete(i, api.instance, p);
+
+      ei = ospf_external_info_add (api.type, api.instance, p, ifindex,
+                                   nexthop, api.tag);
+      if (ei == NULL)
+       {
+         /* Nothing has changed, so nothing to do; return */
+         return 0;
+       }
       if (ospf->router_id.s_addr == 0)
         /* Set flags to generate AS-external-LSA originate event
            for each redistributed protocols later. */
@@ -850,31 +1151,33 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
                   current = ospf_external_info_find_lsa (ospf, &ei->p);
                   if (!current)
                     ospf_external_lsa_originate (ospf, ei);
-                  else if (IS_LSA_MAXAGE (current))
-                    ospf_external_lsa_refresh (ospf, current,
-                                               ei, LSA_REFRESH_FORCE);
                   else
-                    zlog_warn ("ospf_zebra_read_ipv4() : %s already exists",
-                               inet_ntoa (p.prefix));
+                   {
+                     if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+                       zlog_debug ("ospf_zebra_read_ipv4() : %s refreshing LSA",
+                                   inet_ntoa (p.prefix));
+                     ospf_external_lsa_refresh (ospf, current,
+                                                ei, LSA_REFRESH_FORCE);
+                   }
                 }
             }
         }
     }
-  else                          /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
+  else                          /* if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL) */
     {
-      ospf_external_info_delete (api.type, p);
+      ospf_external_info_delete (api.type, api.instance, p);
       if (is_prefix_default (&p))
         ospf_external_lsa_refresh_default (ospf);
       else
-        ospf_external_lsa_flush (ospf, api.type, &p, ifindex, nexthop);
+        ospf_external_lsa_flush (ospf, api.type, &p, ifindex /*, nexthop */);
     }
 
   return 0;
 }
-\f
+
 
 int
-ospf_distribute_list_out_set (struct ospf *ospf, int type, char *name)
+ospf_distribute_list_out_set (struct ospf *ospf, int type, const char *name)
 {
   /* Lookup access-list for distribute-list. */
   DISTRIBUTE_LIST (ospf, type) = access_list_lookup (AFI_IP, name);
@@ -888,17 +1191,17 @@ ospf_distribute_list_out_set (struct ospf *ospf, int type, char *name)
 
   /* If access-list have been set, schedule update timer. */
   if (DISTRIBUTE_LIST (ospf, type))
-    ospf_distribute_list_update (ospf, type);
+    ospf_distribute_list_update (ospf, type, 0);
 
   return CMD_SUCCESS;
 }
 
 int
-ospf_distribute_list_out_unset (struct ospf *ospf, int type, char *name)
+ospf_distribute_list_out_unset (struct ospf *ospf, int type, const char *name)
 {
   /* Schedule update timer. */
   if (DISTRIBUTE_LIST (ospf, type))
-    ospf_distribute_list_update (ospf, type);
+    ospf_distribute_list_update (ospf, type, 0);
 
   /* Unset distribute-list. */
   DISTRIBUTE_LIST (ospf, type) = NULL;
@@ -913,19 +1216,16 @@ ospf_distribute_list_out_unset (struct ospf *ospf, int type, char *name)
 }
 
 /* distribute-list update timer. */
-int
+static int
 ospf_distribute_list_update_timer (struct thread *thread)
 {
   struct route_node *rn;
   struct external_info *ei;
   struct route_table *rt;
   struct ospf_lsa *lsa;
-  u_char type;
+  int type, default_refresh = 0;
   struct ospf *ospf;
 
-  type = (int) THREAD_ARG (thread);
-  rt = EXTERNAL_INFO (type);
-
   ospf = ospf_lookup ();
   if (ospf == NULL)
     return 0;
@@ -935,67 +1235,98 @@ ospf_distribute_list_update_timer (struct thread *thread)
   zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!");
 
   /* foreach all external info. */
-  if (rt)
-    for (rn = route_top (rt); rn; rn = route_next (rn))
-      if ((ei = rn->info) != NULL)
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    {
+      struct list *ext_list;
+      struct listnode *node;
+      struct ospf_external *ext;
+
+      ext_list = om->external[type];
+      if (!ext_list)
+        continue;
+
+      for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext))
         {
-          if (is_prefix_default (&ei->p))
-            ospf_external_lsa_refresh_default (ospf);
-          else if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p)))
-            ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_IF_CHANGED);
-          else
-            ospf_external_lsa_originate (ospf, ei);
+          rt = ext->external_info;
+          if (!rt)
+            continue;
+          for (rn = route_top (rt); rn; rn = route_next (rn))
+            if ((ei = rn->info) != NULL)
+              {
+                if (is_prefix_default (&ei->p))
+                  default_refresh = 1;
+                else if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p)))
+                  ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_IF_CHANGED);
+                else
+                  ospf_external_lsa_originate (ospf, ei);
+              }
         }
+    }
+  if (default_refresh)
+    ospf_external_lsa_refresh_default (ospf);
   return 0;
 }
 
-#define OSPF_DISTRIBUTE_UPDATE_DELAY 5
-
 /* Update distribute-list and set timer to apply access-list. */
 void
-ospf_distribute_list_update (struct ospf *ospf, int type)
+ospf_distribute_list_update (struct ospf *ospf, uintptr_t type,
+                             u_short instance)
 {
   struct route_table *rt;
+  struct ospf_external *ext;
 
   /* External info does not exist. */
-  if (!(rt = EXTERNAL_INFO (type)))
+  ext = ospf_external_lookup(type, instance);
+  if (!ext || !(rt = EXTERNAL_INFO (ext)))
     return;
 
-  /* If exists previously invoked thread, then cancel it. */
+  /* If exists previously invoked thread, then let it continue. */
   if (ospf->t_distribute_update)
-    OSPF_TIMER_OFF (ospf->t_distribute_update);
+    return;
 
   /* Set timer. */
   ospf->t_distribute_update =
-    thread_add_timer (master, ospf_distribute_list_update_timer,
-                      (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY);
+    thread_add_timer_msec (master, ospf_distribute_list_update_timer,
+                           (void *) type, ospf->min_ls_interval);
 }
 
 /* If access-list is updated, apply some check. */
-void
+static void
 ospf_filter_update (struct access_list *access)
 {
   struct ospf *ospf;
   int type;
   int abr_inv = 0;
   struct ospf_area *area;
-  listnode node;
+  struct listnode *node;
 
-  /* If OSPF instatnce does not exist, return right now. */
+  /* If OSPF instance does not exist, return right now. */
   ospf = ospf_lookup ();
   if (ospf == NULL)
     return;
 
   /* Update distribute-list, and apply filter. */
-  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
     {
-      if (ROUTEMAP (ospf, type) != NULL)
-        {
-          /* if route-map is not NULL it may be using this access list */
-          ospf_distribute_list_update (ospf, type);
-          continue;
-        }
+      struct list *red_list;
+      struct listnode *node;
+      struct ospf_redist *red;
+
+      red_list = ospf->redist[type];
+      if (red_list)
+        for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
+          {
+            if (ROUTEMAP (red))
+              {
+                /* if route-map is not NULL it may be using this access list */
+                ospf_distribute_list_update (ospf, type, red->instance);
+              }
+          }
 
+      /* There is place for route-map for default-information (ZEBRA_ROUTE_MAX),
+       * but no distribute list. */
+      if (type == ZEBRA_ROUTE_MAX)
+       break;
 
       if (DISTRIBUTE_NAME (ospf, type))
         {
@@ -1013,51 +1344,111 @@ ospf_filter_update (struct access_list *access)
           /* Schedule distribute-list update timer. */
           if (DISTRIBUTE_LIST (ospf, type) == NULL ||
               strcmp (DISTRIBUTE_NAME (ospf, type), access->name) == 0)
-            ospf_distribute_list_update (ospf, type);
+            ospf_distribute_list_update (ospf, type, 0);
         }
     }
 
   /* Update Area access-list. */
-  for (node = listhead (ospf->areas); node; nextnode (node))
-    if ((area = getdata (node)) != NULL)
-      {
-        if (EXPORT_NAME (area))
+  for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
+    {
+      if (EXPORT_NAME (area))
+        {
+          EXPORT_LIST (area) = NULL;
+          abr_inv++;
+        }
+
+      if (IMPORT_NAME (area))
+        {
+          IMPORT_LIST (area) = NULL;
+          abr_inv++;
+        }
+    }
+
+  /* Schedule ABR tasks -- this will be changed -- takada. */
+  if (IS_OSPF_ABR (ospf) && abr_inv)
+    ospf_schedule_abr_task (ospf);
+}
+
+/* If prefix-list is updated, do some updates. */
+void
+ospf_prefix_list_update (struct prefix_list *plist)
+{
+  struct ospf *ospf;
+  int type;
+  int abr_inv = 0;
+  struct ospf_area *area;
+  struct listnode *node;
+
+  /* If OSPF instatnce does not exist, return right now. */
+  ospf = ospf_lookup ();
+  if (ospf == NULL)
+    return;
+
+  /* Update all route-maps which are used as redistribution filters.
+   * They might use prefix-list.
+   */
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    {
+      struct list *red_list;
+      struct listnode *node;
+      struct ospf_redist *red;
+
+      red_list = ospf->redist[type];
+      if (red_list)
+        for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
           {
-            EXPORT_LIST (area) = NULL;
+            if (ROUTEMAP (red))
+              {
+                /* if route-map is not NULL it may be using this prefix list */
+                ospf_distribute_list_update (ospf, type, red->instance);
+              }
+          }
+    }
+
+  /* Update area filter-lists. */
+  for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area))
+    {
+      /* Update filter-list in. */
+      if (PREFIX_NAME_IN (area))
+        if (strcmp (PREFIX_NAME_IN (area), prefix_list_name (plist)) == 0)
+          {
+            PREFIX_LIST_IN (area) =
+              prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area));
             abr_inv++;
           }
 
-        if (IMPORT_NAME (area))
+      /* Update filter-list out. */
+      if (PREFIX_NAME_OUT (area))
+        if (strcmp (PREFIX_NAME_OUT (area), prefix_list_name (plist)) == 0)
           {
-            IMPORT_LIST (area) = NULL;
+            PREFIX_LIST_IN (area) =
+              prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area));
             abr_inv++;
           }
-      }
+    }
 
-  /* Schedule ABR tasks -- this will be changed -- takada. */
+  /* Schedule ABR task. */
   if (IS_OSPF_ABR (ospf) && abr_inv)
     ospf_schedule_abr_task (ospf);
 }
-\f
 
-struct ospf_distance *
-ospf_distance_new ()
+static struct ospf_distance *
+ospf_distance_new (void)
 {
-  struct ospf_distance *new;
-  new = XMALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance));
-  memset (new, 0, sizeof (struct ospf_distance));
-  return new;
+  return XCALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance));
 }
 
-void
+static void
 ospf_distance_free (struct ospf_distance *odistance)
 {
   XFREE (MTYPE_OSPF_DISTANCE, odistance);
 }
 
 int
-ospf_distance_set (struct vty *vty, struct ospf *ospf, char *distance_str,
-                   char *ip_str, char *access_list_str)
+ospf_distance_set (struct vty *vty, struct ospf *ospf, 
+                   const char *distance_str,
+                   const char *ip_str, 
+                   const char *access_list_str)
 {
   int ret;
   struct prefix_ipv4 p;
@@ -1103,12 +1494,13 @@ ospf_distance_set (struct vty *vty, struct ospf *ospf, char *distance_str,
 }
 
 int
-ospf_distance_unset (struct vty *vty, struct ospf *ospf, char *distance_str,
-                     char *ip_str, char *access_list_str)
+ospf_distance_unset (struct vty *vty, struct ospf *ospf, 
+                     const char *distance_str,
+                     const char *ip_str, char 
+                     const *access_list_str)
 {
   int ret;
   struct prefix_ipv4 p;
-  u_char distance;
   struct route_node *rn;
   struct ospf_distance *odistance;
 
@@ -1119,8 +1511,6 @@ ospf_distance_unset (struct vty *vty, struct ospf *ospf, char *distance_str,
       return CMD_WARNING;
     }
 
-  distance = atoi (distance_str);
-
   rn = route_node_lookup (ospf->distance_table, (struct prefix *) &p);
   if (!rn)
     {
@@ -1186,21 +1576,36 @@ ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or)
   return 0;
 }
 
+static void
+ospf_zebra_connected (struct zclient *zclient)
+{
+  /* Send the client registration */
+  bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+
+  zclient_send_reg_requests (zclient, VRF_DEFAULT);
+}
+
 void
-ospf_zebra_init ()
+ospf_zebra_init (struct thread_master *master, u_short instance)
 {
   /* Allocate zebra structure. */
-  zclient = zclient_new ();
-  zclient_init (zclient, ZEBRA_ROUTE_OSPF);
+  zclient = zclient_new(master);
+  zclient_init (zclient, ZEBRA_ROUTE_OSPF, instance);
+  zclient->zebra_connected = ospf_zebra_connected;
+  zclient->router_id_update = ospf_router_id_update_zebra;
   zclient->interface_add = ospf_interface_add;
   zclient->interface_delete = ospf_interface_delete;
   zclient->interface_up = ospf_interface_state_up;
   zclient->interface_down = ospf_interface_state_down;
   zclient->interface_address_add = ospf_interface_address_add;
   zclient->interface_address_delete = ospf_interface_address_delete;
-  zclient->ipv4_route_add = ospf_zebra_read_ipv4;
-  zclient->ipv4_route_delete = ospf_zebra_read_ipv4;
+  zclient->interface_link_params = ospf_interface_link_params;
+
+  zclient->redistribute_route_ipv4_add = ospf_zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_del = ospf_zebra_read_ipv4;
 
   access_list_add_hook (ospf_filter_update);
   access_list_delete_hook (ospf_filter_update);
+  prefix_list_add_hook (ospf_prefix_list_update);
+  prefix_list_delete_hook (ospf_prefix_list_update);
 }