2005-09-29 Alain Ritoux <alain.ritoux@6wind.com>

    * lib/filer.c: show protocol name in filter_show()
    * lib/plist.c: show protocol name in vty_show_prefix_entry()
    * routemap.c: show protocol name in vty_show_route_map_entry()
    * lib/vty.c: in vty_command(), show protocol name if command unknown

    * zebra/zserv.c: Always provide distance fo route add

    * ripd/rip_snmp.c: rip2IfConfReceive() sends values in conformance
      with RFC. Also PeerDomain is now set to a STRING type.
    * ripd/ripd.h: rip_redistribute_add() API includes metric and distance
    * ripd/ripd.c: rip_redistribute_add() API i.e. stores metric and distance
      Now allows a RIP-route to overcome a redistributed route coming
      from a protocol with worse (higher) administrative distance
      Metrics from redistribution are shown in show ip rip
    * ripd/rip_zebra.c: adapt to the rip_redistribute_add() API, i.e.
      provide distance and metric
    * ripd/rip_interface.c: adapt to the rip_redistribute_add() API
    * ripd/rip_routemap.c: no RMAP_COMPILE_ERROR on (metric > 16) usage
      rather a CMD_WARNING, because set metric ius shared with other
      protocols using larger values (such as OSPF)
      The match metric action takes first external metric if present
      (from redistribution) then RIP metric.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 8a92df3..e060502 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,10 @@
+2005-09-29 Alain Ritoux <alain.ritoux@6wind.com>
+
+	* filer.c: show protocol name in filter_show()
+	* plist.c: show protocol name in vty_show_prefix_entry()
+	* routemap.c: show protocol name in vty_show_route_map_entry()
+	* vty.c: in vty_command(), show protocol name if command unknown
+	
 2005-09-28 Alain Ritoux <alain.ritoux@6wind.com>
 
 	* md5-gnu.h: removed
diff --git a/lib/filter.c b/lib/filter.c
index 55bcdf4..069919b 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -27,6 +27,7 @@
 #include "command.h"
 #include "sockunion.h"
 #include "buffer.h"
+#include "log.h"
 
 struct filter_cisco
 {
@@ -1580,6 +1581,11 @@
   if (master == NULL)
     return 0;
 
+  /* Print the name of the protocol */
+  if (zlog_default)
+      vty_out (vty, "%s:%s",
+      zlog_proto_names[zlog_default->protocol], VTY_NEWLINE);
+
   for (access = master->num.head; access; access = access->next)
     {
       if (name && strcmp (access->name, name) != 0)
diff --git a/lib/plist.c b/lib/plist.c
index 97d254f..83c5aa0 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -28,6 +28,7 @@
 #include "sockunion.h"
 #include "buffer.h"
 #include "stream.h"
+#include "log.h"
 
 /* Each prefix-list's entry. */
 struct prefix_list_entry
@@ -918,6 +919,10 @@
 {
   struct prefix_list_entry *pentry;
 
+  /* Print the name of the protocol */
+  if (zlog_default)
+      vty_out (vty, "%s: ", zlog_proto_names[zlog_default->protocol]);
+                                                                           
   if (dtype == normal_display)
     {
       vty_out (vty, "ip%s prefix-list %s: %d entries%s",
diff --git a/lib/routemap.c b/lib/routemap.c
index 0a4eeb9..a9d94f2 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -205,6 +205,11 @@
   struct route_map_index *index;
   struct route_map_rule *rule;
 
+  /* Print the name of the protocol */
+  if (zlog_default)
+    vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
+             VTY_NEWLINE);
+
   for (index = map->head; index; index = index->next)
     {
       vty_out (vty, "route-map %s, %s, sequence %d%s",
diff --git a/lib/vty.c b/lib/vty.c
index 540f7b9..2f0bd3f 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -388,6 +388,7 @@
 {
   int ret;
   vector vline;
+  const char *protocolname;
 
   /* Split readline string up into the vector */
   vline = cmd_make_strvec (buf);
@@ -406,6 +407,12 @@
 
   ret = cmd_execute_command (vline, vty, NULL, 0);
 
+  /* Get the name of the protocol if any */
+  if (zlog_default)
+      protocolname = zlog_proto_names[zlog_default->protocol];
+  else
+      protocolname = zlog_proto_names[ZLOG_NONE];
+                                                                           
 #ifdef CONSUMED_TIME_CHECK
     GETRUSAGE(&after);
     if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
@@ -427,7 +434,7 @@
 	vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
 	break;
       case CMD_ERR_NO_MATCH:
-	vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
+	vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
 	break;
       case CMD_ERR_INCOMPLETE:
 	vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
diff --git a/ripd/ChangeLog b/ripd/ChangeLog
index 3a9b551..6aecebd 100644
--- a/ripd/ChangeLog
+++ b/ripd/ChangeLog
@@ -1,3 +1,22 @@
+2005-09-29 Alain Ritoux <alain.ritoux@6wind.com>
+
+	* rip_snmp.c: rip2IfConfReceive() sends values in conformance
+	  with RFC. Also PeerDomain is now set to a STRING type.
+	* ripd.h: rip_redistribute_add() API includes metric and distance
+	  added field external_metric in routes.
+	* ripd.c: rip_redistribute_add() API i.e. stores metric and distance
+      Now allows a RIP-route to overcome a redistributed route coming
+	  from a protocol with worse (higher) administrative distance
+	  Metrics from redistribution are shown in show ip rip
+	* rip_zebra.c: adapt to the rip_redistribute_add() API, i.e.
+	  provide distance and metric
+	* rip_interface.c: adapt to the rip_redistribute_add() API
+	* rip_routemap.c: no RMAP_COMPILE_ERROR on (metric > 16) usage
+	  rather a CMD_WARNING, because set metric ius shared with other
+	  protocols using larger values (such as OSPF)
+	  The match metric action takes first external metric if present
+      (from redistribution) then RIP metric.
+
 2005-09-28 Alain Ritoux <alain.ritoux@6wind.com>
 
 	* ripd.c: use new md5 API
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
index 5fa4b7d..85bf3c5 100644
--- a/ripd/rip_interface.c
+++ b/ripd/rip_interface.c
@@ -717,7 +717,7 @@
   if ((rip_enable_if_lookup(ifc->ifp->name) >= 0) ||
       (rip_enable_network_lookup2(ifc) >= 0))
     rip_redistribute_add(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
-                         &address, ifc->ifp->ifindex, NULL);
+                         &address, ifc->ifp->ifindex, NULL, 0, 0);
 
 }
 
@@ -1029,14 +1029,16 @@
         if ((rip_enable_if_lookup(connected->ifp->name) >= 0) ||
             (rip_enable_network_lookup2(connected) >= 0))
           rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
-                                &address, connected->ifp->ifindex, NULL);
+                                &address, connected->ifp->ifindex, 
+                                NULL, 0, 0);
       } else
         {
           rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
                                    &address, connected->ifp->ifindex);
           if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT))
             rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE,
-                                  &address, connected->ifp->ifindex, NULL);
+                                  &address, connected->ifp->ifindex,
+                                  NULL, 0, 0);
         }
     }
 }
diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c
index e7692be..2a2f264 100644
--- a/ripd/rip_routemap.c
+++ b/ripd/rip_routemap.c
@@ -1,4 +1,5 @@
 /* RIPv2 routemap.
+ * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
  * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
  *
  * This file is part of GNU Zebra.
@@ -106,8 +107,14 @@
 	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
 	  return CMD_WARNING;
 	case RMAP_COMPILE_ERROR:
-	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
-	  return CMD_WARNING;
+	  /* rip, ripng and other protocols share the set metric command
+	     but only values from 0 to 16 are valid for rip and ripng
+	     if metric is out of range for rip and ripng, it is not for
+	     other protocols. Do not return an error */
+	  if (strcmp(command, "metric")) {
+	     vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+	     return CMD_WARNING;
+	  }
 	}
     }
   return CMD_SUCCESS;
@@ -161,6 +168,7 @@
 		    route_map_object_t type, void *object)
 {
   u_int32_t *metric;
+  u_int32_t  check;
   struct rip_info *rinfo;
 
   if (type == RMAP_RIP)
@@ -168,7 +176,11 @@
       metric = rule;
       rinfo = object;
     
-      if (rinfo->metric == *metric)
+      /* If external metric is available, the route-map should
+         work on this one (for redistribute purpose)  */
+      check = (rinfo->external_metric) ? rinfo->external_metric :
+                                         rinfo->metric;
+      if (check == *metric)
 	return RMAP_MATCH;
       else
 	return RMAP_NOMATCH;
diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c
index 93773bc..c1bec76 100644
--- a/ripd/rip_snmp.c
+++ b/ripd/rip_snmp.c
@@ -136,7 +136,7 @@
   {RIP2PEERADDRESS,           IPADDRESS, RONLY, rip2PeerTable,
    /* RIP Peer Table. */
    3, {4, 1, 1}},
-  {RIP2PEERDOMAIN,            INTEGER, RONLY, rip2PeerTable,
+  {RIP2PEERDOMAIN,            STRING, RONLY, rip2PeerTable,
    3, {4, 1, 2}},
   {RIP2PEERLASTUPDATE,        TIMETICKS, RONLY, rip2PeerTable,
    3, {4, 1, 3}},
@@ -419,15 +419,19 @@
 #define rip1OrRip2      3
 #define doNotReceive    4
 
+  int recvv;
+
   if (! ri->running)
     return doNotReceive;
 
-  if (ri->ri_receive == RI_RIP_VERSION_1_AND_2)
+  recvv = (ri->ri_receive == RI_RIP_UNSPEC) ?  rip->version_recv :
+                                               ri->ri_receive;
+  if (recvv == RI_RIP_VERSION_1_AND_2)
     return rip1OrRip2;
-  else if (ri->ri_receive & RIPv2)
-    return ripVersion2;
-  else if (ri->ri_receive & RIPv1)
-    return ripVersion1;
+  else if (recvv & RIPv2)
+    return rip2;
+  else if (recvv & RIPv1)
+    return rip1;
   else
     return doNotReceive;
 }
@@ -508,6 +512,7 @@
 	       int exact, size_t *val_len, WriteMethod **write_method)
 {
   static struct in_addr addr;
+  static int domain = 0;
   static int version;
   /* static time_t uptime; */
 
@@ -527,8 +532,8 @@
       return (u_char *) &peer->addr;
 
     case RIP2PEERDOMAIN:
-      *val_len = sizeof (int);
-      return (u_char *) &peer->domain;
+      *val_len = 2;
+      return (u_char *) &domain;
 
     case RIP2PEERLASTUPDATE:
 #if 0 
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
index 734555b..570b528 100644
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -134,12 +134,17 @@
     }
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
+  else
+    api.distance = 255;
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
+  else
+    api.metric = 0;
 
   /* Then fetch IPv4 prefixes. */
   if (command == ZEBRA_IPV4_ROUTE_ADD)
-    rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop);
+    rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, 
+                          &nexthop, api.metric, api.distance);
   else 
     rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex);
 
@@ -597,7 +602,8 @@
 
       rip->default_information = 1;
   
-      rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0, NULL);
+      rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0, 
+                            NULL, 0, 0);
     }
 
   return CMD_SUCCESS;
diff --git a/ripd/ripd.c b/ripd/ripd.c
index b75e018..13cf9b9 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -1,4 +1,5 @@
 /* RIP version 1 and 2.
+ * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
  * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
  *
  * This file is part of GNU Zebra.
@@ -392,6 +393,8 @@
   struct in_addr *nexthop;
   u_char oldmetric;
   int same = 0;
+  int route_reuse = 0;
+  unsigned char old_dist, new_dist;
 
   /* Make prefix structure. */
   memset (&p, 0, sizeof (struct prefix_ipv4));
@@ -480,17 +483,51 @@
 
   if (rinfo)
     {
-      /* Redistributed route check. */
-      if (rinfo->type != ZEBRA_ROUTE_RIP
-          && rinfo->metric != RIP_METRIC_INFINITY)
-        return;
-
       /* Local static route. */
       if (rinfo->type == ZEBRA_ROUTE_RIP
           && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
               (rinfo->sub_type == RIP_ROUTE_DEFAULT))
           && rinfo->metric != RIP_METRIC_INFINITY)
-        return;
+        {
+          route_unlock_node (rp);
+          return;
+        }
+
+      /* Redistributed route check. */
+      if (rinfo->type != ZEBRA_ROUTE_RIP
+          && rinfo->metric != RIP_METRIC_INFINITY)
+        {
+          /* Fill in a minimaly temporary rip_info structure, for a future
+             rip_distance_apply() use) */
+          memset (&rinfotmp, 0, sizeof (rinfotmp));
+          IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
+          rinfotmp.rp = rinfo->rp;
+          new_dist = rip_distance_apply (&rinfotmp);
+          new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
+          old_dist = rinfo->distance;
+          old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
+          /* If imported route does not have STRICT precedence, 
+             mark it as a ghost */
+          if (new_dist > old_dist 
+              || rte->metric == RIP_METRIC_INFINITY)
+            {
+              route_unlock_node (rp);
+              return;
+            }
+          else
+            {
+              RIP_TIMER_OFF (rinfo->t_timeout);
+              RIP_TIMER_OFF (rinfo->t_garbage_collect);
+                                                                                
+              rp->info = NULL;
+              if (rip_route_rte (rinfo))
+                rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, 
+                                        &rinfo->nexthop, rinfo->metric);
+              rip_info_free (rinfo);
+              rinfo = NULL;
+              route_reuse = 1;
+            }
+        }
     }
 
   if (!rinfo)
@@ -544,6 +581,10 @@
                               rinfo->distance);
           rinfo->flags |= RIP_RTF_FIB;
         }
+
+      /* Unlock temporary lock, i.e. same behaviour */
+      if (route_reuse)
+        route_unlock_node (rp);
     }
   else
     {
@@ -1495,7 +1536,8 @@
 /* Add redistributed route to RIP table. */
 void
 rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, 
-		      unsigned int ifindex, struct in_addr *nexthop)
+		      unsigned int ifindex, struct in_addr *nexthop,
+                      unsigned int metric, unsigned char distance)
 {
   int ret;
   struct route_node *rp;
@@ -1551,6 +1593,8 @@
   rinfo->sub_type = sub_type;
   rinfo->ifindex = ifindex;
   rinfo->metric = 1;
+  rinfo->external_metric = metric;
+  rinfo->distance = distance;
   rinfo->rp = rp;
 
   if (nexthop)
@@ -2922,7 +2966,7 @@
 
   node->info = (char *)"static";
 
-  rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+  rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
 
   return CMD_SUCCESS;
 }
@@ -3467,7 +3511,17 @@
 	  }
 	else
 	  {
-	    vty_out (vty, "self            ");
+	    if (rinfo->external_metric)
+	      {
+	        len = vty_out (vty, "self (%s:%d)", 
+	                       route_info[rinfo->type].str_long,
+	                       rinfo->external_metric);
+	        len = 16 - len;
+	        if (len > 0)
+	          vty_out (vty, "%*s", len, " ");
+	      }
+	    else
+	      vty_out (vty, "self            ");
 	    vty_out (vty, "%3d", rinfo->tag);
 	  }
 
diff --git a/ripd/ripd.h b/ripd/ripd.h
index 7874871..6ddd52d 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -200,6 +200,10 @@
   /* Metric of this route. */
   u_int32_t metric;
 
+  /* External metric of this route. 
+     if learnt from an externalm proto */
+  u_int32_t external_metric;
+
   /* Tag information of this route. */
   u_int16_t tag;
 
@@ -393,7 +397,7 @@
                       struct connected *);
 int rip_neighbor_lookup (struct sockaddr_in *);
 void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, 
-			   struct in_addr *);
+			   struct in_addr *, unsigned int, unsigned char);
 void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int);
 void rip_redistribute_withdraw (int);
 void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char);
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 1e453ae..c3c88e8 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,6 +1,10 @@
 
 2005-09-28 Alain Ritoux <alain.ritoux@6wind.com>
 
+	* zserv.c: Always provied distance for route add
+
+2005-09-28 Alain Ritoux <alain.ritoux@6wind.com>
+
 	* connected.c: flag connected_up_ipv6() and connected_down_ipv6()
 	  usage with HAVE_IPV6
 
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 872ddb8..abd99cd 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -486,6 +486,8 @@
   /* Metric */
   if (cmd == ZEBRA_IPV4_ROUTE_ADD || ZEBRA_IPV6_ROUTE_ADD)
     {
+      SET_FLAG (zapi_flags, ZAPI_MESSAGE_DISTANCE);
+      stream_putc (s, rib->distance);
       SET_FLAG (zapi_flags, ZAPI_MESSAGE_METRIC);
       stream_putl (s, rib->metric);
     }