xref: /openbsd-src/regress/usr.sbin/bgpd/unittests/rde_aspa_test.c (revision 4a2c408de7aa871da60ea7a066233502ab912e73)
1*4a2c408dSclaudio /*	$OpenBSD: rde_aspa_test.c,v 1.5 2023/08/16 08:29:41 claudio Exp $ */
281623c4aSclaudio 
381623c4aSclaudio /*
481623c4aSclaudio  * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
581623c4aSclaudio  *
681623c4aSclaudio  * Permission to use, copy, modify, and distribute this software for any
781623c4aSclaudio  * purpose with or without fee is hereby granted, provided that the above
881623c4aSclaudio  * copyright notice and this permission notice appear in all copies.
981623c4aSclaudio  *
1081623c4aSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1181623c4aSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1281623c4aSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1381623c4aSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1481623c4aSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1581623c4aSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1681623c4aSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1781623c4aSclaudio  */
1881623c4aSclaudio 
1981623c4aSclaudio #include <assert.h>
2081623c4aSclaudio #include <err.h>
2181623c4aSclaudio #include <stdio.h>
2281623c4aSclaudio 
2381623c4aSclaudio #include "rde_aspa.c"
2481623c4aSclaudio 
2581623c4aSclaudio static struct aspath	*build_aspath(const uint32_t *, uint32_t, int);
2681623c4aSclaudio static const char	*print_aspath(const uint32_t *, uint32_t);
2781623c4aSclaudio 
2881623c4aSclaudio static void	 reverse_state(struct aspa_state *, struct aspa_state *);
2981623c4aSclaudio static void	 print_state(struct aspa_state *, struct aspa_state *);
3081623c4aSclaudio 
3181623c4aSclaudio struct aspa_test_set {
3281623c4aSclaudio 	uint32_t	customeras;
3381623c4aSclaudio 	const uint32_t	*providers;
3481623c4aSclaudio 	uint32_t	pascnt;
3581623c4aSclaudio };
3681623c4aSclaudio 
3781623c4aSclaudio struct cp_test {
3881623c4aSclaudio 	uint32_t	customeras;
3981623c4aSclaudio 	uint32_t	provideras;
40a01a053bSclaudio 	uint8_t		expected_result;
4181623c4aSclaudio };
4281623c4aSclaudio 
4381623c4aSclaudio struct aspath_test {
4481623c4aSclaudio 	const uint32_t		*aspath;
4581623c4aSclaudio 	uint32_t		 aspathcnt;
4681623c4aSclaudio 	struct aspa_state	 state;
4781623c4aSclaudio };
4881623c4aSclaudio 
4981623c4aSclaudio struct aspa_test {
5081623c4aSclaudio 	const uint32_t	*aspath;
5181623c4aSclaudio 	uint32_t	 aspathcnt;
5281623c4aSclaudio 	enum role	 role;
5381623c4aSclaudio 	uint8_t		 expected_result;
5481623c4aSclaudio };
5581623c4aSclaudio 
5681623c4aSclaudio struct aspa_test_set testset[] = {
5781623c4aSclaudio 	/* test vectors from  github.com/benmaddison/aspa-fuzz */
58*4a2c408dSclaudio 	{ 1, (const uint32_t []){ 4, 5, 6 }, 3 },
59*4a2c408dSclaudio 	{ 2, (const uint32_t []){ 10, 11 }, 2 },
60*4a2c408dSclaudio 	{ 3, (const uint32_t []){ 1, 13, 14 }, 3 },
61*4a2c408dSclaudio 	{ 4, (const uint32_t []){ 16, 24 }, 2 },
62*4a2c408dSclaudio 	{ 5, (const uint32_t []){ 1, 17, 25 }, 3 },
63*4a2c408dSclaudio 	{ 8, (const uint32_t []){ 0 }, 1 },
64*4a2c408dSclaudio 	{ 9, (const uint32_t []){ 2 }, 1 },
65*4a2c408dSclaudio 	{ 10, (const uint32_t []){ 0 }, 1 },
66*4a2c408dSclaudio 	{ 11, (const uint32_t []){ 2 }, 1 },
67*4a2c408dSclaudio 	{ 12, (const uint32_t []){ 3 }, 1 },
68*4a2c408dSclaudio 	{ 13, (const uint32_t []){ 0 }, 1 },
69*4a2c408dSclaudio 	{ 14, (const uint32_t []){ 3, 25 }, 2 },
70*4a2c408dSclaudio 	{ 15, (const uint32_t []){ 4 }, 1 },
71*4a2c408dSclaudio 	{ 16, (const uint32_t []){ 4 }, 1 },
72*4a2c408dSclaudio 	{ 17, (const uint32_t []){ 5 }, 1 },
73*4a2c408dSclaudio 	{ 18, (const uint32_t []){ 6 }, 1 },
74*4a2c408dSclaudio 	{ 20, (const uint32_t []){ 19 }, 1 },
75*4a2c408dSclaudio 	{ 21, (const uint32_t []){ 0 }, 1 },
76*4a2c408dSclaudio 	{ 23, (const uint32_t []){ 22 }, 1 },
77*4a2c408dSclaudio 	{ 24, (const uint32_t []){ 0 }, 1 },
78*4a2c408dSclaudio 	{ 25, (const uint32_t []){ 0 }, 1 },
79*4a2c408dSclaudio 	{ 26, (const uint32_t []){ 5 }, 1 },
80*4a2c408dSclaudio 	{ 27, (const uint32_t []){ 14 }, 1 },
8181623c4aSclaudio 	/* tests to simulate slides-110-sidrops-sriram-aspa-alg-accuracy-01 */
82*4a2c408dSclaudio 	{ 101, (const uint32_t []){ 102 }, 1 },
83*4a2c408dSclaudio 	{ 102, (const uint32_t []){ 103, 104, 105 }, 3 },
84*4a2c408dSclaudio 	{ 103, (const uint32_t []){ 111, 112, 203 }, 3 },
8581623c4aSclaudio 	/* 104 no ASPA */
86*4a2c408dSclaudio 	{ 105, (const uint32_t []){ 0 }, 1 },
8781623c4aSclaudio 
8881623c4aSclaudio 	/* 111 no ASPA */
89*4a2c408dSclaudio 	{ 112, (const uint32_t []){ 0 }, 1 },
90*4a2c408dSclaudio 	{ 113, (const uint32_t []){ 104, 105, 204, 205 }, 4 },
9181623c4aSclaudio 
92*4a2c408dSclaudio 	{ 121, (const uint32_t []){ 131, 132, 133 }, 3 },
93*4a2c408dSclaudio 	{ 123, (const uint32_t []){ 0 }, 1 },
94*4a2c408dSclaudio 	{ 131, (const uint32_t []){ 121, 122, 123 }, 3 },
95*4a2c408dSclaudio 	{ 133, (const uint32_t []){ 0 }, 1 },
9681623c4aSclaudio 
9781623c4aSclaudio 
98*4a2c408dSclaudio 	{ 201, (const uint32_t []){ 202 }, 1 },
99*4a2c408dSclaudio 	{ 202, (const uint32_t []){ 203, 204, 205 }, 3 },
100*4a2c408dSclaudio 	{ 203, (const uint32_t []){ 103, 111, 112 }, 3 },
10181623c4aSclaudio 	/* 204 no ASPA */
102*4a2c408dSclaudio 	{ 205, (const uint32_t []){ 0 }, 1 },
10381623c4aSclaudio 
10481623c4aSclaudio 	/* extra test for big table test */
10581623c4aSclaudio 	{ 65000, (const uint32_t []){
10681623c4aSclaudio 	    3, 5, 10, 15, 20, 21, 22, 23, 24, 25,
10781623c4aSclaudio 	    30, 35, 40, 45, 50, 51, 52, 53, 54, 55,
108*4a2c408dSclaudio 	    60, 65, 70, 75, 80, 81, 82, 83, 87, 90 }, 30 },
109*4a2c408dSclaudio 	{ 196618, (const uint32_t []){ 1, 2, 3, 4 }, 4 },
11081623c4aSclaudio };
11181623c4aSclaudio 
11281623c4aSclaudio struct cp_test cp_testset[] = {
113*4a2c408dSclaudio 	{ 6, 1, UNKNOWN },
114*4a2c408dSclaudio 	{ 42, 1, UNKNOWN },
11581623c4aSclaudio 
116*4a2c408dSclaudio 	{ 1, 2, NOT_PROVIDER },
117*4a2c408dSclaudio 	{ 1, 3, NOT_PROVIDER },
118*4a2c408dSclaudio 	{ 1, 7, NOT_PROVIDER },
119*4a2c408dSclaudio 	{ 5, 2, NOT_PROVIDER },
120*4a2c408dSclaudio 	{ 5, 16, NOT_PROVIDER },
121*4a2c408dSclaudio 	{ 5, 18, NOT_PROVIDER },
122*4a2c408dSclaudio 	{ 5, 24, NOT_PROVIDER },
123*4a2c408dSclaudio 	{ 5, 26, NOT_PROVIDER },
124*4a2c408dSclaudio 	{ 8, 2, NOT_PROVIDER },
125*4a2c408dSclaudio 	{ 9, 5, NOT_PROVIDER },
126*4a2c408dSclaudio 	{ 27, 13, NOT_PROVIDER },
127*4a2c408dSclaudio 	{ 27, 15, NOT_PROVIDER },
12881623c4aSclaudio 
129*4a2c408dSclaudio 	{ 1, 4, PROVIDER },
130*4a2c408dSclaudio 	{ 1, 5, PROVIDER },
131*4a2c408dSclaudio 	{ 1, 6, PROVIDER },
132*4a2c408dSclaudio 	{ 2, 10, PROVIDER },
133*4a2c408dSclaudio 	{ 2, 11, PROVIDER },
134*4a2c408dSclaudio 	{ 9, 2, PROVIDER },
135*4a2c408dSclaudio 	{ 27, 14, PROVIDER },
13681623c4aSclaudio 
137*4a2c408dSclaudio 	{ 196618, 1, PROVIDER },
138*4a2c408dSclaudio 	{ 196618, 2, PROVIDER },
139*4a2c408dSclaudio 	{ 196618, 3, PROVIDER },
140*4a2c408dSclaudio 	{ 196618, 4, PROVIDER },
141*4a2c408dSclaudio 	{ 196618, 5, NOT_PROVIDER },
14281623c4aSclaudio 
14381623c4aSclaudio 	/* big provider set test */
144*4a2c408dSclaudio 	{ 65000, 1, NOT_PROVIDER },
145*4a2c408dSclaudio 	{ 65000, 2, NOT_PROVIDER },
146*4a2c408dSclaudio 	{ 65000, 3, PROVIDER },
147*4a2c408dSclaudio 	{ 65000, 4, NOT_PROVIDER },
148*4a2c408dSclaudio 	{ 65000, 5, PROVIDER },
149*4a2c408dSclaudio 	{ 65000, 15, PROVIDER },
150*4a2c408dSclaudio 	{ 65000, 19, NOT_PROVIDER },
151*4a2c408dSclaudio 	{ 65000, 20, PROVIDER },
152*4a2c408dSclaudio 	{ 65000, 21, PROVIDER },
153*4a2c408dSclaudio 	{ 65000, 22, PROVIDER },
154*4a2c408dSclaudio 	{ 65000, 23, PROVIDER },
155*4a2c408dSclaudio 	{ 65000, 24, PROVIDER },
156*4a2c408dSclaudio 	{ 65000, 25, PROVIDER },
157*4a2c408dSclaudio 	{ 65000, 26, NOT_PROVIDER },
158*4a2c408dSclaudio 	{ 65000, 85, NOT_PROVIDER },
159*4a2c408dSclaudio 	{ 65000, 86, NOT_PROVIDER },
160*4a2c408dSclaudio 	{ 65000, 87, PROVIDER },
161*4a2c408dSclaudio 	{ 65000, 88, NOT_PROVIDER },
162*4a2c408dSclaudio 	{ 65000, 89, NOT_PROVIDER },
163*4a2c408dSclaudio 	{ 65000, 90, PROVIDER },
164*4a2c408dSclaudio 	{ 65000, 91, NOT_PROVIDER },
165*4a2c408dSclaudio 	{ 65000, 92, NOT_PROVIDER },
166*4a2c408dSclaudio 	{ 65000, 6666, NOT_PROVIDER },
16781623c4aSclaudio };
16881623c4aSclaudio 
16981623c4aSclaudio struct aspath_test	aspath_testset[] = {
17081623c4aSclaudio 	{ (const uint32_t []) { 1 }, 1, { 1, 1, 0, 0, 1, 0, 0 } },
17181623c4aSclaudio 	{ (const uint32_t []) { 7 }, 1, { 1, 1, 0, 0, 1, 0, 0 } },
17281623c4aSclaudio 	{ (const uint32_t []) { 8 }, 1, { 1, 1, 0, 0, 1, 0, 0 } },
17381623c4aSclaudio 
17481623c4aSclaudio 	{ (const uint32_t []) { 1, 1 }, 2, { 1, 1, 0, 0, 1, 0, 0 } },
17581623c4aSclaudio 	{ (const uint32_t []) { 7, 7 }, 2, { 1, 1, 0, 0, 1, 0, 0 } },
17681623c4aSclaudio 	{ (const uint32_t []) { 8, 8 }, 2, { 1, 1, 0, 0, 1, 0, 0 } },
17781623c4aSclaudio 
17881623c4aSclaudio 	{ (const uint32_t []) { 1, 1, 1 }, 3, { 1, 1, 0, 0, 1, 0, 0 } },
17981623c4aSclaudio 	{ (const uint32_t []) { 7, 7, 7 }, 3, { 1, 1, 0, 0, 1, 0, 0 } },
18081623c4aSclaudio 	{ (const uint32_t []) { 8, 8, 8 }, 3, { 1, 1, 0, 0, 1, 0, 0 } },
18181623c4aSclaudio 
18281623c4aSclaudio 	{ (const uint32_t []) { 1, 5 }, 2, { 2, 1, 0, 0, 2, 0, 0 } },
18381623c4aSclaudio 	{ (const uint32_t []) { 1, 1, 5, 5 }, 4, { 2, 1, 0, 0, 2, 0, 0 } },
18481623c4aSclaudio 	{ (const uint32_t []) { 1, 5, 17 }, 3, { 3, 1, 0, 0, 3, 0, 0 } },
18581623c4aSclaudio 
18681623c4aSclaudio 	{ (const uint32_t []) { 1, 4 }, 2, { 2, 2, 0, 1, 2, 0, 0 } },
18781623c4aSclaudio 	{ (const uint32_t []) { 1, 6 }, 2, { 2, 2, 1, 0, 2, 0, 0 } },
18881623c4aSclaudio 	{ (const uint32_t []) { 1, 17 }, 2, { 2, 2, 0, 1, 1, 0, 2 } },
18981623c4aSclaudio 
19081623c4aSclaudio 	{ (const uint32_t []) { 42, 43, 44 }, 3, { 3, 3, 2, 0, 1, 2, 0 } },
19181623c4aSclaudio 
19281623c4aSclaudio 	{ (const uint32_t []) { 42, 1, 5, 17, 44 }, 5,
19381623c4aSclaudio 	     { 5, 5, 4, 1, 1, 2, 5 } },
19481623c4aSclaudio 
19581623c4aSclaudio 	/* 1 ?> 6 -? 11 -- 12 -- 13 ?- 19 <? 20 */
19681623c4aSclaudio 	{ (const uint32_t []) { 1, 6, 11, 12, 13, 19, 20 }, 7,
19781623c4aSclaudio 	     { 7, 6, 5, 4, 2, 3, 4 } },
19881623c4aSclaudio };
19981623c4aSclaudio 
20081623c4aSclaudio /*
20181623c4aSclaudio  * For simplicity the relation between is described as 123 LR 124 where:
20281623c4aSclaudio  * R: ? if ASPA(123) is empty
20381623c4aSclaudio  *    > if 124 is a provider of 123
20481623c4aSclaudio  *    - otherwise (124 is not part of the provider list)
20581623c4aSclaudio  * L: ? if ASPA(124) is empty
20681623c4aSclaudio  *    > if 123 is a provider of of 124
20781623c4aSclaudio  *    - otherwise (123 is not part of the provider list)
20881623c4aSclaudio  *
20981623c4aSclaudio  * e.g. 1 -> 2 (2 is provider of 1 but 1 is not for 2)
21081623c4aSclaudio  *      1 ?> 2 (2 is provider of 1 but 2 has no ASPA set defined)
21181623c4aSclaudio  */
21281623c4aSclaudio struct aspa_test	aspa_testset[] = {
21381623c4aSclaudio 	/* empty ASPATH are invalid by default */
214a01a053bSclaudio 	{ (const uint32_t []) { }, 0, ROLE_CUSTOMER, ASPA_INVALID },
215a01a053bSclaudio 	{ (const uint32_t []) { }, 0, ROLE_PROVIDER, ASPA_INVALID },
216a01a053bSclaudio 	{ (const uint32_t []) { }, 0, ROLE_RS, ASPA_INVALID },
217a01a053bSclaudio 	{ (const uint32_t []) { }, 0, ROLE_RS_CLIENT, ASPA_INVALID },
218a01a053bSclaudio 	{ (const uint32_t []) { }, 0, ROLE_PEER, ASPA_INVALID },
21981623c4aSclaudio 
220a01a053bSclaudio 	{ (const uint32_t []) { 2 }, 1, ROLE_RS_CLIENT, ASPA_VALID },
221a01a053bSclaudio 	{ (const uint32_t []) { 2 }, 1, ROLE_PEER, ASPA_VALID },
22281623c4aSclaudio 
223a01a053bSclaudio 	{ (const uint32_t []) { 3 }, 1, ROLE_PROVIDER, ASPA_VALID },
224a01a053bSclaudio 	{ (const uint32_t []) { 4 }, 1, ROLE_CUSTOMER, ASPA_VALID },
225a01a053bSclaudio 	{ (const uint32_t []) { 5 }, 1, ROLE_CUSTOMER, ASPA_VALID },
226a01a053bSclaudio 	{ (const uint32_t []) { 6 }, 1, ROLE_CUSTOMER, ASPA_VALID },
22781623c4aSclaudio 
228a01a053bSclaudio 	{ (const uint32_t []) { 7 }, 1, ROLE_PROVIDER, ASPA_VALID },
229a01a053bSclaudio 	{ (const uint32_t []) { 7 }, 1, ROLE_PEER, ASPA_VALID },
230a01a053bSclaudio 	{ (const uint32_t []) { 7 }, 1, ROLE_RS_CLIENT, ASPA_VALID },
23181623c4aSclaudio 
232a01a053bSclaudio 	{ (const uint32_t []) { 2, 8 }, 2, ROLE_PEER, ASPA_INVALID },
233a01a053bSclaudio 	{ (const uint32_t []) { 2, 8 }, 2, ROLE_RS_CLIENT, ASPA_INVALID },
234a01a053bSclaudio 
235a01a053bSclaudio 	{ (const uint32_t []) { 2, 9 }, 2, ROLE_PEER, ASPA_VALID },
236a01a053bSclaudio 	{ (const uint32_t []) { 2, 9 }, 2, ROLE_RS_CLIENT, ASPA_VALID },
237a01a053bSclaudio 
238a01a053bSclaudio 	{ (const uint32_t []) { 2, 10 }, 2, ROLE_PEER, ASPA_INVALID },
239a01a053bSclaudio 	{ (const uint32_t []) { 2, 10 }, 2, ROLE_RS_CLIENT, ASPA_INVALID },
240a01a053bSclaudio 
241a01a053bSclaudio 	{ (const uint32_t []) { 2, 11 }, 2, ROLE_PEER, ASPA_VALID },
242a01a053bSclaudio 	{ (const uint32_t []) { 2, 11 }, 2, ROLE_RS_CLIENT, ASPA_VALID },
243a01a053bSclaudio 
244a01a053bSclaudio 	{ (const uint32_t []) { 3, 8 }, 2, ROLE_PROVIDER, ASPA_INVALID },
245a01a053bSclaudio 	{ (const uint32_t []) { 3, 12 }, 2, ROLE_PROVIDER, ASPA_VALID },
246a01a053bSclaudio 	{ (const uint32_t []) { 3, 13 }, 2, ROLE_PROVIDER, ASPA_INVALID },
247a01a053bSclaudio 	{ (const uint32_t []) { 3, 14 }, 2, ROLE_PROVIDER, ASPA_VALID },
248a01a053bSclaudio 
249a01a053bSclaudio 	{ (const uint32_t []) { 4, 8 }, 2, ROLE_CUSTOMER, ASPA_VALID },
250a01a053bSclaudio 	{ (const uint32_t []) { 4, 15 }, 2, ROLE_CUSTOMER, ASPA_VALID },
251a01a053bSclaudio 	{ (const uint32_t []) { 4, 16 }, 2, ROLE_CUSTOMER, ASPA_VALID },
252a01a053bSclaudio 	{ (const uint32_t []) { 4, 24 }, 2, ROLE_CUSTOMER, ASPA_VALID },
253a01a053bSclaudio 
254a01a053bSclaudio 	{ (const uint32_t []) { 5, 8 }, 2, ROLE_CUSTOMER, ASPA_VALID },
255a01a053bSclaudio 	{ (const uint32_t []) { 5, 17 }, 2, ROLE_CUSTOMER, ASPA_VALID },
256a01a053bSclaudio 	{ (const uint32_t []) { 5, 25 }, 2, ROLE_CUSTOMER, ASPA_VALID },
257a01a053bSclaudio 	{ (const uint32_t []) { 5, 26 }, 2, ROLE_CUSTOMER, ASPA_VALID },
258a01a053bSclaudio 
259a01a053bSclaudio 	{ (const uint32_t []) { 6, 18 }, 2, ROLE_CUSTOMER, ASPA_VALID },
260a01a053bSclaudio 	{ (const uint32_t []) { 6, 19 }, 2, ROLE_CUSTOMER, ASPA_VALID },
261a01a053bSclaudio 
262a01a053bSclaudio 	{ (const uint32_t []) { 7, 19 }, 2, ROLE_PROVIDER, ASPA_UNKNOWN },
263a01a053bSclaudio 	{ (const uint32_t []) { 7, 19 }, 2, ROLE_PEER, ASPA_UNKNOWN },
264a01a053bSclaudio 	{ (const uint32_t []) { 7, 19 }, 2, ROLE_RS_CLIENT, ASPA_UNKNOWN },
265a01a053bSclaudio 	{ (const uint32_t []) { 7, 21 }, 2, ROLE_PROVIDER, ASPA_INVALID },
266a01a053bSclaudio 	{ (const uint32_t []) { 7, 21 }, 2, ROLE_PEER, ASPA_INVALID },
267a01a053bSclaudio 	{ (const uint32_t []) { 7, 21 }, 2, ROLE_RS_CLIENT, ASPA_INVALID },
268a01a053bSclaudio 
269a01a053bSclaudio 	{ (const uint32_t []) { 6, 19, 20 }, 3, ROLE_CUSTOMER, ASPA_VALID },
270a01a053bSclaudio 	{ (const uint32_t []) { 20, 19, 6 }, 3, ROLE_CUSTOMER, ASPA_VALID },
271a01a053bSclaudio 
272a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 25 }, 3, ROLE_PROVIDER, ASPA_INVALID },
273a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 19 }, 3, ROLE_PROVIDER, ASPA_UNKNOWN },
274a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 19 }, 3, ROLE_PEER, ASPA_UNKNOWN },
275a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 19 }, 3, ROLE_RS_CLIENT, ASPA_UNKNOWN },
276a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 21 }, 3, ROLE_PROVIDER, ASPA_INVALID },
277a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 21 }, 3, ROLE_PEER, ASPA_INVALID },
278a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 21 }, 3, ROLE_RS_CLIENT, ASPA_INVALID },
279a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 27 }, 3, ROLE_PROVIDER, ASPA_VALID },
280a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 27 }, 3, ROLE_PEER, ASPA_VALID },
281a01a053bSclaudio 	{ (const uint32_t []) { 3, 14, 27 }, 3, ROLE_RS_CLIENT, ASPA_VALID },
282a01a053bSclaudio 
283a01a053bSclaudio 	{ (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_PROVIDER,
284a01a053bSclaudio 	    ASPA_INVALID },
285a01a053bSclaudio 	{ (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_PEER, ASPA_INVALID },
286a01a053bSclaudio 	{ (const uint32_t []) { 7, 19, 22, 21 }, 4, ROLE_RS_CLIENT,
28781623c4aSclaudio 	    ASPA_INVALID },
28881623c4aSclaudio 
289a01a053bSclaudio 	{ (const uint32_t []) { 6, 19, 22, 23 }, 4, ROLE_CUSTOMER,
29081623c4aSclaudio 	    ASPA_UNKNOWN },
29181623c4aSclaudio 
29281623c4aSclaudio 	{ (const uint32_t []) { 1, 5, 17, 13, 3, 14, 27 }, 7, ROLE_CUSTOMER,
293a01a053bSclaudio 	    ASPA_VALID },
29481623c4aSclaudio 	{ (const uint32_t []) { 27, 14, 3, 13, 17, 5, 1 }, 7, ROLE_CUSTOMER,
295a01a053bSclaudio 	    ASPA_VALID },
29681623c4aSclaudio 
29781623c4aSclaudio 	{ (const uint32_t []) { 27, 14, 3, 6, 7, 19, 17, 5, 1 }, 9,
298a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_INVALID },
29981623c4aSclaudio 	{ (const uint32_t []) { 27, 14, 3, 7, 19, 6, 1, 5, 17 }, 9,
300a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
30181623c4aSclaudio 
30281623c4aSclaudio 	/* check L < K (ramps overlap) */
30381623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 203, 103, 102, 101 }, 6,
304a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
30581623c4aSclaudio 	{ (const uint32_t []) { 101, 102, 103, 203, 202, 201 }, 6,
306a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
30781623c4aSclaudio 
30881623c4aSclaudio 	/* check L == K (ramps touch) 203 ?> 111 <? 103 */
30981623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 203, 111, 103, 102, 101 }, 7,
310a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
31181623c4aSclaudio 	{ (const uint32_t []) { 101, 102, 103, 111, 203, 202, 201 }, 7,
312a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
31381623c4aSclaudio 	/* check L == K (ramps touch) 203 -> 111 <- 103 */
31481623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 203, 112, 103, 102, 101 }, 7,
315a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
31681623c4aSclaudio 	{ (const uint32_t []) { 101, 102, 103, 112, 203, 202, 201 }, 7,
317a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
31881623c4aSclaudio 
31981623c4aSclaudio 	/* check L - K == 1 (204 ?? 104) */
32081623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 104, 102, 101 }, 6,
321a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
32281623c4aSclaudio 	/* check L - K == 1 (204 -? 105) */
32381623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 105, 102, 101 }, 6,
324a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
32581623c4aSclaudio 	/* check L - K == 1 (205 ?- 104) */
32681623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 104, 102, 101 }, 6,
327a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
32881623c4aSclaudio 	/* check L - K == 1 (205 -- 105) */
32981623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 105, 102, 101 }, 6,
330a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_VALID },
33181623c4aSclaudio 
33281623c4aSclaudio 	/* check L - K == 2 invalid cases (205 ?- 111 -? 105) */
33381623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 111, 105, 102, 101 }, 7,
334a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_INVALID },
33581623c4aSclaudio 	/* check L - K == 2 invalid cases (205 -- 112 -- 105) */
33681623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 112, 105, 102, 101 }, 7,
337a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_INVALID },
33881623c4aSclaudio 	/* check L - K == 2 invalid cases (205 <- 113 -> 105) */
33981623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 113, 105, 102, 101 }, 7,
340a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_INVALID },
34181623c4aSclaudio 
34281623c4aSclaudio 	/* check L - K == 2 unknown cases (205 ?- 111 ?? 104) */
34381623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 111, 104, 102, 101 }, 7,
344a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
34581623c4aSclaudio 	/* check L - K == 2 unknown cases (204 ?? 111 -? 105) */
34681623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 111, 105, 102, 101 }, 7,
347a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
34881623c4aSclaudio 	/* check L - K == 2 unknown cases (204 ?? 111 ?? 104) */
34981623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 111, 104, 102, 101 }, 7,
350a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
35181623c4aSclaudio 	/* check L - K == 2 unknown cases (205 -- 112 ?- 104) */
35281623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 112, 104, 102, 101 }, 7,
353a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
35481623c4aSclaudio 	/* check L - K == 2 unknown cases (204 -? 112 -- 105) */
35581623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 112, 105, 102, 101 }, 7,
356a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
35781623c4aSclaudio 	/* check L - K == 2 unknown cases (204 -? 112 ?- 104) */
35881623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 112, 104, 102, 101 }, 7,
359a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
36081623c4aSclaudio 	/* check L - K == 2 unknown cases (205 <- 113 ?> 104) */
36181623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 205, 113, 104, 102, 101 }, 7,
362a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
36381623c4aSclaudio 	/* check L - K == 2 unknown cases (204 <? 113 -> 105) */
36481623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 113, 105, 102, 101 }, 7,
365a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
36681623c4aSclaudio 	/* check L - K == 2 unknown cases (204 <? 113 ?> 104) */
36781623c4aSclaudio 	{ (const uint32_t []) { 201, 202, 204, 113, 104, 102, 101 }, 7,
368a01a053bSclaudio 	    ROLE_CUSTOMER, ASPA_UNKNOWN },
36981623c4aSclaudio };
37081623c4aSclaudio 
37181623c4aSclaudio static struct rde_aspa *
load_test_set(struct aspa_test_set * testv,uint32_t numentries)37281623c4aSclaudio load_test_set(struct aspa_test_set *testv, uint32_t numentries)
37381623c4aSclaudio {
37481623c4aSclaudio 	struct rde_aspa *aspa;
37581623c4aSclaudio 	size_t data_size = 0;
37681623c4aSclaudio 	uint32_t i;
37781623c4aSclaudio 
378*4a2c408dSclaudio 	for (i = 0; i < numentries; i++)
37981623c4aSclaudio 		data_size += testv[i].pascnt * sizeof(uint32_t);
38081623c4aSclaudio 
38181623c4aSclaudio 	aspa = aspa_table_prep(numentries, data_size);
38281623c4aSclaudio 
383*4a2c408dSclaudio 	for (i = numentries; i > 0; i--)
38481623c4aSclaudio 		aspa_add_set(aspa, testv[i - 1].customeras,
385*4a2c408dSclaudio 		    testv[i - 1].providers, testv[i - 1].pascnt);
38681623c4aSclaudio 
38781623c4aSclaudio 	return aspa;
38881623c4aSclaudio }
38981623c4aSclaudio 
390a01a053bSclaudio static uint8_t
vstate_for_role(struct rde_aspa_state * vstate,enum role role)391a01a053bSclaudio vstate_for_role(struct rde_aspa_state *vstate, enum role role)
392a01a053bSclaudio {
393a01a053bSclaudio 	if (role != ROLE_CUSTOMER) {
394*4a2c408dSclaudio 		return (vstate->onlyup);
395a01a053bSclaudio 	} else {
396*4a2c408dSclaudio 		return (vstate->downup);
397a01a053bSclaudio 	}
398a01a053bSclaudio }
39981623c4aSclaudio 
40081623c4aSclaudio int
main(int argc,char ** argv)40181623c4aSclaudio main(int argc, char **argv)
40281623c4aSclaudio {
40381623c4aSclaudio 	struct rde_aspa *aspa;
40481623c4aSclaudio 	size_t num_cp = sizeof(cp_testset) / sizeof(cp_testset[0]);
40581623c4aSclaudio 	size_t num_aspath = sizeof(aspath_testset) / sizeof(aspath_testset[0]);
40681623c4aSclaudio 	size_t num_aspa = sizeof(aspa_testset) / sizeof(aspa_testset[0]);
40781623c4aSclaudio 	size_t i;
40881623c4aSclaudio 	int cp_failed = 0, aspath_failed = 0, aspa_failed = 0;
40981623c4aSclaudio 
41081623c4aSclaudio 	/* first test, loading empty aspa table works. */
41181623c4aSclaudio 	aspa = load_test_set(NULL, 0);
41281623c4aSclaudio 	assert(aspa == NULL);
41381623c4aSclaudio 	aspa_table_free(aspa);
41481623c4aSclaudio 
41581623c4aSclaudio 	aspa = load_test_set(testset, sizeof(testset) / sizeof(testset[0]));
41681623c4aSclaudio 	assert(aspa != NULL);
41781623c4aSclaudio 
41881623c4aSclaudio 	printf("testing aspa_cp_lookup: ");
41981623c4aSclaudio 	for (i = 0; i < num_cp; i++) {
420a01a053bSclaudio 		uint8_t r;
42181623c4aSclaudio 		r = aspa_cp_lookup(aspa, cp_testset[i].customeras,
422a01a053bSclaudio 		    cp_testset[i].provideras);
42381623c4aSclaudio 
42481623c4aSclaudio 		if (cp_testset[i].expected_result != r) {
42581623c4aSclaudio 			printf("failed: cp_testset[%zu]: "
42681623c4aSclaudio 			    "cas %u pas %u -> %d got %d\n", i,
42781623c4aSclaudio 			    cp_testset[i].customeras,
42881623c4aSclaudio 			    cp_testset[i].provideras,
42981623c4aSclaudio 			    cp_testset[i].expected_result,
43081623c4aSclaudio 			    r);
43181623c4aSclaudio 			cp_failed = 1;
43281623c4aSclaudio 		}
43381623c4aSclaudio 	}
43481623c4aSclaudio 	if (!cp_failed)
43581623c4aSclaudio 		printf("OK\n");
43681623c4aSclaudio 
43781623c4aSclaudio 	printf("testing aspa_check_aspath: ");
43881623c4aSclaudio 	for (i = 0; i < num_aspath; i++) {
439*4a2c408dSclaudio 		struct aspa_state st, revst;
44081623c4aSclaudio 		struct aspath *a;
44181623c4aSclaudio 
442*4a2c408dSclaudio 		memset(&st, 0, sizeof(st));
44381623c4aSclaudio 		a = build_aspath(aspath_testset[i].aspath,
44481623c4aSclaudio 		    aspath_testset[i].aspathcnt, 0);
445*4a2c408dSclaudio 		if (aspa_check_aspath(aspa, a, &st) == -1) {
44681623c4aSclaudio 			printf("failed: aspath_testset[%zu]: "
44781623c4aSclaudio 			    "aspath %s got -1\n", i,
44881623c4aSclaudio 			    print_aspath(aspath_testset[i].aspath,
44981623c4aSclaudio 			    aspath_testset[i].aspathcnt));
45081623c4aSclaudio 			aspath_failed = 1;
45181623c4aSclaudio 		}
45281623c4aSclaudio 
453*4a2c408dSclaudio 		if (memcmp(&aspath_testset[i].state, &st, sizeof(st))) {
45481623c4aSclaudio 			printf("failed: aspath_testset[%zu]: aspath %s "
45581623c4aSclaudio 			    "bad state", i,
45681623c4aSclaudio 			    print_aspath(aspath_testset[i].aspath,
45781623c4aSclaudio 			    aspath_testset[i].aspathcnt));
458*4a2c408dSclaudio 			print_state(&aspath_testset[i].state, &st);
45981623c4aSclaudio 			printf("\n");
46081623c4aSclaudio 			aspath_failed = 1;
46181623c4aSclaudio 		}
46281623c4aSclaudio 		free(a);
46381623c4aSclaudio 
464*4a2c408dSclaudio 		memset(&st, 0, sizeof(st));
46581623c4aSclaudio 		a = build_aspath(aspath_testset[i].aspath,
46681623c4aSclaudio 		    aspath_testset[i].aspathcnt, 1);
467*4a2c408dSclaudio 		if (aspa_check_aspath(aspa, a, &st) == -1) {
46881623c4aSclaudio 			printf("failed: reverse aspath_testset[%zu]: "
46981623c4aSclaudio 			    "aspath %s got -1\n", i,
47081623c4aSclaudio 			    print_aspath(aspath_testset[i].aspath,
47181623c4aSclaudio 			    aspath_testset[i].aspathcnt));
47281623c4aSclaudio 			aspath_failed = 1;
47381623c4aSclaudio 		}
47481623c4aSclaudio 
47581623c4aSclaudio 		reverse_state(&aspath_testset[i].state, &revst);
476*4a2c408dSclaudio 		if (memcmp(&revst, &st, sizeof(st))) {
47781623c4aSclaudio 			printf("failed: reverse aspath_testset[%zu]: aspath %s "
47881623c4aSclaudio 			    "bad state", i,
47981623c4aSclaudio 			    print_aspath(aspath_testset[i].aspath,
48081623c4aSclaudio 			    aspath_testset[i].aspathcnt));
481*4a2c408dSclaudio 			print_state(&revst, &st);
48281623c4aSclaudio 			printf("\n");
48381623c4aSclaudio 			aspath_failed = 1;
48481623c4aSclaudio 		}
48581623c4aSclaudio 		free(a);
48681623c4aSclaudio 	}
48781623c4aSclaudio 	if (!aspath_failed)
48881623c4aSclaudio 		printf("OK\n");
48981623c4aSclaudio 
49081623c4aSclaudio 	printf("testing aspa_validation: ");
49181623c4aSclaudio 	for (i = 0; i < num_aspa; i++) {
49281623c4aSclaudio 		struct aspath *a;
493a01a053bSclaudio 		struct rde_aspa_state vstate;
49481623c4aSclaudio 		uint8_t rv;
49581623c4aSclaudio 
49681623c4aSclaudio 		a = build_aspath(aspa_testset[i].aspath,
49781623c4aSclaudio 		    aspa_testset[i].aspathcnt, 0);
498a01a053bSclaudio 		aspa_validation(aspa, a, &vstate);
499a01a053bSclaudio 
500a01a053bSclaudio 		rv = vstate_for_role(&vstate, aspa_testset[i].role);
50181623c4aSclaudio 
50281623c4aSclaudio 		if (aspa_testset[i].expected_result != rv) {
50381623c4aSclaudio 			printf("failed: aspa_testset[%zu]: aspath %s role %d "
50481623c4aSclaudio 			    "want %d got %d", i,
50581623c4aSclaudio 			    print_aspath(aspa_testset[i].aspath,
50681623c4aSclaudio 			    aspa_testset[i].aspathcnt),
50781623c4aSclaudio 			    aspa_testset[i].role,
50881623c4aSclaudio 			    aspa_testset[i].expected_result,
50981623c4aSclaudio 			    rv);
51081623c4aSclaudio 			aspa_failed = 1;
51181623c4aSclaudio 		}
51281623c4aSclaudio 
51381623c4aSclaudio 		free(a);
51481623c4aSclaudio 	}
51581623c4aSclaudio 	if (!aspa_failed)
51681623c4aSclaudio 		printf("OK\n");
51781623c4aSclaudio 
51881623c4aSclaudio 	aspa_table_free(aspa);
51981623c4aSclaudio 
52081623c4aSclaudio 	return cp_failed | aspath_failed | aspa_failed;
52181623c4aSclaudio }
52281623c4aSclaudio 
52381623c4aSclaudio __dead void
fatalx(const char * emsg,...)52481623c4aSclaudio fatalx(const char *emsg, ...)
52581623c4aSclaudio {
52681623c4aSclaudio 	va_list ap;
52781623c4aSclaudio 	va_start(ap, emsg);
52881623c4aSclaudio 	verrx(2, emsg, ap);
52981623c4aSclaudio }
53081623c4aSclaudio 
53181623c4aSclaudio __dead void
fatal(const char * emsg,...)53281623c4aSclaudio fatal(const char *emsg, ...)
53381623c4aSclaudio {
53481623c4aSclaudio 	va_list ap;
53581623c4aSclaudio 	va_start(ap, emsg);
53681623c4aSclaudio 	verr(2, emsg, ap);
53781623c4aSclaudio }
53881623c4aSclaudio 
53981623c4aSclaudio uint32_t
aspath_extract(const void * seg,int pos)54081623c4aSclaudio aspath_extract(const void *seg, int pos)
54181623c4aSclaudio {
54281623c4aSclaudio 	const u_char	*ptr = seg;
54381623c4aSclaudio 	uint32_t	 as;
54481623c4aSclaudio 
54581623c4aSclaudio 	/* minimal pos check, return 0 since that is an invalid ASN */
54681623c4aSclaudio 	if (pos < 0 || pos >= ptr[1])
54781623c4aSclaudio 		return (0);
54881623c4aSclaudio 	ptr += 2 + sizeof(uint32_t) * pos;
54981623c4aSclaudio 	memcpy(&as, ptr, sizeof(uint32_t));
55081623c4aSclaudio 	return (ntohl(as));
55181623c4aSclaudio }
55281623c4aSclaudio 
55381623c4aSclaudio static struct aspath *
build_aspath(const uint32_t * asns,uint32_t asncnt,int rev)55481623c4aSclaudio build_aspath(const uint32_t *asns, uint32_t asncnt, int rev)
55581623c4aSclaudio {
55681623c4aSclaudio 	struct aspath *aspath;
55781623c4aSclaudio 	uint32_t i, idx, as;
55881623c4aSclaudio 	uint16_t len;
55981623c4aSclaudio 
56081623c4aSclaudio 	/* don't mess around with multi segment ASPATHs */
56181623c4aSclaudio 	if (asncnt >= 255)
56281623c4aSclaudio 		errx(1, "asncnt too big");
56381623c4aSclaudio 
56481623c4aSclaudio 	if (asncnt == 0)
56581623c4aSclaudio 		len = 0;
56681623c4aSclaudio 	else
56781623c4aSclaudio 		len = 2 + sizeof(uint32_t) * asncnt;
56881623c4aSclaudio 	aspath = malloc(ASPATH_HEADER_SIZE + len);
56981623c4aSclaudio 	 if (aspath == NULL)
57081623c4aSclaudio 		err(1, NULL);
57181623c4aSclaudio 
57281623c4aSclaudio 	aspath->len = len;
57381623c4aSclaudio 	aspath->ascnt = asncnt; /* lie but nothing cares */
57481623c4aSclaudio 	aspath->source_as = 0;
5759043a933Sclaudio 
5769043a933Sclaudio 	if (len == 0)
5779043a933Sclaudio 		return aspath;
5789043a933Sclaudio 
5799043a933Sclaudio 	if (rev)
5809043a933Sclaudio 		aspath->source_as = asns[asncnt - 1];
5819043a933Sclaudio 	else
58281623c4aSclaudio 		aspath->source_as = asns[0];
5839043a933Sclaudio 
58481623c4aSclaudio 	aspath->data[0] = AS_SEQUENCE;
58581623c4aSclaudio 	aspath->data[1] = asncnt;
58681623c4aSclaudio 	for (i = 0; i < asncnt; i++) {
58781623c4aSclaudio 		if (rev)
58881623c4aSclaudio 			idx = asncnt - 1 - i;
58981623c4aSclaudio 		else
59081623c4aSclaudio 			idx = i;
59181623c4aSclaudio 		as = htonl(asns[idx]);
59281623c4aSclaudio 		memcpy(aspath->data + 2 + sizeof(as) * i, &as,
59381623c4aSclaudio 		   sizeof(uint32_t));
59481623c4aSclaudio 	}
59581623c4aSclaudio 
59681623c4aSclaudio 	return aspath;
59781623c4aSclaudio }
59881623c4aSclaudio 
59981623c4aSclaudio static const char *
print_aspath(const uint32_t * asns,uint32_t asncnt)60081623c4aSclaudio print_aspath(const uint32_t *asns, uint32_t asncnt)
60181623c4aSclaudio {
60281623c4aSclaudio 	static char buf[1024];
60381623c4aSclaudio 	char b[16];
60481623c4aSclaudio 	uint32_t i;
60581623c4aSclaudio 
60681623c4aSclaudio 	strlcpy(buf, "", sizeof(buf));
60781623c4aSclaudio 	for (i = 0; i < asncnt; i++) {
60881623c4aSclaudio 		snprintf(b, sizeof(b), "%d", asns[i]);
60981623c4aSclaudio 		if (i > 0)
61081623c4aSclaudio 			strlcat(buf, " ", sizeof(buf));
61181623c4aSclaudio 		strlcat(buf, b, sizeof(buf));
61281623c4aSclaudio 	}
61381623c4aSclaudio 	return buf;
61481623c4aSclaudio }
61581623c4aSclaudio 
61681623c4aSclaudio static void
reverse_state(struct aspa_state * in,struct aspa_state * rev)61781623c4aSclaudio reverse_state(struct aspa_state *in, struct aspa_state *rev)
61881623c4aSclaudio {
61981623c4aSclaudio 	memset(rev, 0, sizeof(*rev));
62081623c4aSclaudio 	rev->nhops = in->nhops;
62181623c4aSclaudio 	rev->nup_p = in->nhops + 1 - in->ndown_p;
62281623c4aSclaudio 	if (in->ndown_u != 0)
62381623c4aSclaudio 		rev->nup_u = in->nhops + 1 - in->ndown_u;
62481623c4aSclaudio 	if (in->ndown_np != 0)
62581623c4aSclaudio 		rev->nup_np = in->nhops + 1 - in->ndown_np;
62681623c4aSclaudio 	rev->ndown_p = in->nhops + 1 - in->nup_p;
62781623c4aSclaudio 	if (in->nup_u != 0)
62881623c4aSclaudio 		rev->ndown_u = in->nhops + 1 - in->nup_u;
62981623c4aSclaudio 	if (in->nup_np != 0)
63081623c4aSclaudio 		rev->ndown_np = in->nhops + 1 - in->nup_np;
63181623c4aSclaudio }
63281623c4aSclaudio 
63381623c4aSclaudio static void
print_state(struct aspa_state * a,struct aspa_state * b)63481623c4aSclaudio print_state(struct aspa_state *a, struct aspa_state *b)
63581623c4aSclaudio {
63681623c4aSclaudio 	if (a->nhops != b->nhops)
63781623c4aSclaudio 		printf(" nhops %d != %d", a->nhops, b->nhops);
63881623c4aSclaudio 	if (a->nup_p != b->nup_p)
63981623c4aSclaudio 		printf(" nup_p %d != %d", a->nup_p, b->nup_p);
64081623c4aSclaudio 	if (a->nup_u != b->nup_u)
64181623c4aSclaudio 		printf(" nup_u %d != %d", a->nup_u, b->nup_u);
64281623c4aSclaudio 	if (a->nup_np != b->nup_np)
64381623c4aSclaudio 		printf(" nup_np %d != %d", a->nup_np, b->nup_np);
64481623c4aSclaudio 	if (a->ndown_p != b->ndown_p)
64581623c4aSclaudio 		printf(" ndown_p %d != %d", a->ndown_p, b->ndown_p);
64681623c4aSclaudio 	if (a->ndown_u != b->ndown_u)
64781623c4aSclaudio 		printf(" ndown_u %d != %d", a->ndown_u, b->ndown_u);
64881623c4aSclaudio 	if (a->ndown_np != b->ndown_np)
64981623c4aSclaudio 		printf(" ndown_np %d != %d", a->ndown_np, b->ndown_np);
65081623c4aSclaudio }
6510f5e1a03Sclaudio 
6520f5e1a03Sclaudio time_t
getmonotime(void)6530f5e1a03Sclaudio getmonotime(void)
6540f5e1a03Sclaudio {
6550f5e1a03Sclaudio 	return time(NULL);
6560f5e1a03Sclaudio }
657