From fdf16eb65872b3bee02fb9e25c80ea32cf59f8e9 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 3 Jul 2011 19:43:30 +0200 Subject: Prints full community lists during 'show route all'. --- filter/filter.c | 2 +- nest/a-set.c | 50 ++++++++++++++++++-------- nest/attrs.h | 2 +- nest/cli.c | 2 +- nest/cli.h | 3 ++ nest/route.h | 2 -- nest/rt-attr.c | 102 ++++++++++++++++++++++++++++++++---------------------- proto/bgp/attrs.c | 12 ++----- 8 files changed, 105 insertions(+), 70 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 913bd08..0f44a6e 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -401,7 +401,7 @@ val_print(struct f_val v) case T_SET: tree_print(v.val.t); return; case T_ENUM: logn("(enum %x)%d", v.type, v.val.i); return; case T_PATH: as_path_format(v.val.ad, buf2, 1000); logn("(path %s)", buf2); return; - case T_CLIST: int_set_format(v.val.ad, 1, buf2, 1000); logn("(clist %s)", buf2); return; + case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); logn("(clist %s)", buf2); return; case T_PATH_MASK: pm_format(v.val.path_mask, buf2, 1000); logn("(pathmask%s)", buf2); return; default: logn( "[unknown type %x]", v.type ); return; } diff --git a/nest/a-set.c b/nest/a-set.c index f41b163..3cbd635 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -13,33 +13,53 @@ #include "lib/resource.h" #include "lib/string.h" -void -int_set_format(struct adata *set, int way, byte *buf, unsigned int size) +/** + * int_set_format - format an &set for printing + * @set: set attribute to be formatted + * @way: style of format (0 for router ID list, 1 for community list) + * @from: starting position in set + * @buf: destination buffer + * @size: size of buffer + * + * This function takes a set attribute and formats it. @way specifies + * the style of format (router ID / community). @from argument can be + * used to specify the first printed value for the purpose of printing + * untruncated sets even with smaller buffers. If the output fits in + * the buffer, 0 is returned, otherwise the position of the first not + * printed item is returned. This value can be used as @from argument + * in subsequent calls. If truncated output suffices, -1 can be + * instead used as @from, in that case " ..." is eventually added at + * the buffer to indicate truncation. + */ +int +int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int size) { u32 *z = (u32 *) set->data; - int l = set->length / 4; - int sp = 1; - byte *end = buf + size - 16; + byte *end = buf + size - 24; + int to = set->length / 4; + int i; - while (l--) + for (i = MAX(from, 0); i < to; i++) { - if (!sp) - *buf++ = ' '; if (buf > end) { - strcpy(buf, "..."); - return; + if (from < 0) + strcpy(buf, " ..."); + else + *buf = 0; + return i; } + if (i > from) + *buf++ = ' '; + if (way) - buf += bsprintf(buf, "(%d,%d)", *z >> 16, *z & 0xffff); + buf += bsprintf(buf, "(%d,%d)", z[i] >> 16, z[i] & 0xffff); else - buf += bsprintf(buf, "%R", *z); - - z++; - sp = 0; + buf += bsprintf(buf, "%R", z[i]); } *buf = 0; + return 0; } int diff --git a/nest/attrs.h b/nest/attrs.h index 16fb35a..6ce5755 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -50,7 +50,7 @@ int as_path_match(struct adata *path, struct f_path_mask *mask); /* a-set.c */ -void int_set_format(struct adata *set, int way, byte *buf, unsigned int size); +int int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int size); struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val); int int_set_contains(struct adata *list, u32 val); struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val); diff --git a/nest/cli.c b/nest/cli.c index 4d2b8fd..a61518b 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -120,7 +120,7 @@ void cli_printf(cli *c, int code, char *msg, ...) { va_list args; - byte buf[1024]; + byte buf[CLI_LINE_SIZE]; int cd = code; int size, cnt; diff --git a/nest/cli.h b/nest/cli.h index 57414a2..ea64680 100644 --- a/nest/cli.h +++ b/nest/cli.h @@ -16,6 +16,9 @@ #define CLI_TX_BUF_SIZE 4096 #define CLI_MAX_ASYNC_QUEUE 4096 +#define CLI_MSG_SIZE 500 +#define CLI_LINE_SIZE 512 + struct cli_out { struct cli_out *next; byte *wpos, *outpos, *end; diff --git a/nest/route.h b/nest/route.h index 236882e..c77fe41 100644 --- a/nest/route.h +++ b/nest/route.h @@ -394,8 +394,6 @@ unsigned ea_scan(ea_list *); /* How many bytes do we need for merged ea_list */ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffer */ int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */ unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */ -void ea_format(eattr *e, byte *buf); -#define EA_FORMAT_BUF_SIZE 256 ea_list *ea_append(ea_list *to, ea_list *what); int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 5a7dd09..486a543 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -430,81 +430,105 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED) return GA_UNKNOWN; } +static inline void +opaque_format(struct adata *ad, byte *buf, unsigned int size) +{ + byte *bound = buf + size - 10; + int i; + + for(i = 0; i < ad->length; i++) + { + if (buf > bound) + { + strcpy(buf, " ..."); + return; + } + if (i) + *buf++ = ' '; + + buf += bsprintf(buf, "%02x", ad->data[i]); + } + + *buf = 0; + return; +} + +static inline void +ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, byte *end) +{ + int i = int_set_format(ad, way, 0, pos, end - pos); + cli_printf(c, -1012, "%s", buf); + while (i) + { + i = int_set_format(ad, way, i, buf, end - buf - 1); + cli_printf(c, -1012, "\t%s", buf); + } +} + /** - * ea_format - format an &eattr for printing - * @e: attribute to be formatted - * @buf: destination buffer of size %EA_FORMAT_BUF_SIZE + * ea_show - print an &eattr to CLI + * @c: destination CLI + * @e: attribute to be printed * - * This function takes an extended attribute represented by its - * &eattr structure and formats it nicely for printing according - * to the type information. + * This function takes an extended attribute represented by its &eattr + * structure and prints it to the CLI according to the type information. * * If the protocol defining the attribute provides its own * get_attr() hook, it's consulted first. */ void -ea_format(eattr *e, byte *buf) +ea_show(struct cli *c, eattr *e) { struct protocol *p; int status = GA_UNKNOWN; - unsigned int i; struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr; - byte *end = buf + EA_FORMAT_BUF_SIZE - 1; + byte buf[CLI_MSG_SIZE]; + byte *pos = buf, *end = buf + sizeof(buf); if (p = attr_class_to_protocol[EA_PROTO(e->id)]) { - buf += bsprintf(buf, "%s.", p->name); + pos += bsprintf(pos, "%s.", p->name); if (p->get_attr) - status = p->get_attr(e, buf, end - buf); - buf += strlen(buf); + status = p->get_attr(e, pos, end - pos); + pos += strlen(pos); } else if (EA_PROTO(e->id)) - buf += bsprintf(buf, "%02x.", EA_PROTO(e->id)); + pos += bsprintf(pos, "%02x.", EA_PROTO(e->id)); else - status = get_generic_attr(e, &buf, end - buf); + status = get_generic_attr(e, &pos, end - pos); if (status < GA_NAME) - buf += bsprintf(buf, "%02x", EA_ID(e->id)); + pos += bsprintf(pos, "%02x", EA_ID(e->id)); if (status < GA_FULL) { - *buf++ = ':'; - *buf++ = ' '; + *pos++ = ':'; + *pos++ = ' '; switch (e->type & EAF_TYPE_MASK) { case EAF_TYPE_INT: - bsprintf(buf, "%u", e->u.data); + bsprintf(pos, "%u", e->u.data); break; case EAF_TYPE_OPAQUE: - *buf = 0; - for(i=0; ilength; i++) - { - if (buf > end - 8) - { - strcpy(buf, " ..."); - break; - } - if (i) - *buf++ = ' '; - buf += bsprintf(buf, "%02x", ad->data[i]); - } + opaque_format(ad, pos, end - pos); break; case EAF_TYPE_IP_ADDRESS: - bsprintf(buf, "%I", *(ip_addr *) ad->data); + bsprintf(pos, "%I", *(ip_addr *) ad->data); break; case EAF_TYPE_ROUTER_ID: - bsprintf(buf, "%R", e->u.data); + bsprintf(pos, "%R", e->u.data); break; case EAF_TYPE_AS_PATH: - as_path_format(ad, buf, end - buf); + as_path_format(ad, pos, end - pos); break; case EAF_TYPE_INT_SET: - int_set_format(ad, 1, buf, end - buf); - break; + ea_show_int_set(c, ad, 1, pos, buf, end); + return; case EAF_TYPE_UNDEF: default: - bsprintf(buf, "", e->type); + bsprintf(pos, "", e->type); } } + cli_printf(c, -1012, "%s", buf); } /** @@ -834,17 +858,13 @@ rta_show(struct cli *c, rta *a, ea_list *eal) "RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" }; static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" }; int i; - byte buf[EA_FORMAT_BUF_SIZE]; cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope)); if (!eal) eal = a->eattrs; for(; eal; eal=eal->next) for(i=0; icount; i++) - { - ea_format(&eal->attrs[i], buf); - cli_printf(c, -1012, "\t%s", buf); - } + ea_show(c, &eal->attrs[i]); } /** diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 95eee9a..83ca249 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -255,9 +255,10 @@ bgp_check_cluster_list(struct bgp_proto *p UNUSED, byte *a UNUSED, int len) } static void -bgp_format_cluster_list(eattr *a, byte *buf, int buflen UNUSED) +bgp_format_cluster_list(eattr *a, byte *buf, int buflen) { - int_set_format(a->u.ptr, 0, buf, buflen); + /* Truncates cluster lists larger than buflen, probably not a problem */ + int_set_format(a->u.ptr, 0, -1, buf, buflen); } static int @@ -735,13 +736,6 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate) for(i=0; iattrs[i]; -#ifdef LOCAL_DEBUG - { - byte buf[EA_FORMAT_BUF_SIZE]; - ea_format(a, buf); - DBG("\t%s\n", buf); - } -#endif if (EA_PROTO(a->id) != EAP_BGP) continue; code = EA_ID(a->id); -- cgit v1.2.3