[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/rt_netlink.c b/zebra/rt_netlink.c
index e2f1f9d..3b602c4 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -725,6 +725,7 @@
 
   void *dest;
   void *gate;
+  void *src;
 
   rtm = NLMSG_DATA (h);
 
@@ -764,6 +765,7 @@
   metric = 0;
   dest = NULL;
   gate = NULL;
+  src = NULL;
 
   if (tb[RTA_OIF])
     index = *(int *) RTA_DATA (tb[RTA_OIF]);
@@ -773,6 +775,9 @@
   else
     dest = anyaddr;
 
+  if (tb[RTA_PREFSRC])
+    src = RTA_DATA (tb[RTA_PREFSRC]);
+
   /* Multipath treatment is needed. */
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
@@ -787,7 +792,7 @@
       memcpy (&p.prefix, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
 
-      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
+      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
     }
 #ifdef HAVE_IPV6
   if (rtm->rtm_family == AF_INET6)
@@ -834,6 +839,7 @@
   int table;
   void *dest;
   void *gate;
+  void *src;
 
   rtm = NLMSG_DATA (h);
 
@@ -890,6 +896,7 @@
   index = 0;
   dest = NULL;
   gate = NULL;
+  src = NULL;
 
   if (tb[RTA_OIF])
     index = *(int *) RTA_DATA (tb[RTA_OIF]);
@@ -902,6 +909,9 @@
   if (tb[RTA_GATEWAY])
     gate = RTA_DATA (tb[RTA_GATEWAY]);
 
+  if (tb[RTA_PREFSRC])
+    src = RTA_DATA (tb[RTA_PREFSRC]);
+
   if (rtm->rtm_family == AF_INET)
     {
       struct prefix_ipv4 p;
@@ -920,7 +930,7 @@
         }
 
       if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+        rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
       else
         rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
     }
@@ -1489,7 +1499,9 @@
 		    {
 		      addattr_l (&req.n, sizeof req, RTA_GATEWAY,
 				 &nexthop->rgate.ipv4, bytelen);
-
+                      if (nexthop->src.ipv4.s_addr)
+		          addattr_l(&req.n, sizeof req, RTA_PREFSRC,
+				     &nexthop->src.ipv4, bytelen);
 		      if (IS_ZEBRA_DEBUG_KERNEL)
 			zlog_debug("netlink_route_multipath() (recursive, "
 				   "1 hop): nexthop via %s if %u",
@@ -1519,6 +1531,11 @@
 		    {
 		      addattr32 (&req.n, sizeof req, RTA_OIF,
 				 nexthop->rifindex);
+                      if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+                           || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
+                          && nexthop->src.ipv4.s_addr)
+                        addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+				 &nexthop->src.ipv4, bytelen);
 
 		      if (IS_ZEBRA_DEBUG_KERNEL)
 			zlog_debug("netlink_route_multipath() (recursive, "
@@ -1547,6 +1564,9 @@
 		    {
 		      addattr_l (&req.n, sizeof req, RTA_GATEWAY,
 				 &nexthop->gate.ipv4, bytelen);
+		      if (nexthop->src.ipv4.s_addr)
+                        addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+				 &nexthop->src.ipv4, bytelen);
 
 		      if (IS_ZEBRA_DEBUG_KERNEL)
 			zlog_debug("netlink_route_multipath() (single hop): "
@@ -1571,8 +1591,19 @@
 #endif /* HAVE_IPV6 */
                   if (nexthop->type == NEXTHOP_TYPE_IFINDEX
                       || nexthop->type == NEXTHOP_TYPE_IFNAME
-                      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
-                      || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+                      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+		    {
+		      addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
+
+		      if (nexthop->src.ipv4.s_addr)
+                        addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+				 &nexthop->src.ipv4, bytelen);
+
+		      if (IS_ZEBRA_DEBUG_KERNEL)
+			zlog_debug("netlink_route_multipath() (single hop): "
+				   "nexthop via if %u", nexthop->ifindex);
+		    }
+                  else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
 		    {
 		      addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
@@ -1596,6 +1627,7 @@
       char buf[1024];
       struct rtattr *rta = (void *) buf;
       struct rtnexthop *rtnh;
+      union g_addr *src = NULL;
 
       rta->rta_type = RTA_MULTIPATH;
       rta->rta_len = RTA_LENGTH (0);
@@ -1640,6 +1672,9 @@
                                      &nexthop->rgate.ipv4, bytelen);
                       rtnh->rtnh_len += sizeof (struct rtattr) + 4;
 
+		      if (nexthop->src.ipv4.s_addr)
+                        src = &nexthop->src;
+
 		      if (IS_ZEBRA_DEBUG_KERNEL)
 			zlog_debug("netlink_route_multipath() (recursive, "
 				   "multihop): nexthop via %s if %u",
@@ -1662,10 +1697,20 @@
 		    }
 #endif /* HAVE_IPV6 */
                   /* ifindex */
-                  if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
-                      || nexthop->rtype == NEXTHOP_TYPE_IFNAME
-                      || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
-                      || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
+                  if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
+		      || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
+                      || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
+		    {
+		      rtnh->rtnh_ifindex = nexthop->rifindex;
+                      if (nexthop->src.ipv4.s_addr)
+                        src = &nexthop->src;
+
+		      if (IS_ZEBRA_DEBUG_KERNEL)
+			zlog_debug("netlink_route_multipath() (recursive, "
+				   "multihop): nexthop via if %u",
+				   nexthop->rifindex);
+		    }
+		  else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
 		    {
 		      rtnh->rtnh_ifindex = nexthop->rifindex;
@@ -1701,6 +1746,9 @@
 				     &nexthop->gate.ipv4, bytelen);
 		      rtnh->rtnh_len += sizeof (struct rtattr) + 4;
 
+		      if (nexthop->src.ipv4.s_addr)
+                        src = &nexthop->src;
+
                       if (IS_ZEBRA_DEBUG_KERNEL)
 			zlog_debug("netlink_route_multipath() (multihop): "
 				   "nexthop via %s if %u",
@@ -1723,10 +1771,18 @@
 		    }
 #endif /* HAVE_IPV6 */
                   /* ifindex */
-                  if (nexthop->type == NEXTHOP_TYPE_IFINDEX
-                      || nexthop->type == NEXTHOP_TYPE_IFNAME
-                      || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
-                      || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+                  if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+		      || nexthop->type == NEXTHOP_TYPE_IFINDEX
+                      || nexthop->type == NEXTHOP_TYPE_IFNAME)
+                    {
+		      rtnh->rtnh_ifindex = nexthop->ifindex;
+		      if (nexthop->src.ipv4.s_addr)
+			src = &nexthop->src;
+		      if (IS_ZEBRA_DEBUG_KERNEL)
+			zlog_debug("netlink_route_multipath() (multihop): "
+				   "nexthop via if %u", nexthop->ifindex);
+		    }
+                  else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
 		    {
 		      rtnh->rtnh_ifindex = nexthop->ifindex;
@@ -1746,6 +1802,8 @@
                 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
             }
         }
+      if (src)
+        addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
 
       if (rta->rta_len > RTA_LENGTH (0))
         addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),