Browse Source

[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>'
Paul Jakma 15 years ago
parent
commit
41367172d8
10 changed files with 725 additions and 31 deletions
  1. 29 0
      bgpd/ChangeLog
  2. 79 3
      bgpd/bgp_attr.c
  3. 7 1
      bgpd/bgp_attr.h
  4. 393 25
      bgpd/bgp_route.c
  5. 6 0
      bgpd/bgp_route.h
  6. 168 1
      bgpd/bgp_routemap.c
  7. 1 0
      bgpd/bgpd.h
  8. 4 0
      doc/ChangeLog
  9. 24 1
      doc/bgpd.texi
  10. 14 0
      doc/routemap.texi

+ 29 - 0
bgpd/ChangeLog

@@ -1,3 +1,32 @@
+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'.
+           
 2007-07-26 Paul Jakma <paul.jakma@sun.com>
 
 	* (general) Clean up and compact capability parsing slightly.

+ 79 - 3
bgpd/bgp_attr.c

@@ -56,6 +56,8 @@ static struct message attr_str [] =
   { BGP_ATTR_RCID_PATH,        "RCID_PATH" },
   { BGP_ATTR_MP_REACH_NLRI,    "MP_REACH_NLRI" },
   { BGP_ATTR_MP_UNREACH_NLRI,  "MP_UNREACH_NLRI" },
+  { BGP_ATTR_EXT_COMMUNITIES,  "BGP_ATTR_EXT_COMMUNITIES" },
+  { BGP_ATTR_AS_PATHLIMIT,     "BGP_ATTR_AS_PATHLIMIT" },
   { 0, NULL }
 };
 int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
@@ -345,6 +347,11 @@ attrhash_key_make (void *p)
   key += attr->nexthop.s_addr;
   key += attr->med;
   key += attr->local_pref;
+  if (attr->pathlimit.as)
+    {
+      key += attr->pathlimit.ttl;
+      key += attr->pathlimit.as;
+    }
   
   if (attr->extra)
     {
@@ -396,7 +403,9 @@ attrhash_cmp (void *p1, void *p2)
       && attr1->aspath == attr2->aspath
       && attr1->community == attr2->community
       && attr1->med == attr2->med
-      && attr1->local_pref == attr2->local_pref)
+      && attr1->local_pref == attr2->local_pref
+      && attr1->pathlimit.ttl == attr2->pathlimit.ttl
+      && attr1->pathlimit.as == attr2->pathlimit.as)
     {
       struct attr_extra *ae1 = attr1->extra;
       struct attr_extra *ae2 = attr2->extra;
@@ -676,6 +685,42 @@ bgp_attr_flush (struct attr *attr)
     }
 }
 
+/* Parse AS_PATHLIMIT attribute in an UPDATE */
+static int
+bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
+                      struct attr *attr, u_char flag, u_char *startp)
+{
+  bgp_size_t total;
+  
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+  
+  if (flag != (BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL))
+    {
+      zlog (peer->log, LOG_ERR, 
+	    "AS-Pathlimit attribute flag isn't transitive %d", flag);
+      bgp_notify_send_with_data (peer, 
+				 BGP_NOTIFY_UPDATE_ERR, 
+				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+				 startp, total);
+      return -1;
+    }
+  
+  if (length != 5)
+    {
+      zlog (peer->log, LOG_ERR, 
+	    "AS-Pathlimit length, %u, is not 5", length);
+      bgp_notify_send_with_data (peer, 
+				 BGP_NOTIFY_UPDATE_ERR, 
+				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+				 startp, total);
+      return -1;
+    }
+  
+  attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
+  attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
+  return 0;
+}
 /* Get origin attribute of the update message. */
 static int
 bgp_attr_origin (struct peer *peer, bgp_size_t length, 
@@ -1290,7 +1335,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
 	{
 	  /* XXX warning: long int format, int arg (arg 5) */
 	  zlog (peer->log, LOG_WARNING, 
-		"%s error BGP attribute length %ld is smaller than min len",
+		"%s error BGP attribute length %lu is smaller than min len",
 		peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
 
 	  bgp_notify_send (peer, 
@@ -1386,6 +1431,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
 	case BGP_ATTR_EXT_COMMUNITIES:
 	  ret = bgp_attr_ext_communities (peer, length, attr, flag);
 	  break;
+        case BGP_ATTR_AS_PATHLIMIT:
+          ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
+          break;
 	default:
 	  ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
 	  break;
@@ -1824,7 +1872,25 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
 	    }
 	}
     }
-
+  
+  /* AS-Pathlimit */
+  if (attr->pathlimit.ttl)
+    {
+      u_int32_t as = attr->pathlimit.as;
+      
+      /* should already have been done in announce_check(), 
+       * but just in case..
+       */
+      if (!as)
+        as = peer->local_as;
+      
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
+      stream_putc (s, 5);
+      stream_putc (s, attr->pathlimit.ttl);
+      stream_putl (s, as);
+    }
+  
   /* Unknown transit attribute. */
   if (attr->extra && attr->extra->transit)
     stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
@@ -2034,6 +2100,16 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
     }
 #endif /* HAVE_IPV6 */
 
+  /* AS-Pathlimit */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
+    {
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
+      stream_putc (s, 5);
+      stream_putc (s, attr->pathlimit.ttl);
+      stream_putl (s, attr->pathlimit.as);
+    }
+
   /* Return total size of attribute. */
   len = stream_get_endp (s) - cp - 2;
   stream_putw_at (s, cp, len);

+ 7 - 1
bgpd/bgp_attr.h

@@ -109,7 +109,13 @@ struct attr
   struct in_addr nexthop;
   u_int32_t med;
   u_int32_t local_pref;
-
+  
+  /* AS-Pathlimit */
+  struct {
+    u_int32_t as;
+    u_char ttl;
+  } pathlimit;
+  
   /* Path origin attribute */
   u_char origin;
 };

+ 393 - 25
bgpd/bgp_route.c

@@ -883,7 +883,20 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
 	    return 0;
 	}
     }
-
+  
+  /* AS-Pathlimit check */
+  if (ri->attr->pathlimit.ttl && peer_sort (peer) == BGP_PEER_EBGP)
+    /* Our ASN has not yet been pre-pended, that's done in packet_attribute
+     * on output. Hence the test here is for >=.
+     */
+    if (aspath_count_hops (ri->attr->aspath) >= ri->attr->pathlimit.ttl)
+      {
+        if (BGP_DEBUG (filter, FILTER))
+          zlog_info ("%s [Update:SEND] suppressed, AS-Pathlimit TTL %u exceeded",
+                     peer->host, ri->attr->pathlimit.ttl);
+        return 0;
+      }
+  
   /* For modify attribute, copy it to temporary structure. */
   bgp_attr_dup (attr, ri->attr);
   
@@ -988,6 +1001,39 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
     }
 #endif /* HAVE_IPV6 */
 
+  /* AS-Pathlimit: Check ASN for private/confed */
+  if (attr->pathlimit.ttl)
+    {
+      /* locally originated update */
+      if (!attr->pathlimit.as)
+        attr->pathlimit.as = peer->local_as;
+      
+      /* if the AS_PATHLIMIT attribute is attached to a prefix by a
+         member of a confederation, then when the prefix is advertised outside
+         of the confederation boundary, then the AS number of the
+         confederation member inside of the AS_PATHLIMIT attribute should be
+         replaced by the confederation's AS number. */
+      if (peer_sort (from) == BGP_PEER_CONFED 
+          && peer_sort (peer) != BGP_PEER_CONFED)
+        attr->pathlimit.as = peer->local_as;
+
+      /* Private ASN should be updated whenever announcement leaves
+       * private space. This is deliberately done after simple confed
+       * based update..
+       */
+      if (attr->pathlimit.as >= BGP_PRIVATE_AS_MIN
+          && attr->pathlimit.as <= BGP_PRIVATE_AS_MAX)
+        {
+          if (peer->local_as < BGP_PRIVATE_AS_MIN 
+              || peer->local_as > BGP_PRIVATE_AS_MAX)
+            attr->pathlimit.as = peer->local_as;
+          /* Ours is private, try using theirs.. */
+          else if (peer->as < BGP_PRIVATE_AS_MIN
+                   || peer->local_as > BGP_PRIVATE_AS_MAX)
+            attr->pathlimit.as = peer->as;
+        }
+    }
+  
   /* If this is EBGP peer and remove-private-AS is set.  */
   if (peer_sort (peer) == BGP_PEER_EBGP
       && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
@@ -3151,7 +3197,18 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
   attr.nexthop = bgp_static->igpnexthop;
   attr.med = bgp_static->igpmetric;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
-
+  
+  if (bgp_static->ttl)
+    {
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+      attr.pathlimit.as = 0;
+      attr.pathlimit.ttl = bgp_static->ttl;
+    }
+  
+  if (bgp_static->atomic)
+    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+  
   /* Apply network route-map for export to this rsclient. */
   if (bgp_static->rmap.name)
     {
@@ -3297,6 +3354,17 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   attr.med = bgp_static->igpmetric;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
 
+  if (bgp_static->ttl)
+    {
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+      attr.pathlimit.as = 0;
+      attr.pathlimit.ttl = bgp_static->ttl;
+    }
+
+  if (bgp_static->atomic)
+    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+
   /* Apply route-map. */
   if (bgp_static->rmap.name)
     {
@@ -3517,17 +3585,44 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
   bgp_unlock_node (rn);
 }
 
+static void
+bgp_pathlimit_update_parents (struct bgp *bgp, struct bgp_node *rn,
+                              int ttl_edge)
+{
+  struct bgp_node *parent = rn;
+  struct bgp_static *sp;
+  
+  /* Existing static changed TTL, search parents and adjust their atomic */
+  while ((parent = parent->parent))
+    if ((sp = parent->info))
+      {
+        int sp_level = (sp->atomic ? 1 : 0);
+        ttl_edge ? sp->atomic++ : sp->atomic--;
+        
+        /* did we change state of parent whether atomic is set or not? */
+        if (sp_level != (sp->atomic ? 1 : 0))
+          {
+            bgp_static_update (bgp, &parent->p, sp,
+                               rn->table->afi, rn->table->safi);
+          }
+      }
+}
+
 /* Configure static BGP network.  When user don't run zebra, static
    route should be installed as valid.  */
 static int
 bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, 
-                u_int16_t afi, u_char safi, const char *rmap, int backdoor)
+                u_int16_t afi, u_char safi, const char *rmap, int backdoor,
+                u_char ttl)
 {
   int ret;
   struct prefix p;
   struct bgp_static *bgp_static;
   struct bgp_node *rn;
-  int need_update = 0;
+  u_char need_update = 0;
+  u_char ttl_change = 0;
+  u_char ttl_edge = (ttl ? 1 : 0);
+  u_char new = 0;
 
   /* Convert IP prefix string to struct prefix. */
   ret = str2prefix (ip_str, &p);
@@ -3556,10 +3651,22 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
       bgp_static = rn->info;
 
       /* Check previous routes are installed into BGP.  */
-      if (! bgp_static->backdoor && bgp_static->valid)
-	need_update = 1;
-
+      if (bgp_static->valid)
+        {
+          if (bgp_static->backdoor != backdoor
+              || bgp_static->ttl != ttl)
+            need_update = 1;
+        }
+      
+      /* need to catch TTL set/unset transitions for handling of
+       * ATOMIC_AGGREGATE 
+       */ 
+      if ((bgp_static->ttl ? 1 : 0) != ttl_edge)
+        ttl_change = 1;
+          
       bgp_static->backdoor = backdoor;
+      bgp_static->ttl = ttl;
+      
       if (rmap)
 	{
 	  if (bgp_static->rmap.name)
@@ -3585,6 +3692,10 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
       bgp_static->valid = 0;
       bgp_static->igpmetric = 0;
       bgp_static->igpnexthop.s_addr = 0;
+      bgp_static->ttl = ttl;
+      ttl_change = ttl_edge;
+      new = 1;
+      
       if (rmap)
 	{
 	  if (bgp_static->rmap.name)
@@ -3595,6 +3706,39 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
       rn->info = bgp_static;
     }
 
+  /* ".. sites that choose to advertise the
+   *  AS_PATHLIMIT path attribute SHOULD advertise the ATOMIC_AGGREGATE on
+   *  all less specific covering prefixes as well as the more specific
+   *  prefixes."
+   *
+   * So:
+   * Prefix that has just had pathlimit set/unset:
+   * - Must bump ATOMIC refcount on all parents.
+   *
+   * To catch less specific prefixes:
+   * - Must search children for ones with TTL, bump atomic refcount
+   *   (we dont care if we're deleting a less specific prefix..)
+   */
+  if (ttl_change)
+    {
+      /* Existing static changed TTL, search parents and adjust their atomic */
+      bgp_pathlimit_update_parents (bgp, rn, ttl_edge);
+    }
+  
+  if (new)
+    {
+      struct bgp_node *child;
+      struct bgp_static *sc;
+      
+      /* New static, search children and bump this statics atomic.. */
+      child = bgp_lock_node (rn); /* route_next_until unlocks it.. */
+      while ((child = bgp_route_next_until (child, rn)))
+        {
+          if ((sc = child->info) && sc->ttl)
+            bgp_static->atomic++;
+        }
+    }
+  
   /* If BGP scan is not enabled, we should install this route here.  */
   if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
     {
@@ -3647,7 +3791,10 @@ bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str,
     }
 
   bgp_static = rn->info;
-
+  
+  /* decrement atomic in parents, see bgp_static_set */
+  bgp_pathlimit_update_parents (bgp, rn, 0);
+  
   /* Update BGP RIB. */
   if (! bgp_static->backdoor)
     bgp_static_withdraw (bgp, &p, afi, safi);
@@ -3844,10 +3991,23 @@ DEFUN (bgp_network,
        "Specify a network to announce via BGP\n"
        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
 {
+  u_char ttl = 0;
+  
+  if (argc == 2)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
+  
   return bgp_static_set (vty, vty->index, argv[0],
-			 AFI_IP, bgp_node_safi (vty), NULL, 0);
+			 AFI_IP, bgp_node_safi (vty), NULL, 0, ttl);
 }
 
+ALIAS (bgp_network,
+       bgp_network_ttl_cmd,
+       "network A.B.C.D/M pathlimit <0-255>",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (bgp_network_route_map,
        bgp_network_route_map_cmd,
        "network A.B.C.D/M route-map WORD",
@@ -3857,7 +4017,7 @@ DEFUN (bgp_network_route_map,
        "Name of the route map\n")
 {
   return bgp_static_set (vty, vty->index, argv[0],
-			 AFI_IP, bgp_node_safi (vty), argv[1], 0);
+			 AFI_IP, bgp_node_safi (vty), argv[1], 0, 0);
 }
 
 DEFUN (bgp_network_backdoor,
@@ -3867,9 +4027,24 @@ DEFUN (bgp_network_backdoor,
        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
        "Specify a BGP backdoor route\n")
 {
-  return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+  u_char ttl = 0;
+  
+  if (argc == 2)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
+  
+  return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST,
+                         NULL, 1, ttl);
 }
 
+ALIAS (bgp_network_backdoor,
+       bgp_network_backdoor_ttl_cmd,
+       "network A.B.C.D/M backdoor pathlimit <0-255>",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify a BGP backdoor route\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (bgp_network_mask,
        bgp_network_mask_cmd,
        "network A.B.C.D mask A.B.C.D",
@@ -3880,7 +4055,11 @@ DEFUN (bgp_network_mask,
 {
   int ret;
   char prefix_str[BUFSIZ];
-
+  u_char ttl = 0;
+  
+  if (argc == 3)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[2], 1, 255);
+  
   ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
   if (! ret)
     {
@@ -3889,9 +4068,19 @@ DEFUN (bgp_network_mask,
     }
 
   return bgp_static_set (vty, vty->index, prefix_str,
-			 AFI_IP, bgp_node_safi (vty), NULL, 0);
+			 AFI_IP, bgp_node_safi (vty), NULL, 0, ttl);
 }
 
+ALIAS (bgp_network_mask,
+       bgp_network_mask_ttl_cmd,
+       "network A.B.C.D mask A.B.C.D pathlimit <0-255>",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (bgp_network_mask_route_map,
        bgp_network_mask_route_map_cmd,
        "network A.B.C.D mask A.B.C.D route-map WORD",
@@ -3904,7 +4093,7 @@ DEFUN (bgp_network_mask_route_map,
 {
   int ret;
   char prefix_str[BUFSIZ];
-
+  
   ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
   if (! ret)
     {
@@ -3913,7 +4102,7 @@ DEFUN (bgp_network_mask_route_map,
     }
 
   return bgp_static_set (vty, vty->index, prefix_str,
-			 AFI_IP, bgp_node_safi (vty), argv[2], 0);
+			 AFI_IP, bgp_node_safi (vty), argv[2], 0, 0);
 }
 
 DEFUN (bgp_network_mask_backdoor,
@@ -3927,6 +4116,10 @@ DEFUN (bgp_network_mask_backdoor,
 {
   int ret;
   char prefix_str[BUFSIZ];
+  u_char ttl = 0;
+  
+  if (argc == 3)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[2], 1, 255);
 
   ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
   if (! ret)
@@ -3935,9 +4128,21 @@ DEFUN (bgp_network_mask_backdoor,
       return CMD_WARNING;
     }
 
-  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
+  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST,
+                         NULL, 1, ttl);
 }
 
+ALIAS (bgp_network_mask_backdoor,
+       bgp_network_mask_backdoor_ttl_cmd,
+       "network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Specify a BGP backdoor route\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (bgp_network_mask_natural,
        bgp_network_mask_natural_cmd,
        "network A.B.C.D",
@@ -3946,6 +4151,10 @@ DEFUN (bgp_network_mask_natural,
 {
   int ret;
   char prefix_str[BUFSIZ];
+  u_char ttl = 0;
+  
+  if (argc == 2)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
 
   ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
   if (! ret)
@@ -3955,9 +4164,17 @@ DEFUN (bgp_network_mask_natural,
     }
 
   return bgp_static_set (vty, vty->index, prefix_str,
-			 AFI_IP, bgp_node_safi (vty), NULL, 0);
+			 AFI_IP, bgp_node_safi (vty), NULL, 0, ttl);
 }
 
+ALIAS (bgp_network_mask_natural,
+       bgp_network_mask_natural_ttl_cmd,
+       "network A.B.C.D pathlimit <0-255>",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (bgp_network_mask_natural_route_map,
        bgp_network_mask_natural_route_map_cmd,
        "network A.B.C.D route-map WORD",
@@ -3977,7 +4194,7 @@ DEFUN (bgp_network_mask_natural_route_map,
     }
 
   return bgp_static_set (vty, vty->index, prefix_str,
-			 AFI_IP, bgp_node_safi (vty), argv[1], 0);
+			 AFI_IP, bgp_node_safi (vty), argv[1], 0, 0);
 }
 
 DEFUN (bgp_network_mask_natural_backdoor,
@@ -3989,6 +4206,10 @@ DEFUN (bgp_network_mask_natural_backdoor,
 {
   int ret;
   char prefix_str[BUFSIZ];
+  u_char ttl = 0;
+  
+  if (argc == 2)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
 
   ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
   if (! ret)
@@ -3997,9 +4218,19 @@ DEFUN (bgp_network_mask_natural_backdoor,
       return CMD_WARNING;
     }
 
-  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
+  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST,
+                         NULL, 1, ttl);
 }
 
+ALIAS (bgp_network_mask_natural_backdoor,
+       bgp_network_mask_natural_backdoor_ttl_cmd,
+       "network A.B.C.D backdoor pathlimit (1-255>",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Specify a BGP backdoor route\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (no_bgp_network,
        no_bgp_network_cmd,
        "no network A.B.C.D/M",
@@ -4011,6 +4242,15 @@ DEFUN (no_bgp_network,
 			   bgp_node_safi (vty));
 }
 
+ALIAS (no_bgp_network,
+       no_bgp_network_ttl_cmd,
+       "no network A.B.C.D/M pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 ALIAS (no_bgp_network,
        no_bgp_network_route_map_cmd,
        "no network A.B.C.D/M route-map WORD",
@@ -4028,6 +4268,16 @@ ALIAS (no_bgp_network,
        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
        "Specify a BGP backdoor route\n")
 
+ALIAS (no_bgp_network,
+       no_bgp_network_backdoor_ttl_cmd,
+       "no network A.B.C.D/M backdoor pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify a BGP backdoor route\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (no_bgp_network_mask,
        no_bgp_network_mask_cmd,
        "no network A.B.C.D mask A.B.C.D",
@@ -4051,6 +4301,17 @@ DEFUN (no_bgp_network_mask,
 			   bgp_node_safi (vty));
 }
 
+ALIAS (no_bgp_network,
+       no_bgp_network_mask_ttl_cmd,
+       "no network A.B.C.D mask A.B.C.D pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 ALIAS (no_bgp_network_mask,
        no_bgp_network_mask_route_map_cmd,
        "no network A.B.C.D mask A.B.C.D route-map WORD",
@@ -4072,6 +4333,18 @@ ALIAS (no_bgp_network_mask,
        "Network mask\n"
        "Specify a BGP backdoor route\n")
 
+ALIAS (no_bgp_network_mask,
+       no_bgp_network_mask_backdoor_ttl_cmd,
+       "no network A.B.C.D mask A.B.C.D  backdoor pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Specify a BGP backdoor route\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (no_bgp_network_mask_natural,
        no_bgp_network_mask_natural_cmd,
        "no network A.B.C.D",
@@ -4110,6 +4383,25 @@ ALIAS (no_bgp_network_mask_natural,
        "Network number\n"
        "Specify a BGP backdoor route\n")
 
+ALIAS (no_bgp_network_mask_natural,
+       no_bgp_network_mask_natural_ttl_cmd,
+       "no network A.B.C.D pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
+ALIAS (no_bgp_network_mask_natural,
+       no_bgp_network_mask_natural_backdoor_ttl_cmd,
+       "no network A.B.C.D backdoor pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Specify a BGP backdoor route\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 #ifdef HAVE_IPV6
 DEFUN (ipv6_bgp_network,
        ipv6_bgp_network_cmd,
@@ -4117,9 +4409,23 @@ DEFUN (ipv6_bgp_network,
        "Specify a network to announce via BGP\n"
        "IPv6 prefix <network>/<length>\n")
 {
-  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+  u_char ttl = 0;
+  
+  if (argc == 2)
+    VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255);
+
+  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST,
+                         NULL, 0, ttl);
 }
 
+ALIAS (ipv6_bgp_network,
+       ipv6_bgp_network_ttl_cmd,
+       "network X:X::X:X/M pathlimit <0-255>",
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (ipv6_bgp_network_route_map,
        ipv6_bgp_network_route_map_cmd,
        "network X:X::X:X/M route-map WORD",
@@ -4129,7 +4435,7 @@ DEFUN (ipv6_bgp_network_route_map,
        "Name of the route map\n")
 {
   return bgp_static_set (vty, vty->index, argv[0], AFI_IP6,
-			 bgp_node_safi (vty), argv[1], 0);
+			 bgp_node_safi (vty), argv[1], 0, 0);
 }
 
 DEFUN (no_ipv6_bgp_network,
@@ -4151,6 +4457,15 @@ ALIAS (no_ipv6_bgp_network,
        "Route-map to modify the attributes\n"
        "Name of the route map\n")
 
+ALIAS (no_ipv6_bgp_network,
+       no_ipv6_bgp_network_ttl_cmd,
+       "no network X:X::X:X/M pathlimit <0-255>",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "AS-Path hopcount limit attribute\n"
+       "AS-Pathlimit TTL, in number of AS-Path hops\n")
+
 ALIAS (ipv6_bgp_network,
        old_ipv6_bgp_network_cmd,
        "ipv6 bgp network X:X::X:X/M",
@@ -5777,7 +6092,18 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
 	    }
 	  vty_out (vty, "%s", VTY_NEWLINE);
 	}
-
+      
+      /* 7: AS Pathlimit */
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AS_PATHLIMIT))
+        {
+          
+          vty_out (vty, "      AS-Pathlimit: %u",
+                   attr->pathlimit.ttl);
+          if (attr->pathlimit.as)
+            vty_out (vty, " (%u)", attr->pathlimit.as);
+          vty_out (vty, "%s", VTY_NEWLINE);
+        }
+      
       if (binfo->extra && binfo->extra->damp_info)
 	bgp_damp_info_vty (vty, binfo);
 
@@ -11166,8 +11492,13 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
 
 	if (bgp_static->rmap.name)
 	  vty_out (vty, " route-map %s", bgp_static->rmap.name);
-	else if (bgp_static->backdoor)
-	  vty_out (vty, " backdoor");
+	else 
+	  {
+	    if (bgp_static->backdoor)
+	      vty_out (vty, " backdoor");
+            if (bgp_static->ttl)
+              vty_out (vty, " pathlimit %u", bgp_static->ttl);
+          }
 
 	vty_out (vty, "%s", VTY_NEWLINE);
       }
@@ -11255,6 +11586,12 @@ bgp_route_init ()
   install_element (BGP_NODE, &bgp_network_backdoor_cmd);
   install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd);
   install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
+  install_element (BGP_NODE, &bgp_network_ttl_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_ttl_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_natural_ttl_cmd);
+  install_element (BGP_NODE, &bgp_network_backdoor_ttl_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_backdoor_ttl_cmd);
+  install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd);
   install_element (BGP_NODE, &no_bgp_network_cmd);
   install_element (BGP_NODE, &no_bgp_network_mask_cmd);
   install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd);
@@ -11264,6 +11601,12 @@ bgp_route_init ()
   install_element (BGP_NODE, &no_bgp_network_backdoor_cmd);
   install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd);
   install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd);
+  install_element (BGP_NODE, &no_bgp_network_ttl_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_ttl_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_ttl_cmd);
+  install_element (BGP_NODE, &no_bgp_network_backdoor_ttl_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_backdoor_ttl_cmd);
+  install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd);
 
   install_element (BGP_NODE, &aggregate_address_cmd);
   install_element (BGP_NODE, &aggregate_address_mask_cmd);
@@ -11293,12 +11636,23 @@ bgp_route_init ()
   install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
-  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_backdoor_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_backdoor_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd);  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_backdoor_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_backdoor_ttl_cmd);
+  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd);  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4_NODE, &aggregate_address_cmd);
   install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd);
   install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd);
@@ -11327,12 +11681,24 @@ bgp_route_init ()
   install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_backdoor_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_backdoor_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd);  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_backdoor_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_backdoor_ttl_cmd);
+  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd);  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4M_NODE, &aggregate_address_cmd);
   install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd);
   install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd);
@@ -11518,8 +11884,10 @@ bgp_route_init ()
   /* New config IPv6 BGP commands.  */
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd);
 
   install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
   install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd);

+ 6 - 0
bgpd/bgp_route.h

@@ -104,6 +104,9 @@ struct bgp_static
   /* IGP nexthop. */
   struct in_addr igpnexthop;
 
+  /* Atomic set reference count (ie cause of pathlimit) */
+  u_int32_t atomic;
+  
   /* BGP redistribute route-map.  */
   struct
   {
@@ -113,6 +116,9 @@ struct bgp_static
 
   /* MPLS label.  */
   u_char tag[3];
+  
+  /* AS-Pathlimit TTL */
+  u_char ttl;
 };
 
 /* Flags which indicate a route is unuseable in some form */

+ 168 - 1
bgpd/bgp_routemap.c

@@ -87,13 +87,105 @@ o Cisco route-map
       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)' */
 
@@ -3538,6 +3630,70 @@ ALIAS (no_set_originator_id,
        "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 @@ bgp_route_map_init (void)
   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 @@ bgp_route_map_init (void)
   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);
 }

+ 1 - 0
bgpd/bgpd.h

@@ -591,6 +591,7 @@ struct bgp_nlri
 #define BGP_ATTR_MP_REACH_NLRI                  14
 #define BGP_ATTR_MP_UNREACH_NLRI                15
 #define BGP_ATTR_EXT_COMMUNITIES                16
+#define BGP_ATTR_AS_PATHLIMIT                   21
 
 /* BGP update origin.  */
 #define BGP_ORIGIN_IGP                           0

+ 4 - 0
doc/ChangeLog

@@ -1,3 +1,7 @@
+2007-07-31 Paul Jakma <paul.jakma@sun.com>
+
+	* bgpd.texi: Document 'network ... pathlimit <ttl>'
+
 2007-05-01 David L Stevens <dlstevens@us.ibm.com>
 
 	* main.texi: added route-map, prefix-list, ip protocol

+ 24 - 1
doc/bgpd.texi

@@ -145,10 +145,33 @@ router bgp 1
 @end example
 This configuration example says that network 10.0.0.0/8 will be
 announced to all neighbors.  Some vendors' routers don't advertise
-routes if they aren't present in their IGP routing tables; @code{bgp}
+routes if they aren't present in their IGP routing tables; @code{bgpd}
 doesn't care about IGP routes when announcing its routes.
 @end deffn
 
+@deffn {BGP} {network @var{A.B.C.D/M} pathlimit <0-255>} {}
+This command configures a route to be originated into BGP, just as with the
+previous command, but additionally sets an AS-Pathlimit TTL to be advertised
+on the route. See draft-ietf-idr-as-pathlimit.
+
+Specifying a TTL of 0 can be used to remove pathlimit from a previously
+configured network statement.
+
+Note that when advertising prefixes with AS-Pathlimit set, all less-specific
+prefixes advertised SHOULD also have the Atomic-Aggregate attribute set.
+Failure to do so increases the risks of accidental routing loops occuring.
+
+This implementation will try to automatically set Atomic-Aggregate as
+appropriate on any less-specific prefixes originated by the same speaker,
+however it will not (and often can not) do so where @b{other} speakers in
+the AS are originating more specifics.
+
+Hence the system administrator must take care to ensure that all
+less-specific prefixes originated carry atomic-aggregate as appropriate, by
+manually configuring speakers originating less-specifics to set
+Atomic-Aggregate on those advertisements!
+@end deffn
+
 @deffn {BGP} {no network @var{A.B.C.D/M}} {}
 @end deffn
 

+ 14 - 0
doc/routemap.texi

@@ -155,6 +155,10 @@ Matches the specified @var{metric}.
 Matches the specified  @var{community_list}
 @end deffn
 
+@deffn {Route-map Command} {match pathlimit as @var{ASN}} {}
+Matches the specified AS-Pathlimit @var{ASN}.
+@end deffn
+
 @node Route Map Set Command
 @section Route Map Set Command
 
@@ -190,6 +194,16 @@ Set the BGP-4+ global IPv6 nexthop address.
 Set the BGP-4+ link local IPv6 nexthop address.
 @end deffn
 
+@deffn {Route-map Command} {set pathlimit ttl @var{ttl}} {}
+Sets the specified AS-Pathlimit @var{ttl} on the route. This will also cause
+the AS to be set to the local AS. 
+
+Note that the AS-Pathlimit RFC specifies that speakers advertising this
+attribute should set Atomic-aggregate on all less specific routes. Setting
+AS-Pathlimit by route-map does not do this, the user must do so themselves,
+as they wish. 
+@end deffn
+
 @node Route Map Call Command
 @section Route Map Call Command