#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rde.h"
#include "log.h"
#include "rde_community_test.h"
struct rde_memstats rdemem;
struct rde_community comm;
static void
dump(uint8_t *b, size_t len)
{
size_t l;
printf("\n\t{\n\t\t.data = \"");
for (l = 0; l < len; l++) {
printf("\\x%02x", b[l]);
if (l % 12 == 0 && l != 0)
printf("\"\n\t\t \"");
}
printf("\",\n\t\t.size = %zu\n\t},\n", len);
}
static int
test_parsing(size_t num, struct ibuf *in, struct ibuf *out)
{
struct ibuf *buf, abuf;
uint8_t flags, type, attr[256];
size_t skip;
uint16_t attr_len;
int r;
communities_clean(&comm);
do {
if (ibuf_get_n8(in, &flags) == -1 ||
ibuf_get_n8(in, &type) == -1)
goto bad;
if (flags & ATTR_EXTLEN) {
if (ibuf_get_n16(in, &attr_len) == -1)
goto bad;
} else {
uint8_t tmp;
if (ibuf_get_n8(in, &tmp) == -1)
goto bad;
attr_len = tmp;
}
if (ibuf_get_ibuf(in, attr_len, &abuf) == -1) {
bad:
printf("Test %zu: attribute parse failure\n", num);
return -1;
}
switch (type) {
case ATTR_COMMUNITIES:
r = community_add(&comm, flags, &abuf);
break;
case ATTR_EXT_COMMUNITIES:
r = community_ext_add(&comm, flags, 0, &abuf);
break;
case ATTR_LARGE_COMMUNITIES:
r = community_large_add(&comm, flags, &abuf);
break;
}
if (r == -1) {
printf("Test %zu: community_add failed\n", num);
return -1;
}
} while (ibuf_size(in) > 0);
if ((buf = ibuf_dynamic(0, 4096)) == NULL) {
printf("Test %zu: ibuf_dynamic failed\n", num);
return -1;
}
if (community_writebuf(&comm, ATTR_COMMUNITIES, 1, buf) == -1) {
printf("Test %zu: community_writebuf failed\n", num);
return -1;
}
if (community_writebuf(&comm, ATTR_EXT_COMMUNITIES, 1, buf) == -1) {
printf("Test %zu: community_writebuf failed\n", num);
return -1;
}
if (community_writebuf(&comm, ATTR_LARGE_COMMUNITIES, 1, buf) == -1) {
printf("Test %zu: community_writebuf failed\n", num);
return -1;
}
if (ibuf_size(buf) != ibuf_size(out)) {
printf("Test %zu: ibuf size value %zd != %zd:",
num, ibuf_size(buf), ibuf_size(out));
dump(ibuf_data(buf), ibuf_size(buf));
printf("expected: ");
dump(ibuf_data(out), ibuf_size(out));
return -1;
}
if (memcmp(ibuf_data(buf), ibuf_data(out), ibuf_size(out)) != 0) {
printf("Test %zu: unexpected encoding: ", num);
dump(ibuf_data(buf), ibuf_size(buf));
printf("expected: ");
dump(ibuf_data(out), ibuf_size(out));
return -1;
}
return 0;
}
static int
test_filter(size_t num, struct testfilter *f)
{
size_t l;
int r;
struct rde_peer *p = &peer;
communities_clean(&comm);
if (f->peer != NULL)
p = f->peer;
for (l = 0; f->in[l] != -1; l++) {
r = community_set(&comm, &filters[f->in[l]], p);
if (r != 1) {
printf("Test %zu: community_set %zu "
"unexpected return %d != 1\n",
num, l, r);
return -1;
}
}
if (f->match != -1) {
r = community_match(&comm, &filters[f->match], p);
if (r != f->mout) {
printf("Test %zu: community_match "
"unexpected return %d != %d\n", num, r, f->mout);
return -1;
}
}
if (f->delete != -1) {
community_delete(&comm, &filters[f->delete], p);
if (community_match(&comm, &filters[f->delete], p) != 0) {
printf("Test %zu: community_delete still around\n",
num);
return -1;
}
}
if (f->ncomm != 0) {
if (community_count(&comm, COMMUNITY_TYPE_BASIC) !=
f->ncomm - 1) {
printf("Test %zu: community_count unexpected "
"return %d != %d\n", num, r, f->ncomm - 1);
return -1;
}
}
if (f->next != 0) {
if (community_count(&comm, COMMUNITY_TYPE_EXT) !=
f->next - 1) {
printf("Test %zu: ext community_count unexpected "
"return %d != %d\n", num, r, f->next - 1);
return -1;
}
}
if (f->nlarge != 0) {
if (community_count(&comm, COMMUNITY_TYPE_LARGE) !=
f->nlarge - 1) {
printf("Test %zu: large community_count unexpected "
"return %d != %d\n", num, r, f->nlarge - 1);
return -1;
}
}
return 0;
}
int
main(int argc, char *argv[])
{
size_t t;
int error = 0;
for (t = 0; t < sizeof(vectors) / sizeof(*vectors); t++) {
struct ibuf in, out;
ibuf_from_buffer(&in, vectors[t].data, vectors[t].size);
if (vectors[t].expected == NULL)
ibuf_from_buffer(&out,
vectors[t].data, vectors[t].size);
else
ibuf_from_buffer(&out,
vectors[t].expected, vectors[t].expsize);
if (test_parsing(t, &in, &out) == -1)
error = 1;
}
for (t = 0; t < sizeof(testfilters) / sizeof(*testfilters); t++) {
if (test_filter(t, &testfilters[t]) == -1)
error = 1;
}
if (!error)
printf("OK\n");
return error;
}
__dead void
fatalx(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
verrx(2, emsg, ap);
}
__dead void
fatal(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
verr(2, emsg, ap);
}
void
log_warnx(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
vwarnx(emsg, ap);
va_end(ap);
}
int
attr_writebuf(struct ibuf *buf, uint8_t flags, uint8_t type, void *data,
uint16_t data_len)
{
u_char hdr[4];
flags &= ~ATTR_DEFMASK;
if (data_len > 255) {
flags |= ATTR_EXTLEN;
hdr[2] = (data_len >> 8) & 0xff;
hdr[3] = data_len & 0xff;
} else {
hdr[2] = data_len & 0xff;
}
hdr[0] = flags;
hdr[1] = type;
if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1)
return (-1);
if (data != NULL && ibuf_add(buf, data, data_len) == -1)
return (-1);
return (0);
}