diff options
-rw-r--r-- | bgpd/bgp_aspath.c | 54 | ||||
-rw-r--r-- | bgpd/bgp_aspath.h | 12 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 21 | ||||
-rw-r--r-- | bgpd/bgp_btoa.c | 3 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 7 | ||||
-rw-r--r-- | bgpd/bgp_routemap.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_script.c | 3 | ||||
-rw-r--r-- | bgpd/bgpd.c | 7 | ||||
-rw-r--r-- | bgpd/bgpd.h | 1 | ||||
-rw-r--r-- | lib/asn.c | 64 | ||||
-rw-r--r-- | lib/asn.h | 15 | ||||
-rw-r--r-- | tests/bgpd/test_aspath.c | 6 | ||||
-rw-r--r-- | tests/lib/test_printfrr.c | 9 |
13 files changed, 166 insertions, 38 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 9f74aa76d..fdfe494e9 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -302,9 +302,13 @@ static struct assegment *assegment_normalise(struct assegment *head) return head; } -static struct aspath *aspath_new(void) +static struct aspath *aspath_new(enum asnotation_mode asnotation) { - return XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath)); + struct aspath *as; + + as = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath)); + as->asnotation = asnotation; + return as; } /* Free AS path structure. */ @@ -552,8 +556,10 @@ static void aspath_make_str_count(struct aspath *as, bool make_json) * * This was changed to 10 after the well-known BGP assertion, which * had hit some parts of the Internet in May of 2009. + * plain format : '4294967295 ' : 10 + 1 + * astod format : '65535.65535 ': 11 + 1 */ -#define ASN_STR_LEN (10 + 1) +#define ASN_STR_LEN (11 + 1) str_size = MAX(assegment_count_asns(seg, 0) * ASN_STR_LEN + 2 + 1, ASPATH_STR_DEFAULT_LEN); str_buf = XMALLOC(MTYPE_AS_STR, str_size); @@ -584,7 +590,7 @@ static void aspath_make_str_count(struct aspath *as, bool make_json) /* We might need to increase str_buf, particularly if path has * differing segments types, our initial guesstimate above will - * have been wrong. Need 10 chars for ASN, a separator each and + * have been wrong. Need 11 chars for ASN, a separator each and * potentially two segment delimiters, plus a space between each * segment and trailing zero. * @@ -610,12 +616,11 @@ static void aspath_make_str_count(struct aspath *as, bool make_json) /* write out the ASNs, with their separators, bar the last one*/ for (i = 0; i < seg->length; i++) { if (make_json) - json_object_array_add( - jseg_list, - json_object_new_int64(seg->as[i])); - - len += snprintf(str_buf + len, str_size - len, "%u", - seg->as[i]); + asn_asn2json_array(jseg_list, seg->as[i], + as->asnotation); + len += snprintfrr(str_buf + len, str_size - len, + ASN_FORMAT(as->asnotation), + &seg->as[i]); if (i < (seg->length - 1)) len += snprintf(str_buf + len, str_size - len, @@ -706,6 +711,7 @@ struct aspath *aspath_dup(struct aspath *aspath) new->str = XMALLOC(MTYPE_AS_STR, buflen); new->str_len = aspath->str_len; + new->asnotation = aspath->asnotation; /* copy the string data */ if (aspath->str_len > 0) @@ -733,6 +739,7 @@ static void *aspath_hash_alloc(void *arg) new->str = aspath->str; new->str_len = aspath->str_len; new->json = aspath->json; + new->asnotation = aspath->asnotation; return new; } @@ -840,7 +847,8 @@ static int assegments_parse(struct stream *s, size_t length, On error NULL is returned. */ -struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit) +struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit, + enum asnotation_mode asnotation) { struct aspath as; struct aspath *find; @@ -855,6 +863,7 @@ struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit) return NULL; memset(&as, 0, sizeof(as)); + as.asnotation = asnotation; if (assegments_parse(s, length, &as.segments, use32bit) < 0) return NULL; @@ -1072,7 +1081,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2) seg = assegment_append_asns(seg, seg1->as, match); if (!aspath) { - aspath = aspath_new(); + aspath = aspath_new(as1->asnotation); aspath->segments = seg; } else prevseg->next = seg; @@ -1092,7 +1101,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2) } if (!aspath) - aspath = aspath_new(); + aspath = aspath_new(as1->asnotation); /* Make as-set using rest of all information. */ from = match; @@ -1536,7 +1545,7 @@ struct aspath *aspath_filter_exclude(struct aspath *source, struct assegment *srcseg, *exclseg, *lastseg; struct aspath *newpath; - newpath = aspath_new(); + newpath = aspath_new(source->asnotation); lastseg = NULL; for (srcseg = source->segments; srcseg; srcseg = srcseg->next) { @@ -1766,7 +1775,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath, newseg = assegment_append_asns(newseg, seg->as, cpasns); if (!newpath) { - newpath = aspath_new(); + newpath = aspath_new(aspath->asnotation); newpath->segments = newseg; } else prevseg->next = newseg; @@ -1895,16 +1904,16 @@ static void aspath_segment_add(struct aspath *as, int type) as->segments = new; } -struct aspath *aspath_empty(void) +struct aspath *aspath_empty(enum asnotation_mode asnotation) { - return aspath_parse(NULL, 0, 1); /* 32Bit ;-) */ + return aspath_parse(NULL, 0, 1, asnotation); /* 32Bit ;-) */ } struct aspath *aspath_empty_get(void) { struct aspath *aspath; - aspath = aspath_new(); + aspath = aspath_new(bgp_get_asnotation(NULL)); aspath_make_str_count(aspath, false); return aspath; } @@ -1988,7 +1997,8 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token, return p; } -struct aspath *aspath_str2aspath(const char *str) +struct aspath *aspath_str2aspath(const char *str, + enum asnotation_mode asnotation) { enum as_token token = as_token_unknown; unsigned short as_type; @@ -1996,7 +2006,7 @@ struct aspath *aspath_str2aspath(const char *str) struct aspath *aspath; int needtype; - aspath = aspath_new(); + aspath = aspath_new(asnotation); /* We start default type as AS_SEQUENCE. */ as_type = AS_SEQUENCE; @@ -2070,6 +2080,10 @@ bool aspath_cmp(const void *arg1, const void *arg2) const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; const struct assegment *seg2 = ((const struct aspath *)arg2)->segments; + if (((const struct aspath *)arg1)->asnotation != + ((const struct aspath *)arg2)->asnotation) + return false; + while (seg1 || seg2) { int i; if ((!seg1 && seg2) || (seg1 && !seg2)) diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index a814d73dd..e0cadef5e 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -72,6 +72,9 @@ struct aspath { and AS path regular expression match. */ char *str; unsigned short str_len; + + /* AS notation used by string expression of AS path */ + enum asnotation_mode asnotation; }; #define ASPATH_STR_DEFAULT_LEN 32 @@ -80,7 +83,9 @@ struct aspath { extern void aspath_init(void); extern void aspath_finish(void); extern struct aspath *aspath_parse(struct stream *s, size_t length, - int use32bit); + int use32bit, + enum asnotation_mode asnotation); + extern struct aspath *aspath_dup(struct aspath *aspath); extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2); extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2); @@ -96,9 +101,10 @@ extern bool aspath_cmp_left(const struct aspath *aspath1, extern bool aspath_cmp_left_confed(const struct aspath *as1, const struct aspath *as2); extern struct aspath *aspath_delete_confed_seq(struct aspath *aspath); -extern struct aspath *aspath_empty(void); +extern struct aspath *aspath_empty(enum asnotation_mode asnotation); extern struct aspath *aspath_empty_get(void); -extern struct aspath *aspath_str2aspath(const char *str); +extern struct aspath *aspath_str2aspath(const char *str, + enum asnotation_mode asnotation); extern void aspath_str_update(struct aspath *as, bool make_json); extern void aspath_free(struct aspath *aspath); extern struct aspath *aspath_intern(struct aspath *aspath); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 392b55880..eb1b208d9 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1069,7 +1069,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp, attr->origin = origin; attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN); - attr->aspath = aspath_empty(); + attr->aspath = aspath_empty(bgp->asnotation); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); attr->weight = BGP_ATTR_DEFAULT_WEIGHT; attr->tag = 0; @@ -1107,7 +1107,7 @@ struct attr *bgp_attr_aggregate_intern( if (aspath) attr.aspath = aspath_intern(aspath); else - attr.aspath = aspath_empty(); + attr.aspath = aspath_empty(bgp->asnotation); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); /* Next hop attribute. */ @@ -1605,15 +1605,19 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; struct peer *const peer = args->peer; const bgp_size_t length = args->length; + enum asnotation_mode asnotation; + asnotation = bgp_get_asnotation( + args->peer && args->peer->bgp ? args->peer->bgp : NULL); /* * peer with AS4 => will get 4Byte ASnums * otherwise, will get 16 Bit */ - attr->aspath = aspath_parse( - peer->curr, length, - CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) - && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV)); + attr->aspath = + aspath_parse(peer->curr, length, + CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && + CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV), + asnotation); /* In case of IBGP, length will be zero. */ if (!attr->aspath) { @@ -1705,8 +1709,11 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args, struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; + enum asnotation_mode asnotation; - *as4_path = aspath_parse(peer->curr, length, 1); + asnotation = bgp_get_asnotation(peer->bgp); + + *as4_path = aspath_parse(peer->curr, length, 1, asnotation); /* In case of IBGP, length will be zero. */ if (!*as4_path) { diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index aa14d99f1..af944593b 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -101,7 +101,8 @@ static void attr_parse(struct stream *s, uint16_t len) case BGP_ATTR_AS_PATH: { struct aspath *aspath; - aspath = aspath_parse(s, length, 1); + aspath = aspath_parse(s, length, 1, + bgp_get_asnotation(NULL)); printf("ASPATH: %s\n", aspath->str); aspath_free(aspath); } break; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 23e6195d3..32de9e302 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7246,7 +7246,7 @@ static bool aggr_suppress_map_test(struct bgp *bgp, return false; /* Call route map matching and return result. */ - attr.aspath = aspath_empty(); + attr.aspath = aspath_empty(bgp->asnotation); rmap_path.peer = bgp->peer_self; rmap_path.attr = &attr; @@ -7340,9 +7340,12 @@ static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin, struct lcommunity *lcomm) { static struct aspath *ae = NULL; + enum asnotation_mode asnotation; + + asnotation = bgp_get_asnotation(NULL); if (!ae) - ae = aspath_empty(); + ae = aspath_empty(asnotation); if (!pi) return false; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index c9da71c6d..87e532efb 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -228,7 +228,7 @@ static void *route_aspath_compile(const char *arg) { struct aspath *aspath; - aspath = aspath_str2aspath(arg); + aspath = aspath_str2aspath(arg, bgp_get_asnotation(NULL)); if (!aspath) return NULL; return aspath; diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c index bf3e612bf..a6004fc72 100644 --- a/bgpd/bgp_script.c +++ b/bgpd/bgp_script.c @@ -163,7 +163,8 @@ void lua_decode_attr(lua_State *L, int idx, struct attr *attr) attr->nh_ifindex = lua_tointeger(L, -1); lua_pop(L, 1); lua_getfield(L, idx, "aspath"); - attr->aspath = aspath_str2aspath(lua_tostring(L, -1)); + attr->aspath = aspath_str2aspath(lua_tostring(L, -1), + bgp_get_asnotation(NULL)); lua_pop(L, 1); lua_getfield(L, idx, "localpref"); attr->local_pref = lua_tointeger(L, -1); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 565cbccee..6b8c17da8 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2060,6 +2060,13 @@ const char *bgp_get_name_by_role(uint8_t role) return "unknown"; } +enum asnotation_mode bgp_get_asnotation(struct bgp *bgp) +{ + if (!bgp) + return ASNOTATION_PLAIN; + return bgp->asnotation; +} + static void peer_group2peer_config_copy_af(struct peer_group *group, struct peer *peer, afi_t afi, safi_t safi) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 634c4cf1d..aa53e7c30 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2350,6 +2350,7 @@ extern void peer_tx_shutdown_message_unset(struct peer *); extern void bgp_route_map_update_timer(struct thread *thread); extern const char *bgp_get_name_by_role(uint8_t role); +extern enum asnotation_mode bgp_get_asnotation(struct bgp *bgp); extern void bgp_route_map_terminate(void); @@ -118,6 +118,15 @@ static bool asn_str2asn_internal(const char *asstring, as_t *asn, return ret; } +static void asn_asn2asdot(as_t asn, char *asstring, size_t len) +{ + uint16_t low, high; + + high = (asn >> 16) & 0xffff; + low = asn & 0xffff; + snprintf(asstring, len, "%hu.%hu", high, low); +} + bool asn_str2asn(const char *asstring, as_t *asn) { return asn_str2asn_internal(asstring, asn, NULL, NULL, NULL); @@ -173,3 +182,58 @@ const char *asn_mode2str(enum asnotation_mode asnotation) return lookup_msg(asnotation_mode_msg, asnotation, "Unrecognized AS notation mode"); } + +void asn_asn2json_array(json_object *jseg_list, as_t asn, + enum asnotation_mode asnotation) +{ + static char as_str[ASN_STRING_MAX_SIZE]; + + if ((asnotation == ASNOTATION_PLAIN) || + ((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX)) + json_object_array_add(jseg_list, + json_object_new_int64(asn)); + else { + asn_asn2asdot(asn, as_str, sizeof(as_str)); + json_array_string_add(jseg_list, as_str); + } +} + +static ssize_t printfrr_asnotation(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr, + enum asnotation_mode asnotation) +{ + /* for alignemnt up to 33 chars - %33pASD for instance - */ + char as_str[ASN_STRING_MAX_SIZE*3]; + const as_t *asn; + + if (!ptr) + return bputs(buf, "(null)"); + asn = ptr; + if ((asnotation == ASNOTATION_PLAIN) || + ((asnotation == ASNOTATION_DOT) && *asn < UINT16_MAX)) + snprintf(as_str, sizeof(as_str), "%u", *asn); + else + asn_asn2asdot(*asn, as_str, sizeof(as_str)); + return bputs(buf, as_str); +} + +printfrr_ext_autoreg_p("ASP", printfrr_asplain); +static ssize_t printfrr_asplain(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_asnotation(buf, ea, ptr, ASNOTATION_PLAIN); +} + +printfrr_ext_autoreg_p("ASD", printfrr_asdot); +static ssize_t printfrr_asdot(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOT); +} + +printfrr_ext_autoreg_p("ASE", printfrr_asdotplus); +static ssize_t printfrr_asdotplus(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS); +} @@ -24,6 +24,7 @@ #include "zebra.h" #include "command_match.h" +#include "json.h" #ifdef __cplusplus extern "C" { @@ -48,6 +49,20 @@ extern enum match_type asn_str2asn_match(const char *str); extern bool asn_str2asn_notation(const char *asstring, as_t *asn, enum asnotation_mode *asnotation); extern const char *asn_mode2str(enum asnotation_mode asnotation); +void asn_asn2json_array(json_object *jseg_list, as_t asn, + enum asnotation_mode asnotation); +/* display AS in appropriate format */ +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pASP" (as_t *) +#pragma FRR printfrr_ext "%pASD" (as_t *) +#pragma FRR printfrr_ext "%pASE" (as_t *) +#endif + +#define ASN_FORMAT(mode) \ + ((mode == ASNOTATION_DOT) ? "%pASD" : \ + ((mode == ASNOTATION_DOTPLUS) ? "%pASE" : \ + "%pASP")) + /* for test */ extern void asn_relax_as_zero(bool relax); diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 0f6d5b023..8c173ea66 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -880,7 +880,7 @@ static struct aspath *make_aspath(const uint8_t *data, size_t len, int use32bit) s = stream_new(len); stream_put(s, data, len); } - as = aspath_parse(s, len, use32bit); + as = aspath_parse(s, len, use32bit, ASNOTATION_PLAIN); if (s) stream_free(s); @@ -925,7 +925,7 @@ static int validate(struct aspath *as, const struct test_spec *sp) as4 = make_aspath(STREAM_DATA(s), bytes4, 1); asn_relax_as_zero(true); - asstr = aspath_str2aspath(sp->shouldbe); + asstr = aspath_str2aspath(sp->shouldbe, ASNOTATION_PLAIN); asn_relax_as_zero(false); asconfeddel = aspath_delete_confed_seq(aspath_dup(asinout)); @@ -1103,7 +1103,7 @@ static void empty_prepend_test(struct test_segment *t) printf("empty prepend %s: %s\n", t->name, t->desc); asp1 = make_aspath(t->asdata, t->len, 0); - asp2 = aspath_empty(); + asp2 = aspath_empty(ASNOTATION_PLAIN); ascratch = aspath_dup(asp2); aspath_unintern(&asp2); diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 59d08ae82..f9755512a 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -25,6 +25,7 @@ #include "lib/memory.h" #include "lib/prefix.h" #include "lib/nexthop.h" +#include "lib/asn.h" static int errors; @@ -158,6 +159,7 @@ int main(int argc, char **argv) struct in_addr ip; char *p; char buf[256]; + as_t asn; printcmp("%d %u %d %u", 123, 123, -456, -456); printcmp("%lld %llu %lld %llu", 123LL, 123LL, -456LL, -456LL); @@ -405,6 +407,13 @@ int main(int argc, char **argv) printchk("-00:09", "%pTSIm", &ts); printchk("--:--", "%pTVImx", &tv); printchk("--:--", "%pTTImx", &tt); + /* ASN checks */ + asn = 65536; + printchk("1.0", "%pASD", &asn); + asn = 65400; + printchk("65400", "%pASP", &asn); + printchk("0.65400", "%pASE", &asn); + printchk("65400", "%pASD", &asn); return !!errors; } |