1 /* $OpenBSD: rde_community_test.c,v 1.10 2024/01/24 14:51:56 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include <err.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include "rde.h" 24 #include "log.h" 25 26 #include "rde_community_test.h" 27 28 struct rde_memstats rdemem; 29 struct rde_community comm; 30 31 static void 32 dump(uint8_t *b, size_t len) 33 { 34 size_t l; 35 36 printf("\n\t{\n\t\t.data = \""); 37 for (l = 0; l < len; l++) { 38 printf("\\x%02x", b[l]); 39 if (l % 12 == 0 && l != 0) 40 printf("\"\n\t\t \""); 41 } 42 printf("\",\n\t\t.size = %zu\n\t},\n", len); 43 } 44 45 static int 46 test_parsing(size_t num, struct ibuf *in, struct ibuf *out) 47 { 48 struct ibuf *buf, abuf; 49 uint8_t flags, type, attr[256]; 50 size_t skip; 51 uint16_t attr_len; 52 int r; 53 54 communities_clean(&comm); 55 56 do { 57 if (ibuf_get_n8(in, &flags) == -1 || 58 ibuf_get_n8(in, &type) == -1) 59 goto bad; 60 if (flags & ATTR_EXTLEN) { 61 if (ibuf_get_n16(in, &attr_len) == -1) 62 goto bad; 63 } else { 64 uint8_t tmp; 65 if (ibuf_get_n8(in, &tmp) == -1) 66 goto bad; 67 attr_len = tmp; 68 } 69 if (ibuf_get_ibuf(in, attr_len, &abuf) == -1) { 70 bad: 71 printf("Test %zu: attribute parse failure\n", num); 72 return -1; 73 } 74 75 switch (type) { 76 case ATTR_COMMUNITIES: 77 r = community_add(&comm, flags, &abuf); 78 break; 79 case ATTR_EXT_COMMUNITIES: 80 r = community_ext_add(&comm, flags, 0, &abuf); 81 break; 82 case ATTR_LARGE_COMMUNITIES: 83 r = community_large_add(&comm, flags, &abuf); 84 break; 85 } 86 if (r == -1) { 87 printf("Test %zu: community_add failed\n", num); 88 return -1; 89 } 90 } while (ibuf_size(in) > 0); 91 92 if ((buf = ibuf_dynamic(0, 4096)) == NULL) { 93 printf("Test %zu: ibuf_dynamic failed\n", num); 94 return -1; 95 } 96 97 if (community_writebuf(&comm, ATTR_COMMUNITIES, 1, buf) == -1) { 98 printf("Test %zu: community_writebuf failed\n", num); 99 return -1; 100 } 101 if (community_writebuf(&comm, ATTR_EXT_COMMUNITIES, 1, buf) == -1) { 102 printf("Test %zu: community_writebuf failed\n", num); 103 return -1; 104 } 105 if (community_writebuf(&comm, ATTR_LARGE_COMMUNITIES, 1, buf) == -1) { 106 printf("Test %zu: community_writebuf failed\n", num); 107 return -1; 108 } 109 110 if (ibuf_size(buf) != ibuf_size(out)) { 111 printf("Test %zu: ibuf size value %zd != %zd:", 112 num, ibuf_size(buf), ibuf_size(out)); 113 dump(ibuf_data(buf), ibuf_size(buf)); 114 printf("expected: "); 115 dump(ibuf_data(out), ibuf_size(out)); 116 return -1; 117 } 118 if (memcmp(ibuf_data(buf), ibuf_data(out), ibuf_size(out)) != 0) { 119 printf("Test %zu: unexpected encoding: ", num); 120 dump(ibuf_data(buf), ibuf_size(buf)); 121 printf("expected: "); 122 dump(ibuf_data(out), ibuf_size(out)); 123 return -1; 124 } 125 126 return 0; 127 } 128 129 static int 130 test_filter(size_t num, struct testfilter *f) 131 { 132 size_t l; 133 int r; 134 struct rde_peer *p = &peer; 135 136 communities_clean(&comm); 137 138 if (f->peer != NULL) 139 p = f->peer; 140 141 for (l = 0; f->in[l] != -1; l++) { 142 r = community_set(&comm, &filters[f->in[l]], p); 143 if (r != 1) { 144 printf("Test %zu: community_set %zu " 145 "unexpected return %d != 1\n", 146 num, l, r); 147 return -1; 148 } 149 } 150 151 if (f->match != -1) { 152 r = community_match(&comm, &filters[f->match], p); 153 if (r != f->mout) { 154 printf("Test %zu: community_match " 155 "unexpected return %d != %d\n", num, r, f->mout); 156 return -1; 157 } 158 } 159 160 if (f->delete != -1) { 161 community_delete(&comm, &filters[f->delete], p); 162 163 if (community_match(&comm, &filters[f->delete], p) != 0) { 164 printf("Test %zu: community_delete still around\n", 165 num); 166 return -1; 167 } 168 } 169 170 if (f->ncomm != 0) { 171 if (community_count(&comm, COMMUNITY_TYPE_BASIC) != 172 f->ncomm - 1) { 173 printf("Test %zu: community_count unexpected " 174 "return %d != %d\n", num, r, f->ncomm - 1); 175 return -1; 176 } 177 } 178 179 if (f->next != 0) { 180 if (community_count(&comm, COMMUNITY_TYPE_EXT) != 181 f->next - 1) { 182 printf("Test %zu: ext community_count unexpected " 183 "return %d != %d\n", num, r, f->next - 1); 184 return -1; 185 } 186 } 187 188 if (f->nlarge != 0) { 189 if (community_count(&comm, COMMUNITY_TYPE_LARGE) != 190 f->nlarge - 1) { 191 printf("Test %zu: large community_count unexpected " 192 "return %d != %d\n", num, r, f->nlarge - 1); 193 return -1; 194 } 195 } 196 197 return 0; 198 } 199 200 int 201 main(int argc, char *argv[]) 202 { 203 size_t t; 204 int error = 0; 205 206 for (t = 0; t < sizeof(vectors) / sizeof(*vectors); t++) { 207 struct ibuf in, out; 208 209 ibuf_from_buffer(&in, vectors[t].data, vectors[t].size); 210 if (vectors[t].expected == NULL) 211 ibuf_from_buffer(&out, 212 vectors[t].data, vectors[t].size); 213 else 214 ibuf_from_buffer(&out, 215 vectors[t].expected, vectors[t].expsize); 216 217 if (test_parsing(t, &in, &out) == -1) 218 error = 1; 219 } 220 221 for (t = 0; t < sizeof(testfilters) / sizeof(*testfilters); t++) { 222 if (test_filter(t, &testfilters[t]) == -1) 223 error = 1; 224 } 225 226 if (!error) 227 printf("OK\n"); 228 return error; 229 } 230 231 __dead void 232 fatalx(const char *emsg, ...) 233 { 234 va_list ap; 235 va_start(ap, emsg); 236 verrx(2, emsg, ap); 237 } 238 239 __dead void 240 fatal(const char *emsg, ...) 241 { 242 va_list ap; 243 va_start(ap, emsg); 244 verr(2, emsg, ap); 245 } 246 247 void 248 log_warnx(const char *emsg, ...) 249 { 250 va_list ap; 251 va_start(ap, emsg); 252 vwarnx(emsg, ap); 253 va_end(ap); 254 } 255 256 int 257 attr_writebuf(struct ibuf *buf, uint8_t flags, uint8_t type, void *data, 258 uint16_t data_len) 259 { 260 u_char hdr[4]; 261 262 flags &= ~ATTR_DEFMASK; 263 if (data_len > 255) { 264 flags |= ATTR_EXTLEN; 265 hdr[2] = (data_len >> 8) & 0xff; 266 hdr[3] = data_len & 0xff; 267 } else { 268 hdr[2] = data_len & 0xff; 269 } 270 271 hdr[0] = flags; 272 hdr[1] = type; 273 274 if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1) 275 return (-1); 276 if (data != NULL && ibuf_add(buf, data, data_len) == -1) 277 return (-1); 278 return (0); 279 280 } 281