Prints full community lists during 'show route all'.
This commit is contained in:
parent
6370d6f61b
commit
fdf16eb658
8 changed files with 106 additions and 71 deletions
|
@ -401,7 +401,7 @@ val_print(struct f_val v)
|
||||||
case T_SET: tree_print(v.val.t); return;
|
case T_SET: tree_print(v.val.t); return;
|
||||||
case T_ENUM: logn("(enum %x)%d", v.type, v.val.i); 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_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;
|
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;
|
default: logn( "[unknown type %x]", v.type ); return;
|
||||||
}
|
}
|
||||||
|
|
48
nest/a-set.c
48
nest/a-set.c
|
@ -13,33 +13,53 @@
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/string.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;
|
u32 *z = (u32 *) set->data;
|
||||||
int l = set->length / 4;
|
byte *end = buf + size - 24;
|
||||||
int sp = 1;
|
int to = set->length / 4;
|
||||||
byte *end = buf + size - 16;
|
int i;
|
||||||
|
|
||||||
while (l--)
|
for (i = MAX(from, 0); i < to; i++)
|
||||||
{
|
{
|
||||||
if (!sp)
|
|
||||||
*buf++ = ' ';
|
|
||||||
if (buf > end)
|
if (buf > end)
|
||||||
{
|
{
|
||||||
|
if (from < 0)
|
||||||
strcpy(buf, " ...");
|
strcpy(buf, " ...");
|
||||||
return;
|
else
|
||||||
|
*buf = 0;
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i > from)
|
||||||
|
*buf++ = ' ';
|
||||||
|
|
||||||
if (way)
|
if (way)
|
||||||
buf += bsprintf(buf, "(%d,%d)", *z >> 16, *z & 0xffff);
|
buf += bsprintf(buf, "(%d,%d)", z[i] >> 16, z[i] & 0xffff);
|
||||||
else
|
else
|
||||||
buf += bsprintf(buf, "%R", *z);
|
buf += bsprintf(buf, "%R", z[i]);
|
||||||
|
|
||||||
z++;
|
|
||||||
sp = 0;
|
|
||||||
}
|
}
|
||||||
*buf = 0;
|
*buf = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -50,7 +50,7 @@ int as_path_match(struct adata *path, struct f_path_mask *mask);
|
||||||
|
|
||||||
/* a-set.c */
|
/* 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);
|
struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
|
||||||
int int_set_contains(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);
|
struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
|
||||||
|
|
|
@ -120,7 +120,7 @@ void
|
||||||
cli_printf(cli *c, int code, char *msg, ...)
|
cli_printf(cli *c, int code, char *msg, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
byte buf[1024];
|
byte buf[CLI_LINE_SIZE];
|
||||||
int cd = code;
|
int cd = code;
|
||||||
int size, cnt;
|
int size, cnt;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#define CLI_TX_BUF_SIZE 4096
|
#define CLI_TX_BUF_SIZE 4096
|
||||||
#define CLI_MAX_ASYNC_QUEUE 4096
|
#define CLI_MAX_ASYNC_QUEUE 4096
|
||||||
|
|
||||||
|
#define CLI_MSG_SIZE 500
|
||||||
|
#define CLI_LINE_SIZE 512
|
||||||
|
|
||||||
struct cli_out {
|
struct cli_out {
|
||||||
struct cli_out *next;
|
struct cli_out *next;
|
||||||
byte *wpos, *outpos, *end;
|
byte *wpos, *outpos, *end;
|
||||||
|
|
|
@ -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 */
|
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 */
|
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 */
|
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);
|
ea_list *ea_append(ea_list *to, ea_list *what);
|
||||||
|
|
||||||
int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */
|
int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */
|
||||||
|
|
102
nest/rt-attr.c
102
nest/rt-attr.c
|
@ -430,81 +430,105 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
|
||||||
return GA_UNKNOWN;
|
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
|
* ea_show - print an &eattr to CLI
|
||||||
* @e: attribute to be formatted
|
* @c: destination CLI
|
||||||
* @buf: destination buffer of size %EA_FORMAT_BUF_SIZE
|
* @e: attribute to be printed
|
||||||
*
|
*
|
||||||
* This function takes an extended attribute represented by its
|
* This function takes an extended attribute represented by its &eattr
|
||||||
* &eattr structure and formats it nicely for printing according
|
* structure and prints it to the CLI according to the type information.
|
||||||
* to the type information.
|
|
||||||
*
|
*
|
||||||
* If the protocol defining the attribute provides its own
|
* If the protocol defining the attribute provides its own
|
||||||
* get_attr() hook, it's consulted first.
|
* get_attr() hook, it's consulted first.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ea_format(eattr *e, byte *buf)
|
ea_show(struct cli *c, eattr *e)
|
||||||
{
|
{
|
||||||
struct protocol *p;
|
struct protocol *p;
|
||||||
int status = GA_UNKNOWN;
|
int status = GA_UNKNOWN;
|
||||||
unsigned int i;
|
|
||||||
struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
|
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)])
|
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)
|
if (p->get_attr)
|
||||||
status = p->get_attr(e, buf, end - buf);
|
status = p->get_attr(e, pos, end - pos);
|
||||||
buf += strlen(buf);
|
pos += strlen(pos);
|
||||||
}
|
}
|
||||||
else if (EA_PROTO(e->id))
|
else if (EA_PROTO(e->id))
|
||||||
buf += bsprintf(buf, "%02x.", EA_PROTO(e->id));
|
pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
|
||||||
else
|
else
|
||||||
status = get_generic_attr(e, &buf, end - buf);
|
status = get_generic_attr(e, &pos, end - pos);
|
||||||
|
|
||||||
if (status < GA_NAME)
|
if (status < GA_NAME)
|
||||||
buf += bsprintf(buf, "%02x", EA_ID(e->id));
|
pos += bsprintf(pos, "%02x", EA_ID(e->id));
|
||||||
if (status < GA_FULL)
|
if (status < GA_FULL)
|
||||||
{
|
{
|
||||||
*buf++ = ':';
|
*pos++ = ':';
|
||||||
*buf++ = ' ';
|
*pos++ = ' ';
|
||||||
switch (e->type & EAF_TYPE_MASK)
|
switch (e->type & EAF_TYPE_MASK)
|
||||||
{
|
{
|
||||||
case EAF_TYPE_INT:
|
case EAF_TYPE_INT:
|
||||||
bsprintf(buf, "%u", e->u.data);
|
bsprintf(pos, "%u", e->u.data);
|
||||||
break;
|
break;
|
||||||
case EAF_TYPE_OPAQUE:
|
case EAF_TYPE_OPAQUE:
|
||||||
*buf = 0;
|
opaque_format(ad, pos, end - pos);
|
||||||
for(i=0; i<ad->length; i++)
|
|
||||||
{
|
|
||||||
if (buf > end - 8)
|
|
||||||
{
|
|
||||||
strcpy(buf, " ...");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i)
|
|
||||||
*buf++ = ' ';
|
|
||||||
buf += bsprintf(buf, "%02x", ad->data[i]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case EAF_TYPE_IP_ADDRESS:
|
case EAF_TYPE_IP_ADDRESS:
|
||||||
bsprintf(buf, "%I", *(ip_addr *) ad->data);
|
bsprintf(pos, "%I", *(ip_addr *) ad->data);
|
||||||
break;
|
break;
|
||||||
case EAF_TYPE_ROUTER_ID:
|
case EAF_TYPE_ROUTER_ID:
|
||||||
bsprintf(buf, "%R", e->u.data);
|
bsprintf(pos, "%R", e->u.data);
|
||||||
break;
|
break;
|
||||||
case EAF_TYPE_AS_PATH:
|
case EAF_TYPE_AS_PATH:
|
||||||
as_path_format(ad, buf, end - buf);
|
as_path_format(ad, pos, end - pos);
|
||||||
break;
|
break;
|
||||||
case EAF_TYPE_INT_SET:
|
case EAF_TYPE_INT_SET:
|
||||||
int_set_format(ad, 1, buf, end - buf);
|
ea_show_int_set(c, ad, 1, pos, buf, end);
|
||||||
break;
|
return;
|
||||||
case EAF_TYPE_UNDEF:
|
case EAF_TYPE_UNDEF:
|
||||||
default:
|
default:
|
||||||
bsprintf(buf, "<type %02x>", e->type);
|
bsprintf(pos, "<type %02x>", 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" };
|
"RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" };
|
||||||
static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
|
static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
|
||||||
int i;
|
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));
|
cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope));
|
||||||
if (!eal)
|
if (!eal)
|
||||||
eal = a->eattrs;
|
eal = a->eattrs;
|
||||||
for(; eal; eal=eal->next)
|
for(; eal; eal=eal->next)
|
||||||
for(i=0; i<eal->count; i++)
|
for(i=0; i<eal->count; i++)
|
||||||
{
|
ea_show(c, &eal->attrs[i]);
|
||||||
ea_format(&eal->attrs[i], buf);
|
|
||||||
cli_printf(c, -1012, "\t%s", buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -255,9 +255,10 @@ bgp_check_cluster_list(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
static int
|
||||||
|
@ -735,13 +736,6 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
|
||||||
for(i=0; i<cnt; i++)
|
for(i=0; i<cnt; i++)
|
||||||
{
|
{
|
||||||
a = &new->attrs[i];
|
a = &new->attrs[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)
|
if (EA_PROTO(a->id) != EAP_BGP)
|
||||||
continue;
|
continue;
|
||||||
code = EA_ID(a->id);
|
code = EA_ID(a->id);
|
||||||
|
|
Loading…
Reference in a new issue