[zebra] Routemap support on received routes, with 'set src' command (linux)

2007-05-01 David L Stevens <dlstevens@us.ibm.com>

	* (general) These changes collectively add route-map and
	  prefix-list support to zebra and fix a bug in "show
	  route-map" (with no argument).
	* doc/main.texi: added route-map, prefix-list, ip protocol
	  and set src documentation
	* lib/command.h: added PROTOCOL_NODE type
	* lib/log.c: (proto_name2num) new function, protocol name to
	  number translation.
	* lib/routemap.c: (vty_show_route_map) fixed "show route-map"
	  without route-map name
	* lib/routemap.h: added RMAP_ZEBRA type
	* lib/zebra.h: added proto_name2num() prototype
	* vtysh/extract.pl.in: added VTYSH_ZEBRA flag for route-map and
	  plist
	* vtysh/Makefile.am: added zebra_routemap.c
	* vtysh/vtysh.h: added VTYSH_ZEBRA flag to VTYSH_RMAP
	* zebra/connected.c: (connected_up_ipv4) added src preference argument
	  to rib_add_ipv4()
	* zebra/kernel_socket.c: (rtm_read) ditto
	* zebra/main.c: added prefix list initialization
	* zebra/Makefile.am: added zebra_routemap.c source file
	* zebra/rib.h: added generic address union "g_addr" and use in
	  existing places that had an explicit union.
	  Added "src" to struct nexthop.
	  Added preferred src arg to nexthop_ipv4_add and rib_add_ipv4.
	* zebra/rt_netlink.c: (netlink_routing_table) set preferred source on
	  netlink messages.
	  (netlink_route_change) ditto
	  (netlink_route_multipath) ditto.
	* zebra/rtread_getmsg.c: (handle_route_entry) added (NULL) src to
	  rib_add_ipv4() call.
	* zebra/rtread_proc.c: (proc_route_read) ditto
	* zebra/zebra_rib.c: (nexthop_ipv4_add) add src argument.
	  (nexthop_ipv4_ifindex_add) ditto
	  (rib_add_ipv4) ditto
	  (nexthop_active_check) Add route-map processing.
	* zebra/zebra_routemap.c: new file for zebra route-map commands.
	* zebra/zebra_vty.c: (ip_protocol_cmd) Apply route-map to protocol
	  (vty_show_ip_route_detail) added "src" printing
	  (vty_show_ip_route) ditto
	  (show_ip_protocol_cmd) new command, list routemaps.
	  (config_write_protocol) write out routemap protocl config.
	  (zebra_vty_init) Install the new routemap protocol commands.
	* zebra/zserv.c: (zread_ipv4_add) added (NULL) src arg
	  (zebra_init) init zebra route-maps.
	* zebra/zserv.h: add zebra_route_map_init
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 02c73d1..693b333 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -32,6 +32,8 @@
 #include "linklist.h"
 #include "thread.h"
 #include "workqueue.h"
+#include "prefix.h"
+#include "routemap.h"
 
 #include "zebra/rib.h"
 #include "zebra/rt.h"
@@ -233,7 +235,7 @@
 }
 
 struct nexthop *
-nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
+nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
 {
   struct nexthop *nexthop;
 
@@ -241,6 +243,8 @@
   memset (nexthop, 0, sizeof (struct nexthop));
   nexthop->type = NEXTHOP_TYPE_IPV4;
   nexthop->gate.ipv4 = *ipv4;
+  if (src)
+    nexthop->src.ipv4 = *src;
 
   nexthop_add (rib, nexthop);
 
@@ -249,7 +253,7 @@
 
 static struct nexthop *
 nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, 
-			  unsigned int ifindex)
+                          struct in_addr *src, unsigned int ifindex)
 {
   struct nexthop *nexthop;
 
@@ -257,6 +261,8 @@
   memset (nexthop, 0, sizeof (struct nexthop));
   nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
   nexthop->gate.ipv4 = *ipv4;
+  if (src)
+    nexthop->src.ipv4 = *src;
   nexthop->ifindex = ifindex;
 
   nexthop_add (rib, nexthop);
@@ -685,12 +691,20 @@
 }
 #endif /* HAVE_IPV6 */
 
+#define RIB_SYSTEM_ROUTE(R) \
+        ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+
 static int
 nexthop_active_check (struct route_node *rn, struct rib *rib,
 		      struct nexthop *nexthop, int set)
 {
   struct interface *ifp;
+  route_map_result_t ret = RMAP_MATCH;
+  extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1];
+  struct route_map *rmap;
+  int family;
 
+  family = 0;
   switch (nexthop->type)
     {
     case NEXTHOP_TYPE_IFINDEX:
@@ -700,8 +714,9 @@
       else
 	UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       break;
-    case NEXTHOP_TYPE_IFNAME:
     case NEXTHOP_TYPE_IPV6_IFNAME:
+      family = AFI_IP6;
+    case NEXTHOP_TYPE_IFNAME:
       ifp = if_lookup_by_name (nexthop->ifname);
       if (ifp && if_is_up (ifp))
 	{
@@ -718,6 +733,7 @@
       break;
     case NEXTHOP_TYPE_IPV4:
     case NEXTHOP_TYPE_IPV4_IFINDEX:
+      family = AFI_IP;
       if (nexthop_active_ipv4 (rib, nexthop, set, rn))
 	SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       else
@@ -725,12 +741,14 @@
       break;
 #ifdef HAVE_IPV6
     case NEXTHOP_TYPE_IPV6:
+      family = AFI_IP6;
       if (nexthop_active_ipv6 (rib, nexthop, set, rn))
 	SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       else
 	UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       break;
     case NEXTHOP_TYPE_IPV6_IFINDEX:
+      family = AFI_IP6;
       if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
 	{
 	  ifp = if_lookup_by_index (nexthop->ifindex);
@@ -754,6 +772,26 @@
     default:
       break;
     }
+  if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+    return 0;
+
+  if (RIB_SYSTEM_ROUTE(rib) ||
+      (family == AFI_IP && rn->p.family != AF_INET) ||
+      (family == AFI_IP6 && rn->p.family != AF_INET6))
+    return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+
+  rmap = 0;
+  if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&
+        	proto_rm[family][rib->type])
+    rmap = route_map_lookup_by_name (proto_rm[family][rib->type]);
+  if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
+    rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
+  if (rmap) {
+      ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop);
+  }
+
+  if (ret == RMAP_DENYMATCH)
+    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
   return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
 }
 
@@ -782,8 +820,6 @@
 }
 
 
-#define RIB_SYSTEM_ROUTE(R) \
-        ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
 
 static void
 rib_install_kernel (struct route_node *rn, struct rib *rib)
@@ -1231,7 +1267,8 @@
 
 int
 rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
-	      struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+	      struct in_addr *gate, struct in_addr *src,
+	      unsigned int ifindex, u_int32_t vrf_id,
 	      u_int32_t metric, u_char distance)
 {
   struct rib *rib;
@@ -1300,9 +1337,9 @@
   if (gate)
     {
       if (ifindex)
-	nexthop_ipv4_ifindex_add (rib, gate, ifindex);
+	nexthop_ipv4_ifindex_add (rib, gate, src, ifindex);
       else
-	nexthop_ipv4_add (rib, gate);
+	nexthop_ipv4_add (rib, gate, src);
     }
   else
     nexthop_ifindex_add (rib, ifindex);
@@ -1539,7 +1576,7 @@
       switch (si->type)
         {
           case STATIC_IPV4_GATEWAY:
-            nexthop_ipv4_add (rib, &si->gate.ipv4);
+            nexthop_ipv4_add (rib, &si->gate.ipv4, NULL);
             break;
           case STATIC_IPV4_IFNAME:
             nexthop_ifname_add (rib, si->gate.ifname);
@@ -1563,7 +1600,7 @@
       switch (si->type)
         {
           case STATIC_IPV4_GATEWAY:
-            nexthop_ipv4_add (rib, &si->gate.ipv4);
+            nexthop_ipv4_add (rib, &si->gate.ipv4, NULL);
             break;
           case STATIC_IPV4_IFNAME:
             nexthop_ifname_add (rib, si->gate.ifname);