isisd: add support to import routes from other protocols

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 1201627..8c4eef0 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2001,2002   Sampo Saaristo
  *                           Tampere University of Technology      
  *                           Institute of Communications Engineering
+ * Copyright (C) 2013-2015   Christian Franke <chris@opensourcerouting.org>
  *
  * This program is free software; you can redistribute it and/or modify it 
  * under the terms of the GNU General Public Licenseas published by the Free 
@@ -525,11 +526,14 @@
   struct stream *stream;
   struct zapi_ipv4 api;
   struct prefix_ipv4 p;
+  struct prefix *p_generic = (struct prefix*)&p;
   unsigned long ifindex __attribute__ ((unused));
   struct in_addr nexthop __attribute__ ((unused));
 
   stream = zclient->ibuf;
+  memset(&api, 0, sizeof(api));
   memset (&p, 0, sizeof (struct prefix_ipv4));
+  memset(&nexthop, 0, sizeof(nexthop));
   ifindex = 0;
 
   api.type = stream_getc (stream);
@@ -554,31 +558,80 @@
     api.distance = stream_getc (stream);
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (stream);
-  else
-    api.metric = 0;
+
+  /*
+   * Avoid advertising a false default reachability. (A default
+   * route installed by IS-IS gets redistributed from zebra back
+   * into IS-IS causing us to start advertising default reachabity
+   * without this check)
+   */
+  if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
+    command = ZEBRA_IPV4_ROUTE_DELETE;
 
   if (command == ZEBRA_IPV4_ROUTE_ADD)
-    {
-      if (isis->debugs & DEBUG_ZEBRA)
-	zlog_debug ("IPv4 Route add from Z");
-    }
+    isis_redist_add(api.type, p_generic, api.distance, api.metric);
+  else
+    isis_redist_delete(api.type, p_generic);
 
   return 0;
 }
 
-#ifdef HAVE_IPV6
 static int
 isis_zebra_read_ipv6 (int command, struct zclient *zclient,
 		      zebra_size_t length, vrf_id_t vrf_id)
 {
+  struct stream *stream;
+  struct zapi_ipv6 api;
+  struct prefix_ipv6 p;
+  struct prefix *p_generic = (struct prefix*)&p;
+  struct in6_addr nexthop;
+  unsigned long ifindex __attribute__((unused));
+
+  stream = zclient->ibuf;
+  memset(&api, 0, sizeof(api));
+  memset(&p, 0, sizeof(struct prefix_ipv6));
+  memset(&nexthop, 0, sizeof(nexthop));
+  ifindex = 0;
+
+  api.type = stream_getc(stream);
+  api.flags = stream_getc(stream);
+  api.message = stream_getc(stream);
+
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc(stream);
+  stream_get(&p.prefix, stream, PSIZE(p.prefixlen));
+
+  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc(stream); /* this is always 1 */
+      stream_get(&nexthop, stream, sizeof(nexthop));
+    }
+  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc(stream);
+      ifindex = stream_getl(stream);
+    }
+  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc(stream);
+  if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl(stream);
+
+  /*
+   * Avoid advertising a false default reachability. (A default
+   * route installed by IS-IS gets redistributed from zebra back
+   * into IS-IS causing us to start advertising default reachabity
+   * without this check)
+   */
+  if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
+    command = ZEBRA_IPV6_ROUTE_DELETE;
+
+  if (command == ZEBRA_IPV6_ROUTE_ADD)
+    isis_redist_add(api.type, p_generic, api.distance, api.metric);
+  else
+    isis_redist_delete(api.type, p_generic);
+
   return 0;
 }
-#endif
-
-#define ISIS_TYPE_IS_REDISTRIBUTED(T) \
-T == ZEBRA_ROUTE_MAX ? \
-  vrf_bitmap_check (zclient->default_information, VRF_DEFAULT) : \
-  vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)
 
 int
 isis_distribute_list_update (int routetype)
@@ -586,14 +639,23 @@
   return 0;
 }
 
-#if 0 /* Not yet. */
-static int
-isis_redistribute_default_set (int routetype, int metric_type,
-			       int metric_value)
+void
+isis_zebra_redistribute_set(int type)
 {
-  return 0;
+  if (type == DEFAULT_ROUTE)
+    zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, VRF_DEFAULT);
+  else
+    zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT);
 }
-#endif /* 0 */
+
+void
+isis_zebra_redistribute_unset(int type)
+{
+  if (type == DEFAULT_ROUTE)
+    zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, VRF_DEFAULT);
+  else
+    zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT);
+}
 
 static void
 isis_zebra_connected (struct zclient *zclient)