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
dump(uint8_t * b,size_t len)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
test_parsing(size_t num,struct ibuf * in,struct ibuf * out)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
test_filter(size_t num,struct testfilter * f)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
main(int argc,char * argv[])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
fatalx(const char * emsg,...)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
fatal(const char * emsg,...)240 fatal(const char *emsg, ...)
241 {
242 va_list ap;
243 va_start(ap, emsg);
244 verr(2, emsg, ap);
245 }
246
247 void
log_warnx(const char * emsg,...)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
attr_writebuf(struct ibuf * buf,uint8_t flags,uint8_t type,void * data,uint16_t data_len)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