* bgp_routemap.c: New route-map command - "match ip route-source".

	[merge from GNU Zebra]
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index c1ca177..8a64fe9 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,5 +1,9 @@
 2005-02-02 Akihiro Mizutani <mizutani@net-chef.net>
 
+	* bgp_routemap.c: New route-map command - "match ip route-source".
+
+2005-02-02 Akihiro Mizutani <mizutani@net-chef.net>
+
 	* bgp_clist.[ch], bgp_route.c, bgp_routemap.c, bgp_vty.c:
 	  community-list cleanup.
 
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 73165d3..b11aaf2 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -57,7 +57,7 @@
        interface        :  Not yet
        ip address       :  Done
        ip next-hop      :  Done
-       ip route-source  :  (This will not be implemented by bgpd)
+       ip route-source  :  Done
        ip prefix-list   :  Done
        ipv6 address     :  Done
        ipv6 next-hop    :  Done
@@ -291,6 +291,64 @@
   route_match_ip_next_hop_free
 };
 
+/* `match ip route-source ACCESS-LIST' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_route_source (void *rule, struct prefix *prefix, 
+			     route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  struct bgp_info *bgp_info;
+  struct peer *peer;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      peer = bgp_info->peer;
+
+      if (! peer || sockunion_family (&peer->su) != AF_INET)
+	return RMAP_NOMATCH;
+
+      p.family = AF_INET;
+      p.prefix = peer->su.sin.sin_addr;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+	return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, &p) == FILTER_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip route-source' match statement. `arg' is
+   access-list name. */
+void *
+route_match_ip_route_source_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_route_source_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip route-source matching. */
+struct route_map_rule_cmd route_match_ip_route_source_cmd =
+{
+  "ip route-source",
+  route_match_ip_route_source,
+  route_match_ip_route_source_compile,
+  route_match_ip_route_source_free
+};
+
 /* `match ip address prefix-list PREFIX_LIST' */
 
 route_map_result_t
@@ -378,6 +436,59 @@
   route_match_ip_next_hop_prefix_list_free
 };
 
+/* `match ip route-source prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_route_source_prefix_list (void *rule, struct prefix *prefix,
+					 route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+  struct bgp_info *bgp_info;
+  struct peer *peer;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      peer = bgp_info->peer;
+
+      if (! peer || sockunion_family (&peer->su) != AF_INET)
+	return RMAP_NOMATCH;
+
+      p.family = AF_INET;
+      p.prefix = peer->su.sin.sin_addr;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_route_source_prefix_list_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_route_source_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd =
+{
+  "ip route-source prefix-list",
+  route_match_ip_route_source_prefix_list,
+  route_match_ip_route_source_prefix_list_compile,
+  route_match_ip_route_source_prefix_list_free
+};
+
 /* `match metric METRIC' */
 
 /* Match function return 1 if match is success else return zero. */
@@ -2305,6 +2416,44 @@
        "IP access-list number (expanded range)\n"
        "IP Access-list name\n")
 
+DEFUN (match_ip_route_source, 
+       match_ip_route_source_cmd,
+       "match ip route-source (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match advertising source address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP standard access-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0]);
+}
+
+DEFUN (no_match_ip_route_source,
+       no_match_ip_route_source_cmd,
+       "no match ip route-source",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match advertising source address of route\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "ip route-source", argv[0]);
+}
+
+ALIAS (no_match_ip_route_source,
+       no_match_ip_route_source_val_cmd,
+       "no match ip route-source (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match advertising source address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP standard access-list name\n");
+
 DEFUN (match_ip_address_prefix_list, 
        match_ip_address_prefix_list_cmd,
        "match ip address prefix-list WORD",
@@ -2379,6 +2528,43 @@
        "Match entries of prefix-lists\n"
        "IP prefix-list name\n")
 
+DEFUN (match_ip_route_source_prefix_list, 
+       match_ip_route_source_prefix_list_cmd,
+       "match ip route-source prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match advertising source address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_route_source_prefix_list,
+       no_match_ip_route_source_prefix_list_cmd,
+       "no match ip route-source prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match advertising source address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", NULL);
+
+  return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_route_source_prefix_list,
+       no_match_ip_route_source_prefix_list_val_cmd,
+       "no match ip route-source prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match advertising source address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n");
+
 DEFUN (match_metric, 
        match_metric_cmd,
        "match metric <0-4294967295>",
@@ -3395,8 +3581,10 @@
   route_map_install_match (&route_match_peer_cmd);
   route_map_install_match (&route_match_ip_address_cmd);
   route_map_install_match (&route_match_ip_next_hop_cmd);
+  route_map_install_match (&route_match_ip_route_source_cmd);
   route_map_install_match (&route_match_ip_address_prefix_list_cmd);
   route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+  route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);
   route_map_install_match (&route_match_aspath_cmd);
   route_map_install_match (&route_match_community_cmd);
   route_map_install_match (&route_match_ecommunity_cmd);
@@ -3429,6 +3617,9 @@
   install_element (RMAP_NODE, &match_ip_next_hop_cmd);
   install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
   install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+  install_element (RMAP_NODE, &match_ip_route_source_cmd);
+  install_element (RMAP_NODE, &no_match_ip_route_source_cmd);
+  install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd);
 
   install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
   install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
@@ -3436,6 +3627,9 @@
   install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
   install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
   install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_ip_route_source_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_val_cmd);
 
   install_element (RMAP_NODE, &match_aspath_cmd);
   install_element (RMAP_NODE, &no_match_aspath_cmd);