Browse Source

Merge RIP part of 6Wind patch.

hasso 16 years ago
parent
commit
16705130a1
7 changed files with 742 additions and 111 deletions
  1. 4 0
      ripd/ChangeLog
  2. 1 1
      ripd/Makefile.am
  3. 194 43
      ripd/rip_interface.c
  4. 249 24
      ripd/rip_routemap.c
  5. 40 2
      ripd/rip_zebra.c
  6. 241 39
      ripd/ripd.c
  7. 13 2
      ripd/ripd.h

+ 4 - 0
ripd/ChangeLog

@@ -1,3 +1,7 @@
+2003-05-25 Vincent Jardin <vjardin@wanadoo.fr>
+
+  * 6Wind patch merge.
+
 2003-04-19 Hasso Tepper <hasso@estpak.ee>
 
 	* rip_routemap.c: sync daemon's route-map commands to have same

+ 1 - 1
ripd/Makefile.am

@@ -17,7 +17,7 @@ noinst_HEADERS = \
 ripd_SOURCES = \
 	rip_main.c $(librip_a_SOURCES)
 
-ripd_LDADD = ../lib/libzebra.a
+ripd_LDADD = -L../lib -lzebra
 
 sysconf_DATA = ripd.conf.sample
 

+ 194 - 43
ripd/rip_interface.c

@@ -43,6 +43,10 @@
 void rip_enable_apply (struct interface *);
 void rip_passive_interface_apply (struct interface *);
 int rip_if_down(struct interface *ifp);
+int rip_enable_if_lookup (char *ifname);
+int rip_enable_network_lookup2 (struct connected *connected);
+void rip_enable_apply_all ();
+
 
 struct message ri_version_msg[] = 
 {
@@ -122,7 +126,7 @@ rip_interface_new ()
      Relay or SMDS is enabled, the default value for split-horizon is
      off.  But currently Zebra does detect Frame Relay or SMDS
      interface.  So all interface is set to split horizon.  */
-  ri->split_horizon_default = 1;
+  ri->split_horizon_default = RIP_SPLIT_HORIZON;
   ri->split_horizon = ri->split_horizon_default;
 
   return ri;
@@ -226,10 +230,8 @@ rip_request_interface_send (struct interface *ifp, u_char version)
 	      to.sin_port = htons (RIP_PORT_DEFAULT);
 	      to.sin_addr = p->prefix;
 
-#if 0
 	      if (IS_RIP_DEBUG_EVENT)
 		zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr));
-#endif /* 0 */
 	      
 	      rip_request_send (&to, ifp, version);
 	    }
@@ -466,6 +468,9 @@ rip_interface_add (int command, struct zclient *zclient, zebra_size_t length)
 
   /* rip_request_neighbor_all (); */
 
+  /* Check interface routemap. */
+  rip_if_rmap_update_interface (ifp);
+
   return 0;
 }
 
@@ -554,8 +559,8 @@ rip_interface_reset ()
 	  ri->key_chain = NULL;
 	}
 
-      ri->split_horizon = 0;
-      ri->split_horizon_default = 0;
+      ri->split_horizon = RIP_NO_SPLIT_HORIZON;
+      ri->split_horizon_default = RIP_NO_SPLIT_HORIZON;
 
       ri->list[RIP_FILTER_IN] = NULL;
       ri->list[RIP_FILTER_OUT] = NULL;
@@ -644,6 +649,34 @@ rip_if_down_all ()
     }
 }
 
+static void
+rip_apply_address_add (struct connected *ifc) {
+  struct prefix_ipv4 address;
+  struct prefix *p;
+
+  if (!rip)
+    return;
+
+  if (! if_is_up(ifc->ifp))
+    return;
+
+  p = ifc->address;
+
+  memset (&address, 0, sizeof (address));
+  address.family = p->family;
+  address.prefix = p->u.prefix4;
+  address.prefixlen = p->prefixlen;
+  apply_mask_ipv4(&address);
+
+  /* Check if this interface is RIP enabled or not
+     or  Check if this address's prefix is RIP enabled */
+  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);
+
+}
+
 int
 rip_interface_address_add (int command, struct zclient *zclient,
 			   zebra_size_t length)
@@ -663,9 +696,9 @@ rip_interface_address_add (int command, struct zclient *zclient,
       if (IS_RIP_DEBUG_ZEBRA)
 	zlog_info ("connected address %s/%d is added", 
 		   inet_ntoa (p->u.prefix4), p->prefixlen);
-      
-      /* Check is this interface is RIP enabled or not.*/
-      rip_enable_apply (ifc->ifp);
+
+      /* Check if this prefix needs to be redistributed */
+      rip_apply_address_add(ifc);
 
 #ifdef HAVE_SNMP
       rip_ifaddr_add (ifc->ifp, ifc);
@@ -675,6 +708,29 @@ rip_interface_address_add (int command, struct zclient *zclient,
   return 0;
 }
 
+static void
+rip_apply_address_del (struct connected *ifc) {
+  struct prefix_ipv4 address;
+  struct prefix *p;
+
+  if (!rip)
+    return;
+
+  if (! if_is_up(ifc->ifp))
+    return;
+
+  p = ifc->address;
+
+  memset (&address, 0, sizeof (address));
+  address.family = p->family;
+  address.prefix = p->u.prefix4;
+  address.prefixlen = p->prefixlen;
+  apply_mask_ipv4(&address);
+
+  rip_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
+                          &address, ifc->ifp->ifindex);
+}
+
 int
 rip_interface_address_delete (int command, struct zclient *zclient,
 			      zebra_size_t length)
@@ -698,8 +754,9 @@ rip_interface_address_delete (int command, struct zclient *zclient,
 	  rip_ifaddr_delete (ifc->ifp, ifc);
 #endif /* HAVE_SNMP */
 
-	  /* Check if this interface is RIP enabled or not.*/
-	  rip_enable_apply (ifc->ifp);
+	  /* Chech wether this prefix needs to be removed */
+          rip_apply_address_del(ifc);
+
 	}
 
       connected_free (ifc);
@@ -710,8 +767,10 @@ rip_interface_address_delete (int command, struct zclient *zclient,
 }
 
 /* Check interface is enabled by network statement. */
+/* Check wether the interface has at least a connected prefix that
+ * is within the ripng_enable_network table. */
 int
-rip_enable_network_lookup (struct interface *ifp)
+rip_enable_network_lookup_if (struct interface *ifp)
 {
   struct listnode *nn;
   struct connected *connected;
@@ -743,6 +802,34 @@ rip_enable_network_lookup (struct interface *ifp)
   return -1;
 }
 
+/* Check wether connected is within the ripng_enable_network table. */
+int
+rip_enable_network_lookup2 (struct connected *connected)
+{
+  struct prefix_ipv4 address;
+  struct prefix *p;
+
+  p = connected->address;
+
+  if (p->family == AF_INET) {
+    struct route_node *node;
+
+    address.family = p->family;
+    address.prefix = p->u.prefix4;
+    address.prefixlen = IPV4_MAX_BITLEN;
+
+    /* LPM on p->family, p->u.prefix4/IPV4_MAX_BITLEN within rip_enable_network */
+    node = route_node_match (rip_enable_network,
+                             (struct prefix *)&address);
+
+    if (node) {
+      route_unlock_node (node);
+      return 1;
+    }
+  }
+
+  return -1;
+}
 /* Add RIP enable network. */
 int
 rip_enable_network_add (struct prefix *p)
@@ -759,6 +846,9 @@ rip_enable_network_add (struct prefix *p)
   else
     node->info = "enabled";
 
+  /* XXX: One should find a better solution than a generic one */
+  rip_enable_apply_all();
+
   return 1;
 }
 
@@ -779,6 +869,9 @@ rip_enable_network_delete (struct prefix *p)
       /* Unlock lookup lock. */
       route_unlock_node (node);
 
+      /* XXX: One should find a better solution than a generic one */
+      rip_enable_apply_all ();
+
       return 1;
     }
   return -1;
@@ -810,6 +903,8 @@ rip_enable_if_add (char *ifname)
 
   vector_set (rip_enable_interface, strdup (ifname));
 
+  rip_enable_apply_all(); /* TODOVJ */
+
   return 1;
 }
 
@@ -828,6 +923,8 @@ rip_enable_if_delete (char *ifname)
   free (str);
   vector_unset (rip_enable_interface, index);
 
+  rip_enable_apply_all(); /* TODOVJ */
+
   return 1;
 }
 
@@ -883,10 +980,13 @@ rip_connect_set (struct interface *ifp, int set)
 	address.prefixlen = p->prefixlen;
 	apply_mask_ipv4 (&address);
 
-	if (set)
-	  rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
-				&address, connected->ifp->ifindex, NULL);
-	else
+	if (set) {
+          /* Check once more wether this prefix is within a "network IF_OR_PREF" one */
+          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);
+	} else
 	  {
 	    rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
 				     &address, connected->ifp->ifindex);
@@ -905,16 +1005,13 @@ rip_enable_apply (struct interface *ifp)
   struct rip_interface *ri = NULL;
 
   /* Check interface. */
-  if (if_is_loopback (ifp))
-    return;
-
   if (! if_is_operative (ifp))
     return;
 
   ri = ifp->info;
 
   /* Check network configuration. */
-  ret = rip_enable_network_lookup (ifp);
+  ret = rip_enable_network_lookup_if (ifp);
 
   /* If the interface is matched. */
   if (ret > 0)
@@ -939,7 +1036,6 @@ rip_enable_apply (struct interface *ifp)
   /* Update running status of the interface. */
   if (ri->enable_network || ri->enable_interface)
     {
-      if (! ri->running)
 	{
 	  if (IS_RIP_DEBUG_EVENT)
 	    zlog_info ("turn on %s", ifp->name);
@@ -955,13 +1051,11 @@ rip_enable_apply (struct interface *ifp)
     {
       if (ri->running)
 	{
-	  if (IS_RIP_DEBUG_EVENT)
-	    zlog_info ("turn off %s", ifp->name);
-
-	  /* Might as well clean up the route table as well */ 
+	  /* Might as well clean up the route table as well
+	   * rip_if_down sets to 0 ri->running, and displays "turn off %s"
+	   **/ 
 	  rip_if_down(ifp);
 
-	  ri->running = 0;
           rip_connect_set (ifp, 0);
 	}
     }
@@ -1181,8 +1275,6 @@ DEFUN (rip_network,
       return CMD_WARNING;
     }
 
-  rip_enable_apply_all ();
-
   return CMD_SUCCESS;
 }
 
@@ -1212,8 +1304,6 @@ DEFUN (no_rip_network,
       return CMD_WARNING;
     }
 
-  rip_enable_apply_all ();
-
   return CMD_SUCCESS;
 }
 
@@ -1661,10 +1751,15 @@ ALIAS (no_ip_rip_authentication_key_chain,
        "Authentication key-chain\n"
        "name of key-chain\n")
 
-DEFUN (rip_split_horizon,
-       rip_split_horizon_cmd,
-       "ip split-horizon",
+/* CHANGED: ip rip split-horizon
+   Cisco and Zebra's command is
+   ip split-horizon
+ */
+DEFUN (ip_rip_split_horizon,
+       ip_rip_split_horizon_cmd,
+       "ip rip split-horizon",
        IP_STR
+       "Routing Information Protocol\n"
        "Perform split horizon\n")
 {
   struct interface *ifp;
@@ -1673,15 +1768,38 @@ DEFUN (rip_split_horizon,
   ifp = vty->index;
   ri = ifp->info;
 
-  ri->split_horizon = 1;
+  ri->split_horizon = RIP_SPLIT_HORIZON;
   return CMD_SUCCESS;
 }
 
-DEFUN (no_rip_split_horizon,
-       no_rip_split_horizon_cmd,
-       "no ip split-horizon",
+DEFUN (ip_rip_split_horizon_poisoned_reverse,
+       ip_rip_split_horizon_poisoned_reverse_cmd,
+       "ip rip split-horizon poisoned-reverse",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Perform split horizon\n"
+       "With poisoned-reverse\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = vty->index;
+  ri = ifp->info;
+
+  ri->split_horizon = RIP_SPLIT_HORIZON_POISONED_REVERSE;
+  return CMD_SUCCESS;
+}
+
+/* CHANGED: no ip rip split-horizon
+   Cisco and Zebra's command is
+   no ip split-horizon
+ */
+DEFUN (no_ip_rip_split_horizon,
+       no_ip_rip_split_horizon_cmd,
+       "no ip rip split-horizon",
        NO_STR
        IP_STR
+       "Routing Information Protocol\n"
        "Perform split horizon\n")
 {
   struct interface *ifp;
@@ -1690,10 +1808,19 @@ DEFUN (no_rip_split_horizon,
   ifp = vty->index;
   ri = ifp->info;
 
-  ri->split_horizon = 0;
+  ri->split_horizon = RIP_NO_SPLIT_HORIZON;
   return CMD_SUCCESS;
 }
 
+ALIAS (no_ip_rip_split_horizon,
+       no_ip_rip_split_horizon_poisoned_reverse_cmd,
+       "no ip rip split-horizon poisoned-reverse",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Perform split horizon\n"
+       "With poisoned-reverse\n")
+
 DEFUN (rip_passive_interface,
        rip_passive_interface_cmd,
        "passive-interface IFNAME",
@@ -1727,6 +1854,18 @@ rip_interface_config_write (struct vty *vty)
       ifp = getdata (node);
       ri = ifp->info;
 
+      /* Do not display the interface if there is no
+       * configuration about it.
+       **/
+      if ((!ifp->desc)                                     &&
+          (ri->split_horizon == ri->split_horizon_default) &&
+          (ri->ri_send == RI_RIP_UNSPEC)                   &&
+          (ri->ri_receive == RI_RIP_UNSPEC)                &&
+          (ri->auth_type != RIP_AUTH_MD5)                  &&
+          (!ri->auth_str)                                  &&
+          (!ri->key_chain)                                 )
+        continue;
+
       vty_out (vty, "interface %s%s", ifp->name,
 	       VTY_NEWLINE);
 
@@ -1737,10 +1876,19 @@ rip_interface_config_write (struct vty *vty)
       /* Split horizon. */
       if (ri->split_horizon != ri->split_horizon_default)
 	{
-	  if (ri->split_horizon)
-	    vty_out (vty, " ip split-horizon%s", VTY_NEWLINE);
-	  else
-	    vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE);
+          switch (ri->split_horizon) {
+          case RIP_SPLIT_HORIZON:
+            vty_out (vty, " ip rip split-horizon%s", VTY_NEWLINE);
+            break;
+          case RIP_SPLIT_HORIZON_POISONED_REVERSE:
+            vty_out (vty, " ip rip split-horizon poisoned-reverse%s",
+                          VTY_NEWLINE);
+            break;
+          case RIP_NO_SPLIT_HORIZON:
+          default:
+            vty_out (vty, " no ip rip split-horizon%s", VTY_NEWLINE);
+            break;
+          }
 	}
 
       /* RIP version setting. */
@@ -1837,6 +1985,7 @@ int
 rip_interface_delete_hook (struct interface *ifp)
 {
   XFREE (MTYPE_RIP_INTERFACE, ifp->info);
+  ifp->info = NULL;
   return 0;
 }
 
@@ -1897,6 +2046,8 @@ rip_if_init ()
   install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd);
   install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd);
 
-  install_element (INTERFACE_NODE, &rip_split_horizon_cmd);
-  install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_split_horizon_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_split_horizon_poisoned_reverse_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_poisoned_reverse_cmd);
 }

+ 249 - 24
ripd/rip_routemap.c

@@ -31,6 +31,18 @@
 #include "plist.h"
 
 #include "ripd/ripd.h"
+
+struct rip_metric_modifier
+{
+  enum 
+  {
+    metric_increment,
+    metric_decrement,
+    metric_absolute
+  } type;
+
+  u_char metric;
+};
 
 /* Add rip route map rule. */
 int
@@ -439,6 +451,57 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
   route_match_ip_address_prefix_list_compile,
   route_match_ip_address_prefix_list_free
 };
+
+/* `match tag TAG' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_tag (void *rule, struct prefix *prefix, 
+		    route_map_object_t type, void *object)
+{
+  u_short *tag;
+  struct rip_info *rinfo;
+
+  if (type == RMAP_RIP)
+    {
+      tag = rule;
+      rinfo = object;
+
+      /* The information stored by rinfo is host ordered. */
+      if (rinfo->tag == *tag)
+	return RMAP_MATCH;
+      else
+	return RMAP_NOMATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match tag' match statement. `arg' is TAG value */
+void *
+route_match_tag_compile (char *arg)
+{
+  u_short *tag;
+
+  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+  *tag = atoi (arg);
+
+  return tag;
+}
+
+/* Free route map's compiled `match tag' value. */
+void
+route_match_tag_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag matching. */
+struct route_map_rule_cmd route_match_tag_cmd =
+{
+  "tag",
+  route_match_tag,
+  route_match_tag_compile,
+  route_match_tag_free
+};
 
 /* `set metric METRIC' */
 
@@ -447,17 +510,26 @@ route_map_result_t
 route_set_metric (void *rule, struct prefix *prefix, 
 		  route_map_object_t type, void *object)
 {
-  u_int32_t *metric;
-  struct rip_info *rinfo;
-
   if (type == RMAP_RIP)
     {
-      /* Fetch routemap's rule information. */
-      metric = rule;
+      struct rip_metric_modifier *mod;
+      struct rip_info *rinfo;
+
+      mod = rule;
       rinfo = object;
-    
-      /* Set metric out value. */
-      rinfo->metric_out = *metric;
+
+      if (mod->type == metric_increment)
+	rinfo->metric_out += mod->metric;
+      else if (mod->type == metric_decrement)
+	rinfo->metric_out -= mod->metric;
+      else if (mod->type == metric_absolute)
+	rinfo->metric_out = mod->metric;
+
+      if (rinfo->metric_out < 1)
+	rinfo->metric_out = 1;
+      if (rinfo->metric_out > RIP_METRIC_INFINITY)
+	rinfo->metric_out = RIP_METRIC_INFINITY;
+
       rinfo->metric_set = 1;
     }
   return RMAP_OKAY;
@@ -467,22 +539,51 @@ route_set_metric (void *rule, struct prefix *prefix,
 void *
 route_set_metric_compile (char *arg)
 {
-  u_int32_t *metric;
+  int len;
+  char *pnt;
+  int type;
+  long metric;
+  char *endptr = NULL;
+  struct rip_metric_modifier *mod;
 
-  metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
-  *metric = atoi (arg);
+  len = strlen (arg);
+  pnt = arg;
 
-  return metric;
+  if (len == 0)
+    return NULL;
 
-#if 0
-  /* To make it consistent to other daemon, metric check is commented
-     out.*/
-  if (*metric >= 0 && *metric <= 16)
-    return metric;
+  /* Examine first character. */
+  if (arg[0] == '+')
+    {
+      type = metric_increment;
+      pnt++;
+    }
+  else if (arg[0] == '-')
+    {
+      type = metric_decrement;
+      pnt++;
+    }
+  else
+    type = metric_absolute;
 
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
-  return NULL;
-#endif /* 0 */
+  /* Check beginning with digit string. */
+  if (*pnt < '0' || *pnt > '9')
+    return NULL;
+
+  /* Convert string to integer. */
+  metric = strtol (pnt, &endptr, 10);
+
+  if (metric == LONG_MAX || *endptr != '\0')
+    return NULL;
+  if (metric < 0 || metric > RIP_METRIC_INFINITY)
+    return NULL;
+
+  mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, 
+		 sizeof (struct rip_metric_modifier));
+  mod->type = type;
+  mod->metric = metric;
+
+  return mod;
 }
 
 /* Free route map's compiled `set metric' value. */
@@ -560,6 +661,58 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd =
   route_set_ip_nexthop_compile,
   route_set_ip_nexthop_free
 };
+
+/* `set tag TAG' */
+
+/* Set tag to object.  ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix, 
+		      route_map_object_t type, void *object)
+{
+  u_short *tag;
+  struct rip_info *rinfo;
+
+  if(type == RMAP_RIP)
+    {
+      /* Fetch routemap's rule information. */
+      tag = rule;
+      rinfo = object;
+    
+      /* Set next hop value. */ 
+      rinfo->tag_out = *tag;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `tag' compile function.  Given string is converted
+   to u_short. */
+void *
+route_set_tag_compile (char *arg)
+{
+  u_short *tag;
+
+  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+  *tag = atoi (arg);
+
+  return tag;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_tag_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag set. */
+struct route_map_rule_cmd route_set_tag_cmd =
+{
+  "tag",
+  route_set_tag,
+  route_set_tag_compile,
+  route_set_tag_free
+};
 
 #define MATCH_STR "Match values from routing table\n"
 #define SET_STR "Set values in destination routing protocol\n"
@@ -777,14 +930,46 @@ ALIAS (no_match_ip_address_prefix_list,
        "Match entries of prefix-lists\n"
        "IP prefix-list name\n")
 
+DEFUN (match_tag, 
+       match_tag_cmd,
+       "match tag <0-65535>",
+       MATCH_STR
+       "Match tag of route\n"
+       "Metric value\n")
+{
+  return rip_route_match_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_match_tag,
+       no_match_tag_cmd,
+       "no match tag",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "tag", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_match_tag,
+       no_match_tag_val_cmd,
+       "no match tag <0-65535>",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n"
+       "Metric value\n")
+
 /* set functions */
 
 DEFUN (set_metric,
        set_metric_cmd,
-       "set metric <0-4294967295>",
+       "set metric (<0-4294967295>|<+/-metric>)",
        SET_STR
        "Metric value for destination routing protocol\n"
-       "Metric value\n")
+       "Metric value\n"
+       "Add or subtract metric\n")
 {
   return rip_route_set_add (vty, vty->index, "metric", argv[0]);
 }
@@ -804,11 +989,12 @@ DEFUN (no_set_metric,
 
 ALIAS (no_set_metric,
        no_set_metric_val_cmd,
-       "no set metric <0-4294967295>",
+       "no set metric (<0-4294967295>|<+/-metric>)",
        NO_STR
        SET_STR
        "Metric value for destination routing protocol\n"
-       "Metric value\n")
+       "Metric value\n"
+       "Add or subtract metric\n")
 
 DEFUN (set_ip_nexthop,
        set_ip_nexthop_cmd,
@@ -854,6 +1040,37 @@ ALIAS (no_set_ip_nexthop,
        "Next hop address\n"
        "IP address of next hop\n")
 
+DEFUN (set_tag,
+       set_tag_cmd,
+       "set tag <0-65535>",
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+{
+  return rip_route_set_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_set_tag,
+       no_set_tag_cmd,
+       "no set tag",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n")
+{
+  if (argc == 0)
+    return rip_route_set_delete (vty, vty->index, "tag", NULL);
+  
+  return rip_route_set_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_set_tag,
+       no_set_tag_val_cmd,
+       "no set tag <0-65535>",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+
 void
 rip_route_map_reset ()
 {
@@ -875,9 +1092,11 @@ rip_route_map_init ()
   route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
   route_map_install_match (&route_match_ip_address_cmd);
   route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+  route_map_install_match (&route_match_tag_cmd);
 
   route_map_install_set (&route_set_metric_cmd);
   route_map_install_set (&route_set_ip_nexthop_cmd);
+  route_map_install_set (&route_set_tag_cmd);
 
   install_element (RMAP_NODE, &match_metric_cmd);
   install_element (RMAP_NODE, &no_match_metric_cmd);
@@ -897,6 +1116,9 @@ rip_route_map_init ()
   install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
   install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
   install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_tag_cmd);
+  install_element (RMAP_NODE, &no_match_tag_cmd);
+  install_element (RMAP_NODE, &no_match_tag_val_cmd);
 
   install_element (RMAP_NODE, &set_metric_cmd);
   install_element (RMAP_NODE, &no_set_metric_cmd);
@@ -904,4 +1126,7 @@ rip_route_map_init ()
   install_element (RMAP_NODE, &set_ip_nexthop_cmd);
   install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
   install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+  install_element (RMAP_NODE, &set_tag_cmd);
+  install_element (RMAP_NODE, &no_set_tag_cmd);
+  install_element (RMAP_NODE, &no_set_tag_val_cmd);
 }

+ 40 - 2
ripd/rip_zebra.c

@@ -502,6 +502,43 @@ DEFUN (no_rip_redistribute_type_metric,
   return CMD_WARNING;
 }
 
+DEFUN (rip_redistribute_type_metric_routemap,
+       rip_redistribute_type_metric_routemap_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+  int metric;
+
+  metric = atoi (argv[1]);
+
+  for (i = 0; redist_type[i].str; i++) {
+    if (strncmp(redist_type[i].str, argv[0],
+		redist_type[i].str_min_len) == 0) 
+      {
+	rip_redistribute_metric_set (redist_type[i].type, metric);
+	rip_routemap_set (redist_type[i].type, argv[2]);
+	zclient_redistribute_set (zclient, redist_type[i].type);
+	return CMD_SUCCESS;
+      }
+  }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+
 DEFUN (no_rip_redistribute_type_metric_routemap,
        no_rip_redistribute_type_metric_routemap_cmd,
        "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD",
@@ -559,7 +596,7 @@ DEFUN (rip_default_information_originate,
 
       rip->default_information = 1;
   
-      rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+      rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0, NULL);
     }
 
   return CMD_SUCCESS;
@@ -581,7 +618,7 @@ DEFUN (no_rip_default_information_originate,
 
       rip->default_information = 0;
   
-      rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+      rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0);
     }
 
   return CMD_SUCCESS;
@@ -682,6 +719,7 @@ rip_zclient_init ()
   install_element (RIP_NODE, &rip_redistribute_type_cmd);
   install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd);
   install_element (RIP_NODE, &rip_redistribute_type_metric_cmd);
+  install_element (RIP_NODE, &rip_redistribute_type_metric_routemap_cmd);
   install_element (RIP_NODE, &no_rip_redistribute_type_cmd);
   install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd);
   install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd);

+ 241 - 39
ripd/ripd.c

@@ -32,6 +32,7 @@
 #include "filter.h"
 #include "sockunion.h"
 #include "routemap.h"
+#include "if_rmap.h"
 #include "plist.h"
 #include "distribute.h"
 #include "md5-gnu.h"
@@ -404,6 +405,40 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
   if (ret < 0)
     return;
 
+  /* Modify entry according to the interface routemap. */
+  if (ri->routemap[RIP_FILTER_IN])
+    {
+      int ret;
+      struct rip_info newinfo;
+
+      memset (&newinfo, 0, sizeof (newinfo));
+      newinfo.type = ZEBRA_ROUTE_RIP;
+      newinfo.sub_type = RIP_ROUTE_RTE;
+      newinfo.nexthop= rte->nexthop;
+      newinfo.from   = from->sin_addr;
+      newinfo.ifindex= ifp->ifindex;
+      newinfo.metric = rte->metric;
+      newinfo.metric_out = rte->metric; /* XXX */
+      newinfo.tag    = ntohs(rte->tag); /* XXX */
+
+      /* The object should be of the type of rip_info */
+      ret = route_map_apply (ri->routemap[RIP_FILTER_IN], 
+			     (struct prefix *)&p, RMAP_RIP, &newinfo);
+
+      if (ret == RMAP_DENYMATCH)
+	{
+	  if (IS_RIP_DEBUG_PACKET)
+	    zlog_info ("RIP %s/%d is filtered by route-map in",
+		       inet_ntoa (p.prefix), p.prefixlen);
+	  return;
+	}
+
+      /* Get back the object */
+      rte->nexthop    = newinfo.nexthop_out;
+      rte->tag        = htons(newinfo.tag_out); /* XXX */
+      rte->metric     = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
+    }
+
   /* Once the entry has been validated, update the metric by
      adding the cost of the network on wich the message
      arrived. If the result is greater than infinity, use infinity
@@ -425,11 +460,11 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
   else
     nexthop = &rte->nexthop;
 
-  /* Check nexthop address. */
+  /* Check if nexthop address is myself, then do nothing. */
   if (rip_nexthop_check (nexthop) < 0)
     {
       if (IS_RIP_DEBUG_PACKET)
-	zlog_info ("Nexthop address %s is invalid", inet_ntoa (*nexthop));
+	zlog_info ("Nexthop address %s is myself", inet_ntoa (*nexthop));
       return;
     }
 
@@ -448,7 +483,8 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
 
       /* Local static route. */
       if (rinfo->type == ZEBRA_ROUTE_RIP
-	  && rinfo->sub_type == RIP_ROUTE_STATIC
+	  && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
+	      (rinfo->sub_type == RIP_ROUTE_DEFAULT))
 	  && rinfo->metric != RIP_METRIC_INFINITY)
 	return;
     }
@@ -514,7 +550,8 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
 	 to the address of the router from which the datagram came.
 	 If this datagram is from the same router as the existing
 	 route, reinitialize the timeout.  */
-      same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr);
+      same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
+      	      && (rinfo->ifindex == ifp->ifindex));
 
       if (same)
 	rip_timeout_update (rinfo);
@@ -522,9 +559,10 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
       /* Next, compare the metrics.  If the datagram is from the same
 	 router as the existing route, and the new metric is different
 	 than the old one; or, if the new metric is lower than the old
-	 one; do the following actions: */
+	 one, or if the tag has been changed; do the following actions: */
       if ((same && rinfo->metric != rte->metric) ||
-	  rte->metric < rinfo->metric)
+	  (rte->metric < rinfo->metric) ||
+	  (same && (rinfo->metric == rte->metric) && ntohs(rte->tag) != rinfo->tag))
 	{
 	  /* - Adopt the route from the datagram.  That is, put the
 	     new metric in, and adjust the next hop address (if
@@ -1275,9 +1313,11 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
 
       /* Manually configured RIP route check. */
       if (rinfo->type == ZEBRA_ROUTE_RIP 
-	  && rinfo->sub_type == RIP_ROUTE_STATIC)
+	  && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
+	      (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
 	{
-	  if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC)
+	  if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
+	                                  (sub_type != RIP_ROUTE_DEFAULT)))
 	    {
 	      route_unlock_node (rp);
 	      return;
@@ -1312,6 +1352,18 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
 
   rinfo->flags |= RIP_RTF_CHANGED;
 
+  if (IS_RIP_DEBUG_EVENT) {
+    if (!nexthop)
+      zlog_info ("Redistribute new prefix %s/%d on the interface %s",
+                 inet_ntoa(p->prefix), p->prefixlen,
+                 ifindex2ifname(ifindex));
+    else
+      zlog_info ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
+                 inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
+                 ifindex2ifname(ifindex));
+  }
+
+
   rip_event (RIP_TRIGGERED_UPDATE, 0);
 }
 
@@ -1345,6 +1397,11 @@ rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
 	  RIP_TIMER_OFF (rinfo->t_timeout);
 	  rinfo->flags |= RIP_RTF_CHANGED;
 
+          if (IS_RIP_DEBUG_EVENT)
+            zlog_info ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
+                       inet_ntoa(p->prefix), p->prefixlen,
+                       ifindex2ifname(ifindex));
+
 	  rip_event (RIP_TRIGGERED_UPDATE, 0);
 	}
     }
@@ -1362,7 +1419,14 @@ rip_request_process (struct rip_packet *packet, int size,
   struct rip_info *rinfo;
   struct rip_interface *ri;
 
+  /* Does not reponse to the requests on the loopback interfaces */
+  if (if_is_loopback (ifp))
+    return;
+
+  /* Check RIPng process is enabled on this interface. */
   ri = ifp->info;
+  if (! ri->running)
+    return;
 
   /* When passive interface is specified, suppress responses */
   if (ri->passive)
@@ -1907,7 +1971,7 @@ rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
       masklen2ip (p->prefixlen, &mask);
 
       stream_putw (s, AF_INET);
-      stream_putw (s, rinfo->tag);
+      stream_putw (s, rinfo->tag_out);
       stream_put_ipv4 (s, p->prefix.s_addr);
       stream_put_ipv4 (s, mask.s_addr);
       stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
@@ -2054,7 +2118,7 @@ rip_output_process (struct interface *ifp, struct prefix *ifaddr,
 
 	/* Split horizon. */
 	/* if (split_horizon == rip_split_horizon) */
-	if (ri->split_horizon)
+	if (ri->split_horizon == RIP_SPLIT_HORIZON)
 	  {
 	    /* We perform split horizon for RIP and connected route. */
 	    if ((rinfo->type == ZEBRA_ROUTE_RIP ||
@@ -2067,23 +2131,36 @@ rip_output_process (struct interface *ifp, struct prefix *ifaddr,
 	rinfo->metric_set = 0;
 	rinfo->nexthop_out.s_addr = 0;
 	rinfo->metric_out = rinfo->metric;
+	rinfo->tag_out = rinfo->tag;
 	rinfo->ifindex_out = ifp->ifindex;
 
-	/* In order to avoid some local loops, if the RIP route has a
-	   nexthop via this interface, keep the nexthop, otherwise set
-	   it to 0. The nexthop should not be propagated beyond the
-	   local broadcast/multicast area in order to avoid an IGP
-	   multi-level recursive look-up.  For RIP and connected
-	   route, we don't set next hop value automatically.  For
-	   settting next hop to those routes, please use
-	   route-map.  */
-
-	if (rinfo->type != ZEBRA_ROUTE_RIP
-	    && rinfo->type != ZEBRA_ROUTE_CONNECT
-	    && rinfo->ifindex == ifp->ifindex)
+	/* In order to avoid some local loops,
+	 * if the RIP route has a nexthop via this interface, keep the nexthop,
+	 * otherwise set it to 0. The nexthop should not be propagated
+	 * beyond the local broadcast/multicast area in order
+	 * to avoid an IGP multi-level recursive look-up.
+	 * see (4.4)
+	 */
+	if (rinfo->ifindex == ifp->ifindex)
 	  rinfo->nexthop_out = rinfo->nexthop;
+
+	/* Interface route-map */
+	if (ri->routemap[RIP_FILTER_OUT])
+	  {
+	    ret = route_map_apply (ri->routemap[RIP_FILTER_OUT], 
+				     (struct prefix *) p, RMAP_RIP, 
+				     rinfo);
+
+	    if (ret == RMAP_DENYMATCH)
+	      {
+	        if (IS_RIP_DEBUG_PACKET)
+	          zlog_info ("RIP %s/%d is filtered by route-map out",
+			     inet_ntoa (p->prefix), p->prefixlen);
+		  continue;
+	      }
+	  }
            
-	/* Apply route map - continue, if deny */
+	/* Apply redistribute route map - continue, if deny */
 	if (rip->route_map[rinfo->type].name
 	    && rinfo->sub_type != RIP_ROUTE_INTERFACE)
 	  {
@@ -2125,7 +2202,17 @@ rip_output_process (struct interface *ifp, struct prefix *ifaddr,
 
 	if (rinfo->metric_out > RIP_METRIC_INFINITY)
 	  rinfo->metric_out = RIP_METRIC_INFINITY;
-	  
+
+	/* Perform split-horizon with poisoned reverse 
+	 * for RIP and connected routes.
+	 **/
+	if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
+	  if ((rinfo->type == ZEBRA_ROUTE_RIP ||
+	       rinfo->type == ZEBRA_ROUTE_CONNECT) &&
+	       rinfo->ifindex == ifp->ifindex)
+	       rinfo->metric_out = RIP_METRIC_INFINITY;
+	}
+ 
 	/* Write RTE to the stream. */
 	num = rip_write_rte (num, s, p, version, rinfo, to ? NULL : ifp);
 	if (num == rtemax)
@@ -2419,6 +2506,14 @@ rip_redistribute_withdraw (int type)
 	    RIP_TIMER_OFF (rinfo->t_timeout);
 	    rinfo->flags |= RIP_RTF_CHANGED;
 
+	    if (IS_RIP_DEBUG_EVENT) {
+              struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
+
+              zlog_info ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
+                         inet_ntoa(p->prefix), p->prefixlen,
+                         ifindex2ifname(rinfo->ifindex));
+	    }
+
 	    rip_event (RIP_TRIGGERED_UPDATE, 0);
 	  }
       }
@@ -2775,6 +2870,17 @@ DEFUN (no_rip_timers,
 
   return CMD_SUCCESS;
 }
+
+ALIAS (no_rip_timers,
+       no_rip_timers_val_cmd,
+       "no timers basic <0-65535> <0-65535> <0-65535>",
+       NO_STR
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n"
+       "Routing table update timer value in second. Default is 30.\n"
+       "Routing information timeout timer. Default is 180.\n"
+       "Garbage collection timer. Default is 120.\n")
+
 
 struct route_table *rip_distance_table;
 
@@ -3109,11 +3215,12 @@ DEFUN (show_ip_rip,
   if (! rip)
     return CMD_SUCCESS;
 
-  vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s"
-	   "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
+  vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
+	   "Sub-codes:%s"
+           "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
 	   "      (i) - interface%s%s"
-	   "     Network            Next Hop         Metric From            Time%s",
-	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+	   "     Network         Next Hop         Metric From            Tag Time%s",
+	   VTY_NEWLINE, VTY_NEWLINE,  VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
   
   for (np = route_top (rip->table); np; np = route_next (np))
     if ((rinfo = np->info) != NULL)
@@ -3126,7 +3233,7 @@ DEFUN (show_ip_rip,
 		       rip_route_type_print (rinfo->sub_type),
 		       inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
 	
-	len = 24 - len;
+	len = 21 - len;
 
 	if (len > 0)
 	  vty_out (vty, "%*s", len, " ");
@@ -3142,15 +3249,20 @@ DEFUN (show_ip_rip,
 	    (rinfo->sub_type == RIP_ROUTE_RTE))
 	  {
 	    vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
+	    vty_out (vty, "%3d ", rinfo->tag);
 	    rip_vty_out_uptime (vty, rinfo);
 	  }
 	else if (rinfo->metric == RIP_METRIC_INFINITY)
 	  {
 	    vty_out (vty, "self            ");
+	    vty_out (vty, "%3d ", rinfo->tag);
 	    rip_vty_out_uptime (vty, rinfo);
 	  }
 	else
-	  vty_out (vty, "self");
+	  {
+	    vty_out (vty, "self            ");
+	    vty_out (vty, "%3d", rinfo->tag);
+	  }
 
 	vty_out (vty, "%s", VTY_NEWLINE);
       }
@@ -3168,11 +3280,13 @@ rip_next_thread_timer (struct thread *thread)
   return thread->u.sands.tv_sec - timer_now.tv_sec;
 }
 
-DEFUN (show_ip_protocols_rip,
-       show_ip_protocols_rip_cmd,
-       "show ip protocols",
+/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
+DEFUN (show_ip_rip_status,
+       show_ip_rip_status_cmd,
+       "show ip rip status",
        SHOW_STR
        IP_STR
+       "Show RIP routes\n"
        "IP routing protocol process parameters and statistics\n")
 {
   listnode node;
@@ -3307,6 +3421,9 @@ config_write_rip (struct vty *vty)
       /* Distribute configuration. */
       write += config_write_distribute (vty);
 
+      /* Interface routemap configuration */
+      write += config_write_if_rmap (vty);
+
       /* Distance configuration. */
       if (rip->distance)
 	vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
@@ -3538,6 +3655,83 @@ rip_reset ()
   rip_zclient_reset ();
 }
 
+void
+rip_if_rmap_update (struct if_rmap *if_rmap)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+  struct route_map *rmap;
+
+  ifp = if_lookup_by_name (if_rmap->ifname);
+  if (ifp == NULL)
+    return;
+
+  ri = ifp->info;
+
+  if (if_rmap->routemap[IF_RMAP_IN])
+    {
+      rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
+      if (rmap)
+	ri->routemap[IF_RMAP_IN] = rmap;
+      else
+	ri->routemap[IF_RMAP_IN] = NULL;
+    }
+  else
+    ri->routemap[RIP_FILTER_IN] = NULL;
+
+  if (if_rmap->routemap[IF_RMAP_OUT])
+    {
+      rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
+      if (rmap)
+	ri->routemap[IF_RMAP_OUT] = rmap;
+      else
+	ri->routemap[IF_RMAP_OUT] = NULL;
+    }
+  else
+    ri->routemap[RIP_FILTER_OUT] = NULL;
+}
+
+void
+rip_if_rmap_update_interface (struct interface *ifp)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_lookup (ifp->name);
+  if (if_rmap)
+    rip_if_rmap_update (if_rmap);
+}
+
+void
+rip_routemap_update_redistribute (void)
+{
+  int i;
+
+  if (rip)
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
+	{
+	  if (rip->route_map[i].name)
+	    rip->route_map[i].map = 
+	      route_map_lookup_by_name (rip->route_map[i].name);
+	}
+    }
+}
+
+void
+rip_routemap_update ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_if_rmap_update_interface (ifp);
+    }
+
+  rip_routemap_update_redistribute ();
+}
+
 /* Allocate new rip structure and set default value. */
 void
 rip_init ()
@@ -3550,9 +3744,9 @@ rip_init ()
 
   /* Install rip commands. */
   install_element (VIEW_NODE, &show_ip_rip_cmd);
-  install_element (VIEW_NODE, &show_ip_protocols_rip_cmd);
+  install_element (VIEW_NODE, &show_ip_rip_status_cmd);
   install_element (ENABLE_NODE, &show_ip_rip_cmd);
-  install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd);
+  install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
   install_element (CONFIG_NODE, &router_rip_cmd);
   install_element (CONFIG_NODE, &no_router_rip_cmd);
 
@@ -3565,6 +3759,7 @@ rip_init ()
   install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
   install_element (RIP_NODE, &rip_timers_cmd);
   install_element (RIP_NODE, &no_rip_timers_cmd);
+  install_element (RIP_NODE, &no_rip_timers_val_cmd);
   install_element (RIP_NODE, &rip_route_cmd);
   install_element (RIP_NODE, &no_rip_route_cmd);
   install_element (RIP_NODE, &rip_distance_cmd);
@@ -3577,10 +3772,6 @@ rip_init ()
   /* Debug related init. */
   rip_debug_init ();
 
-  /* Filter related init. */
-  rip_route_map_init ();
-  rip_offset_init ();
-
   /* SNMP init. */
 #ifdef HAVE_SNMP
   rip_snmp_init ();
@@ -3601,6 +3792,17 @@ rip_init ()
   distribute_list_add_hook (rip_distribute_update);
   distribute_list_delete_hook (rip_distribute_update);
 
+  /* Route-map */
+  rip_route_map_init ();
+  rip_offset_init ();
+
+  route_map_add_hook (rip_routemap_update);
+  route_map_delete_hook (rip_routemap_update);
+
+  if_rmap_init (RIP_NODE);
+  if_rmap_hook_add (rip_if_rmap_update);
+  if_rmap_hook_delete (rip_if_rmap_update);
+
   /* Distance control. */
   rip_distance_table = route_table_init ();
 }

+ 13 - 2
ripd/ripd.h

@@ -199,6 +199,7 @@ struct rip_info
   struct in_addr nexthop_out;
   u_char metric_set;
   u_int32_t metric_out;
+  u_short tag_out;
   unsigned int ifindex_out;
 
   struct route_node *rp;
@@ -211,6 +212,12 @@ struct rip_info
 #endif /* NEW_RIP_TABLE */
 };
 
+typedef enum {
+  RIP_NO_SPLIT_HORIZON = 0,
+  RIP_SPLIT_HORIZON,
+  RIP_SPLIT_HORIZON_POISONED_REVERSE
+} split_horizon_policy_t;
+
 /* RIP specific interface configuration. */
 struct rip_interface
 {
@@ -239,8 +246,8 @@ struct rip_interface
   char *key_chain;
 
   /* Split horizon flag. */
-  int split_horizon;
-  int split_horizon_default;
+  split_horizon_policy_t split_horizon;
+  split_horizon_policy_t split_horizon_default;
 
   /* For filter type slot. */
 #define RIP_FILTER_IN  0
@@ -253,6 +260,9 @@ struct rip_interface
   /* Prefix-list. */
   struct prefix_list *prefix[RIP_FILTER_MAX];
 
+  /* Route-map. */
+  struct route_map *routemap[RIP_FILTER_MAX];
+
   /* Wake up thread. */
   struct thread *t_wakeup;
 
@@ -369,6 +379,7 @@ void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_ch
 void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t);
 void rip_interface_multicast_set (int, struct interface *);
 void rip_distribute_update_interface (struct interface *);
+void rip_if_rmap_update_interface (struct interface *);
 
 int config_write_rip_network (struct vty *, int);
 int config_write_rip_offset_list (struct vty *);