[bgpd] Add support for AS_PATHLIMIT / draft-ietf-idr-as-pathlimit

2007-07-31 Paul Jakma <paul.jakma@sun.com>

	* (general) Support for draft-ietf-idr-as-pathlimit-03.
	* bgp_attr.h: (struct attr) Add pathlimit struct
          bgp_attr.c: (attr_str) Add BGP_ATTR_AS_PATHLIMIT string.
          (attrhash_key_make) tally pathlimit too
          (attrhash_cmp) cmp pathlimit attr
          (bgp_attr_aspathlimit) New, parse AS_PATHLIMIT attr.
          (bgp_attr_parse) ditto
          (bgp_packet_attribute) Write out AS_PATHLIMIT when set
          (bgp_dump_routes_attr) ditto
         * bgp_route.h: (struct bgp_static) Add TTL field
         * bgp_route.c: (bgp_announce_check) Drop paths that are over
           their hop-count TTL before sending via EBGP.
           Mangle ASN in pathlimit for confeds/private as best we can.
           (bgp_static_update_{rsclient,main}) Add any configure pathlimit
           information.
           (bgp_pathlimit_update_parents) New, update atomic-aggr setting for
           parents of an aspathlimit'ed static.
           (bgp_static_set) Add TTL argument, for all the 'bgp network'
           commands.
           Call previous for TTL changed statics.
           (bgp_static_unset) Call pathlimit_update_parents.
           (various bgp network commands) Add 'pathlimit <0-255>' qualifier
           to all the various forms, bar route-map - which can set ttl
           itself.
         * bgp_routemap.c: (general) Add support for 'set pathlimit ttl' and
           'match pathlimit as'.
         * doc/bgpd.texi: Document 'network ... pathlimit <ttl>'
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 6a44c47..305d679 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -87,14 +87,106 @@
       origin            :  Done
       tag               :  (This will not be implemented by bgpd)
       weight            :  Done
+      pathlimit		:  Done
 
 o Local extention
 
   set ipv6 next-hop global: Done
   set ipv6 next-hop local : Done
+  set pathlimit ttl       : Done
+  match pathlimit as     : Done
 
 */ 
 
+/* Compiles either AS or TTL argument. It is amused the VTY code
+ * has already range-checked the values to be suitable as TTL or ASN
+ */
+static void *
+route_pathlimit_compile (const char *arg)
+{
+  unsigned long tmp;
+  u_int32_t *val;
+  char *endptr = NULL;
+
+  /* TTL or AS value shoud be integer. */
+  if (! all_digit (arg))
+    return NULL;
+  
+  tmp = strtoul (arg, &endptr, 10);
+  if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX)
+    return NULL;
+   
+  if (!(val = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t))))
+    return NULL;
+  
+  *val = tmp;
+  
+  return val;
+}
+
+static void
+route_pathlimit_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static route_map_result_t
+route_match_pathlimit_as (void *rule, struct prefix *prefix, route_map_object_t type,
+      void *object)
+{
+  struct bgp_info *info = object;
+  struct attr *attr = info->attr;
+  uint32_t as = *(uint32_t *)rule;
+  
+  if (type != RMAP_BGP)
+    return RMAP_NOMATCH;
+  
+  if (!attr->pathlimit.as)
+    return RMAP_NOMATCH;
+  
+  if (as == attr->pathlimit.as)
+    return RMAP_MATCH;
+  
+  return RMAP_NOMATCH;
+}
+
+/* 'match pathlimit as' */
+struct route_map_rule_cmd route_match_pathlimit_as_cmd =
+{
+  "pathlimit as",
+  route_match_pathlimit_as,
+  route_pathlimit_compile,
+  route_pathlimit_free
+};
+
+/* Set pathlimit TTL. */
+static route_map_result_t
+route_set_pathlimit_ttl (void *rule, struct prefix *prefix,
+		         route_map_object_t type, void *object)
+{
+  struct bgp_info *info = object;
+  struct attr *attr = info->attr;
+  u_char ttl = *(uint32_t *)rule;
+  
+  if (type == RMAP_BGP)
+    {
+      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
+      attr->pathlimit.ttl = ttl;
+      attr->pathlimit.as = 0;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Set local preference rule structure. */
+struct route_map_rule_cmd route_set_pathlimit_ttl_cmd = 
+{
+  "pathlimit ttl",
+  route_set_pathlimit_ttl,
+  route_pathlimit_compile,
+  route_pathlimit_free,
+};
+
  /* 'match peer (A.B.C.D|X:X::X:X)' */
 
 /* Compares the peer specified in the 'match peer' clause with the peer
@@ -3538,6 +3630,70 @@
        "BGP originator ID attribute\n"
        "IP address of originator\n")
 
+DEFUN (set_pathlimit_ttl,
+       set_pathlimit_ttl_cmd,
+       "set pathlimit ttl <1-255>",
+       SET_STR
+       "BGP AS-Pathlimit attribute\n"
+       "Set AS-Path Hop-count TTL\n")
+{
+  return bgp_route_set_add (vty, vty->index, "pathlimit ttl", argv[0]);
+}
+
+DEFUN (no_set_pathlimit_ttl,
+       no_set_pathlimit_ttl_cmd,
+       "no set pathlimit ttl",
+       NO_STR
+       SET_STR
+       "BGP AS-Pathlimit attribute\n"
+       "Set AS-Path Hop-count TTL\n")
+{
+  if (argc == 0)
+    return bgp_route_set_delete (vty, vty->index, "pathlimit ttl", NULL);
+  
+  return bgp_route_set_delete (vty, vty->index, "pathlimit ttl", argv[0]);
+}
+
+ALIAS (no_set_pathlimit_ttl,
+       no_set_pathlimit_ttl_val_cmd,
+       "no set pathlimit ttl <1-255>",
+       NO_STR
+       MATCH_STR
+       "BGP AS-Pathlimit attribute\n"
+       "Set AS-Path Hop-count TTL\n")
+
+DEFUN (match_pathlimit_as,
+       match_pathlimit_as_cmd,
+       "match pathlimit as <1-65535>",
+       MATCH_STR
+       "BGP AS-Pathlimit attribute\n"
+       "Match Pathlimit AS number\n")
+{
+  return bgp_route_match_add (vty, vty->index, "pathlimit as", argv[0]);
+}
+
+DEFUN (no_match_pathlimit_as,
+       no_match_pathlimit_as_cmd,
+       "no match pathlimit as",
+       NO_STR
+       MATCH_STR
+       "BGP AS-Pathlimit attribute\n"
+       "Match Pathlimit AS number\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "pathlimit as", NULL);
+  
+  return bgp_route_match_delete (vty, vty->index, "pathlimit as", argv[0]);
+}
+
+ALIAS (no_match_pathlimit_as,
+       no_match_pathlimit_as_val_cmd,
+       "no match pathlimit as <1-65535>",
+       NO_STR
+       MATCH_STR
+       "BGP AS-Pathlimit attribute\n"
+       "Match Pathlimit ASN\n")
+
 
 /* Initialization of route map. */
 void
@@ -3671,7 +3827,7 @@
   route_map_install_match (&route_match_ipv6_address_prefix_list_cmd);
   route_map_install_set (&route_set_ipv6_nexthop_global_cmd);
   route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
-
+  
   install_element (RMAP_NODE, &match_ipv6_address_cmd);
   install_element (RMAP_NODE, &no_match_ipv6_address_cmd);
   install_element (RMAP_NODE, &match_ipv6_next_hop_cmd);
@@ -3685,4 +3841,15 @@
   install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
   install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd);
 #endif /* HAVE_IPV6 */
+
+  /* AS-Pathlimit */
+  route_map_install_match (&route_match_pathlimit_as_cmd);
+  route_map_install_set (&route_set_pathlimit_ttl_cmd);
+
+  install_element (RMAP_NODE, &set_pathlimit_ttl_cmd);
+  install_element (RMAP_NODE, &no_set_pathlimit_ttl_cmd);
+  install_element (RMAP_NODE, &no_set_pathlimit_ttl_val_cmd);
+  install_element (RMAP_NODE, &match_pathlimit_as_cmd);
+  install_element (RMAP_NODE, &no_match_pathlimit_as_cmd);
+  install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd);
 }