[RFC,PATCH 2/2] BGP: Implement skip_private_as_path_prefix.

Lennert Buytenhek buytenh at wantstofly.org
Sat Aug 12 21:31:13 CEST 2017


When skip_private_as_path_prefix is enabled for a BGP peer, leading
private AS numbers will be skipped when computing the length of AS
paths learned from this peer for the purpose of comparing path
lengths of different BGP-learned routes.
---
 nest/a-path.c      | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 nest/attrs.h       |  1 +
 proto/bgp/attrs.c  |  8 +++---
 proto/bgp/bgp.h    |  1 +
 proto/bgp/config.Y |  3 ++-
 5 files changed, 82 insertions(+), 5 deletions(-)

diff --git a/nest/a-path.c b/nest/a-path.c
index b453f702..c2d8bdf8 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -193,6 +193,80 @@ as_path_getlen_int(struct adata *path, int bs)
 }
 
 int
+as_is_private(u32 as)
+{
+  if (as >= 64512 && as <= 65534)
+    return 1;
+  if (as >= 4200000000 && as <= 4294967294)
+    return 1;
+  return 0;
+}
+
+int
+as_set_is_private(u32 *as, int len)
+{
+  int i;
+
+  for (i = 0; i < len; i++)
+    if (!as_is_private(get_u32(as + i)))
+      return 0;
+
+  return 1;
+}
+
+int
+as_sequence_private_prefix_length(u32 *as, int len)
+{
+  int i;
+
+  for (i = 0; i < len; i++)
+    if (!as_is_private(get_u32(as + i)))
+      break;
+
+  return i;
+}
+
+int
+as_path_getlen_ext(struct adata *path, int skip_private)
+{
+  int res = 0;
+  u8 *p = path->data;
+  u8 *q = p+path->length;
+  int len;
+  int i;
+
+  while (p<q)
+    {
+      switch (*p++)
+	{
+	case AS_PATH_SET:
+	  len = *p++;
+	  if (skip_private && !as_set_is_private((u32 *)p, len))
+	    skip_private = 0;
+	  if (!skip_private)
+	    res++;
+	  p += BS * len;
+	  break;
+	case AS_PATH_SEQUENCE:
+	  len = *p++;
+	  i = 0;
+	  if (skip_private)
+	    {
+	      i = as_sequence_private_prefix_length((u32 *)p, len);
+	      if (i < len)
+		skip_private = 0;
+	    }
+	  res += len - i;
+	  p += BS * len;
+	  break;
+	default:
+	  bug("as_path_getlen_ext: Invalid path segment");
+	}
+    }
+  return res;
+}
+
+int
 as_path_get_last(struct adata *path, u32 *orig_as)
 {
   int found = 0;
diff --git a/nest/attrs.h b/nest/attrs.h
index a34e64d3..d0808cd6 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -33,6 +33,7 @@ int as_path_convert_to_new(struct adata *path, byte *dst, int req_as);
 void as_path_format(struct adata *path, byte *buf, uint size);
 int as_path_getlen(struct adata *path);
 int as_path_getlen_int(struct adata *path, int bs);
+int as_path_getlen_ext(struct adata *path, int skip_private);
 int as_path_get_first(struct adata *path, u32 *orig_as);
 int as_path_get_last(struct adata *path, u32 *last_as);
 u32 as_path_get_last_nonaggregated(struct adata *path);
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 478c805c..ec6db1e5 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1280,8 +1280,8 @@ bgp_rte_better(rte *new, rte *old)
     {
       x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
       y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
-      n = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
-      o = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
+      n = x ? as_path_getlen_ext(x->u.ptr, new_bgp->cf->skip_private_as_path_prefix) : AS_PATH_MAXLEN;
+      o = y ? as_path_getlen_ext(y->u.ptr, old_bgp->cf->skip_private_as_path_prefix) : AS_PATH_MAXLEN;
       if (n < o)
 	return 1;
       if (n > o)
@@ -1401,8 +1401,8 @@ bgp_rte_mergable(rte *pri, rte *sec)
     {
       x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
       y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
-      p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
-      s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
+      p = x ? as_path_getlen_ext(x->u.ptr, pri_bgp->cf->skip_private_as_path_prefix) : AS_PATH_MAXLEN;
+      s = y ? as_path_getlen_ext(y->u.ptr, sec_bgp->cf->skip_private_as_path_prefix) : AS_PATH_MAXLEN;
 
       if (p != s)
 	return 0;
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 8652fae8..10fdeeda 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -52,6 +52,7 @@ struct bgp_config {
   int allow_local_as;			/* Allow that number of local ASNs in incoming AS_PATHs */
   int allow_local_pref;			/* Allow LOCAL_PREF in EBGP sessions */
   int iebgp_peer;			/* Peer has different AS but should be treated as internal peer */
+  int skip_private_as_path_prefix;	/* Skip leading private ASes when comparing AS path lengths */
   int gr_mode;				/* Graceful restart mode (BGP_GR_*) */
   int setkey;				/* Set MD5 password to system SA/SP database */
   unsigned gr_time;			/* Graceful restart timeout */
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index f01a6fb6..153747c6 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -28,7 +28,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
 	TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC,
 	SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE,
 	CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY,
-	IEBGP_PEER)
+	IEBGP_PEER, SKIP_PRIVATE_AS_PATH_PREFIX)
 
 CF_GRAMMAR
 
@@ -135,6 +135,7 @@ bgp_proto:
  | bgp_proto GRACEFUL RESTART AWARE ';' { BGP_CFG->gr_mode = BGP_GR_AWARE; }
  | bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; }
  | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
+ | bgp_proto SKIP_PRIVATE_AS_PATH_PREFIX bool ';' { BGP_CFG->skip_private_as_path_prefix = $3; }
  | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
  | bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; }
  | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
-- 
2.13.4


More information about the Bird-users mailing list