[quagga-dev 5002] BGP AS-Pathlimit support

Paul Jakma Paul.Jakma at Sun.COM
Mon Jul 30 20:39:54 IST 2007


Support for Tony Li's:

  http://tools.ietf.org/html/draft-ietf-idr-as-pathlimit-03

is attached.

  I've tested I can configure a static route in bgpd with pathlimit set 
(i seem to have forgotten to install the 'no network' forms for the 
pathlimit commands hough ;) ) - and the attribute gets sent (at least, a 
peer logs unknown attribute with the right code and length ;) ). It's a 
simple enough attribute though.

Lab-testing of this patch would be very much appreciated.

regards,
-- 
Paul Jakma,
Solaris Networking                       Sun Microsystems, Scotland
http://opensolaris.org/os/project/quagga tel: EMEA x73150 / +44 15066 73150
-------------- next part --------------
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 07c9413..7aff8ea 100644
--- a/bgpd/bgp_attr.c
+++ b/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)
+    {
+      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,8 @@ 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);
 	default:
 	  ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
 	  break;
@@ -1824,7 +1871,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 +2099,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);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index ac14947..6d8b434 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -87,6 +87,13 @@ struct attr_extra
   u_char mp_nexthop_len;
 };
 
+/* AS-Pathlimit */
+struct aspathlimit
+{
+  u_int32_t as;
+  u_char ttl;
+};
+
 /* BGP core attribute structure. */
 struct attr
 {
@@ -109,7 +116,9 @@ struct attr
   struct in_addr nexthop;
   u_int32_t med;
   u_int32_t local_pref;
-
+  
+  struct aspathlimit pathlimit;
+  
   /* Path origin attribute */
   u_char origin;
 };
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1c0e6f1..f8c4205 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -883,7 +883,17 @@ 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)
+    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 +998,38 @@ 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)
+    {
+      /* 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;
+        }
+      /* locally originated update */
+      if (!attr->pathlimit.as)
+        attr->pathlimit.as = peer->local_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,6 +3193,13 @@ 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.pathlimit.as = 0;
+      attr.pathlimit.ttl = bgp_static->ttl;
+    }
 
   /* Apply network route-map for export to this rsclient. */
   if (bgp_static->rmap.name)
@@ -3297,6 +3346,13 @@ 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.pathlimit.as = 0;
+      attr.pathlimit.ttl = bgp_static->ttl;
+    }
+
   /* Apply route-map. */
   if (bgp_static->rmap.name)
     {
@@ -3521,7 +3577,8 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
    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;
@@ -3556,10 +3613,16 @@ 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;
+        }
+      
       bgp_static->backdoor = backdoor;
+      bgp_static->ttl = ttl;
+      
       if (rmap)
 	{
 	  if (bgp_static->rmap.name)
@@ -3585,6 +3648,8 @@ 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;
+      
       if (rmap)
 	{
 	  if (bgp_static->rmap.name)
@@ -3844,10 +3909,22 @@ 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 <1-255>",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\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 +3934,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 +3944,23 @@ 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 <1-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-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 +3971,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 +3984,18 @@ 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 <1-255>",
+       "Specify a network to announce via BGP\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\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 +4008,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 +4017,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 +4031,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 +4043,20 @@ 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 <1-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-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 +4065,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 +4078,16 @@ 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 <1-255>",
+       "Specify a network to announce via BGP\n"
+       "Network number\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 +4107,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 +4119,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 +4131,18 @@ 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-Pathlimit TTL, in number of AS-Path hops\n")
+
 DEFUN (no_bgp_network,
        no_bgp_network_cmd,
        "no network A.B.C.D/M",
@@ -4117,9 +4260,22 @@ 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 <1-255>",
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\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 +4285,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,
@@ -5777,7 +5933,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 +11333,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 +11427,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);
@@ -11293,7 +11471,12 @@ 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);
@@ -11327,6 +11510,12 @@ 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);
@@ -11518,6 +11707,7 @@ 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);
 
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index c7eb8c6..144ea39 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -113,6 +113,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 */
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 @@ 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)' */
 
 /* Compares the peer specified in the 'match peer' clause with the peer
@@ -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);
 }
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 8b180a4..3fba604 100644
--- a/bgpd/bgpd.h
+++ b/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


More information about the Quagga-dev mailing list