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