2 * Copyright (C) 2007 Sun Microsystems, Inc.
4 * This file is part of Quagga.
6 * Quagga is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * Quagga is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Quagga; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31 #include "bgpd/bgpd.h"
32 #include "bgpd/bgp_open.h"
33 #include "bgpd/bgp_debug.h"
34 #include "bgpd/bgp_packet.h"
36 #define VT100_RESET "\x1b[0m"
37 #define VT100_RED "\x1b[31m"
38 #define VT100_GREEN "\x1b[32m"
39 #define VT100_YELLOW "\x1b[33m"
46 /* need these to link in libbgp */
47 struct zebra_privs_t
*bgpd_privs
= NULL
;
48 struct thread_master
*master
= NULL
;
50 static int failed
= 0;
53 /* test segments to parse and validate, and use for other tests */
54 static struct test_segment
{
57 const u_char data
[1024];
59 #define SHOULD_PARSE 0
61 int parses
; /* whether it should parse or not */
62 as_t peek_for
; /* what peek_for_as4_capability should say */
64 /* AFI/SAFI validation */
75 "capability header, and no more",
76 { CAPABILITY_CODE_REFRESH
, 0x0 },
81 "header, no data but length says there is",
87 "valid, with padding",
88 { CAPABILITY_CODE_REFRESH
, 0x2, 0x0, 0x0 },
93 "violates minsize requirement",
94 { CAPABILITY_CODE_ORF
, 0x2, 0x0, 0x0 },
97 { NULL
, NULL
, {0}, 0, 0},
100 static struct test_segment mp_segments
[] =
104 { 0x1, 0x4, 0x0, 0x1, 0x0, 0x1 },
106 1, AFI_IP
, SAFI_UNICAST
, VALID_AFI
,
110 { 0x1, 0x4, 0x0, 0x2, 0x0, 0x1 },
112 1, AFI_IP6
, SAFI_UNICAST
, VALID_AFI
,
117 { CAPABILITY_CODE_MP
, 0x4, 0x0, 0x1, 0x0, 0x2 },
119 1, AFI_IP
, SAFI_MULTICAST
, VALID_AFI
,
123 "MP IP6/MPLS-labeled VPN",
124 { CAPABILITY_CODE_MP
, 0x4, 0x0, 0x2, 0x0, 0x80 },
126 1, AFI_IP6
, SAFI_MPLS_LABELED_VPN
, VALID_AFI
,
131 { CAPABILITY_CODE_MP
, 0x4, 0x0, 0x2, 0x0, 0x4 },
133 1, AFI_IP6
, SAFI_MPLS_VPN
, VALID_AFI
,
137 "MP IP4/MPLS-laveled VPN",
138 { CAPABILITY_CODE_MP
, 0x4, 0x0, 0x1, 0x0, 0x80 },
140 1, AFI_IP
, SAFI_MPLS_LABELED_VPN
, VALID_AFI
,
144 "MP unknown AFI/SAFI",
145 { CAPABILITY_CODE_MP
, 0x4, 0x0, 0xa, 0x0, 0x81 },
147 1, 0xa, 0x81, INVALID_AFI
, /* parses, but unknown */
151 "MP IP4/Unicast, length too short (< minimum)",
152 { CAPABILITY_CODE_MP
, 0x2, 0x0, 0x1, 0x0, 0x1 },
157 "MP IP4/Unicast, length too long",
158 { CAPABILITY_CODE_MP
, 0x6, 0x0, 0x1, 0x0, 0x1 },
160 1, AFI_IP
, SAFI_UNICAST
, VALID_AFI
,
162 { NULL
, NULL
, {0}, 0, 0}
165 static struct test_segment misc_segments
[] =
169 "ORF, simple, single entry, single tuple",
170 { /* hdr */ CAPABILITY_CODE_ORF
, 0x7,
171 /* mpc */ 0x0, 0x1, 0x0, 0x1,
173 /* tuples */ 0x40, 0x3
179 "ORF, multi entry/tuple",
180 { /* hdr */ CAPABILITY_CODE_ORF
, 0x21,
181 /* mpc */ 0x0, 0x1, 0x0, 0x1,
183 /* tuples */ 0x40, ORF_MODE_BOTH
,
184 0x80, ORF_MODE_RECEIVE
,
186 /* mpc */ 0x0, 0x2, 0x0, 0x1,
188 /* tuples */ 0x40, ORF_MODE_BOTH
,
189 0x80, ORF_MODE_RECEIVE
,
191 /* mpc */ 0x0, 0x2, 0x0, 0x2,
193 /* tuples */ 0x40, ORF_MODE_RECEIVE
,
201 "ORF, multi entry/tuple, hdr length too short",
202 { /* hdr */ CAPABILITY_CODE_ORF
, 0x15,
203 /* mpc */ 0x0, 0x1, 0x0, 0x1,
205 /* tuples */ 0x40, 0x3,
208 /* mpc */ 0x0, 0x1, 0x0, 0x1,
210 /* tuples */ 0x40, 0x3,
213 /* mpc */ 0x0, 0x2, 0x0, 0x2,
215 /* tuples */ 0x40, 0x3,
219 35, SHOULD_ERR
, /* It should error on invalid Route-Refresh.. */
223 "ORF, multi entry/tuple, length too long",
224 { /* hdr */ 0x3, 0x22,
225 /* mpc */ 0x0, 0x1, 0x0, 0x1,
227 /* tuples */ 0x40, 0x3,
230 /* mpc */ 0x0, 0x2, 0x0, 0x1,
232 /* tuples */ 0x40, 0x3,
235 /* mpc */ 0x0, 0x2, 0x0, 0x2,
237 /* tuples */ 0x40, 0x3,
245 "ORF, multi entry/tuple, entry number too long",
246 { /* hdr */ 0x3, 0x21,
247 /* mpc */ 0x0, 0x1, 0x0, 0x1,
249 /* tuples */ 0x40, 0x3,
252 /* mpc */ 0x0, 0x2, 0x0, 0x1,
254 /* tuples */ 0x40, 0x3,
257 /* mpc */ 0x0, 0x2, 0x0, 0x2,
259 /* tuples */ 0x40, 0x3,
263 35, SHOULD_PARSE
, /* parses, but last few tuples should be gibberish */
267 "ORF, multi entry/tuple, entry number too short",
268 { /* hdr */ 0x3, 0x21,
269 /* mpc */ 0x0, 0x1, 0x0, 0x1,
271 /* tuples */ 0x40, 0x3,
274 /* mpc */ 0x0, 0x2, 0x0, 0x1,
276 /* tuples */ 0x40, 0x3,
279 /* mpc */ 0x0, 0x2, 0x0, 0x2,
281 /* tuples */ 0x40, 0x3,
285 35, SHOULD_PARSE
, /* Parses, but should get gibberish afi/safis */
289 "ORF, multi entry/tuple, padded to align",
290 { /* hdr */ 0x3, 0x22,
291 /* mpc */ 0x0, 0x1, 0x0, 0x1,
293 /* tuples */ 0x40, 0x3,
296 /* mpc */ 0x0, 0x2, 0x0, 0x1,
298 /* tuples */ 0x40, 0x3,
301 /* mpc */ 0x0, 0x2, 0x0, 0x2,
303 /* tuples */ 0x40, 0x3,
313 { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, /* AS: 2882400018 */
314 6, SHOULD_PARSE
, 2882400018,
317 "AS4 capability: short",
318 { 0x41, 0x4, 0xab, 0xcd, 0xef }, /* AS: 2882400018 */
322 "AS4 capability: long",
323 { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12, 0x12 },
324 7, SHOULD_ERR
, 2882400018,
328 { /* hdr */ CAPABILITY_CODE_RESTART
, 0xe,
329 /* R-bit, time */ 0xf1, 0x12,
343 "GR capability, but header length too short",
344 { /* hdr */ 0x40, 0xa,
345 /* R-bit, time */ 0xf1, 0x12,
356 15 /* array is 16 though */, SHOULD_ERR
,
359 "GR capability, but header length too long",
360 { /* hdr */ 0x40, 0xf,
361 /* R-bit, time */ 0xf1, 0x12,
375 "GR capability, but truncated",
376 { /* hdr */ 0x40, 0xf,
377 /* R-bit, time */ 0xf1, 0x12,
391 "GR capability, but empty.",
392 { /* hdr */ 0x40, 0x0,
397 "MP capability, but empty.",
398 { /* hdr */ 0x1, 0x0,
403 "ORF capability, but empty.",
404 { /* hdr */ 0x3, 0x0,
409 "AS4 capability, but empty.",
410 { /* hdr */ 0x41, 0x0,
415 "Dynamic capability, but empty.",
416 { /* hdr */ 0x42, 0x0,
421 "Dynamic capability (deprecated version)",
422 { CAPABILITY_CODE_DYNAMIC
, 0x0 },
425 { NULL
, NULL
, {0}, 0, 0}
428 /* DYNAMIC message */
429 struct test_segment dynamic_cap_msgs
[] =
432 "Dynamic Capability Message, IP/Multicast",
433 { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2 },
434 7, SHOULD_PARSE
, /* horrible alignment, just as with ORF */
437 "Dynamic Capability Message, IP/Multicast, truncated",
438 { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2 },
442 "Dynamic Capability Message, IP/Multicast, padded",
443 { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2, 0x0 },
444 8, SHOULD_ERR
, /* No way to tell padding from data.. */
447 "Dynamic Capability Message, IP/Multicast, cap data padded",
448 { 0x0, 0x1, 0x5, 0x0, 0x1, 0x0, 0x2, 0x0 },
449 8, SHOULD_PARSE
, /* You can though add padding to the capability data */
451 { "DynCapMPCoverflow",
452 "Dynamic Capability Message, IP/Multicast, cap data != length",
453 { 0x0, 0x1, 0x3, 0x0, 0x1, 0x0, 0x2, 0x0 },
456 { NULL
, NULL
, {0}, 0, 0}
459 /* Entire Optional-Parameters block */
460 struct test_segment opt_params
[] =
463 "One capability per Optional-Param",
464 { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
465 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
466 0x02, 0x02, 0x80, 0x00, /* RR (old) */
467 0x02, 0x02, 0x02, 0x00, /* RR */
472 "Series of capability, one Optional-Param",
474 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
475 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
476 0x80, 0x00, /* RR (old) */
482 "AS4 capability after other caps (singlets)",
483 { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
484 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
485 0x02, 0x02, 0x80, 0x00, /* RR (old) */
486 0x02, 0x02, 0x02, 0x00, /* RR */
487 0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */
489 32, SHOULD_PARSE
, 196614,
492 "AS4 capability, in series of capabilities",
494 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
495 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
496 0x80, 0x00, /* RR (old) */
498 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */
500 24, SHOULD_PARSE
, 196614,
503 "AS4 capability, in series of capabilities",
505 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/uni */
506 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/uni */
507 0x02, 0x02, 0x80, 0x00, /* RR old */
508 0x02, 0x02, 0x02, 0x00, /* RR */
509 0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06, /* AS4 */
511 32, SHOULD_PARSE
, 196614,
514 "AS4 capability, in series of capabilities",
516 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01,
517 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01,
518 0x02, 0x02, 0x80, 0x00,
519 0x02, 0x02, 0x02, 0x00,
520 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0xfc, 0x03,
521 0x02, 0x09, 0x82, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x80, 0x03,
522 0x02, 0x09, 0x03, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x40, 0x03,
523 0x02, 0x02, 0x42, 0x00,
525 58, SHOULD_PARSE
, 64515,
528 { NULL
, NULL
, {0}, 0, 0}
531 /* basic parsing test */
533 parse_test (struct peer
*peer
, struct test_segment
*t
, int type
)
538 int oldfailed
= failed
;
540 #define RANDOM_FUZZ 35
542 stream_reset (peer
->ibuf
);
543 stream_put (peer
->ibuf
, NULL
, RANDOM_FUZZ
);
544 stream_set_getp (peer
->ibuf
, RANDOM_FUZZ
);
549 stream_putc (peer
->ibuf
, BGP_OPEN_OPT_CAP
);
550 stream_putc (peer
->ibuf
, t
->len
);
553 /* for (i = 0; i < BGP_MARKER_SIZE; i++)
554 stream_putc (peer->, 0xff);
556 stream_putc (s, BGP_MSG_CAPABILITY);*/
559 stream_write (peer
->ibuf
, t
->data
, t
->len
);
561 printf ("%s: %s\n", t
->name
, t
->desc
);
566 len
+= 2; /* to cover the OPT-Param header */
568 printf ("len: %u\n", len
);
569 /* peek_for_as4 wants getp at capibility*/
570 as4
= peek_for_as4_capability (peer
, len
);
571 printf ("peek_for_as4: as4 is %u\n", as4
);
572 /* and it should leave getp as it found it */
573 assert (stream_get_getp (peer
->ibuf
) == RANDOM_FUZZ
);
575 ret
= bgp_open_option_parse (peer
, len
, &capability
);
578 ret
= bgp_capability_receive (peer
, t
->len
);
581 printf ("unknown type %u\n", type
);
585 if (!ret
&& t
->validate_afi
)
587 safi_t safi
= t
->safi
;
589 if (bgp_afi_safi_valid_indices (t
->afi
, &safi
) != t
->afi_valid
)
592 printf ("MP: %u/%u (%u): recv %u, nego %u\n",
593 t
->afi
, t
->safi
, safi
,
594 peer
->afc_recv
[t
->afi
][safi
],
595 peer
->afc_nego
[t
->afi
][safi
]);
597 if (t
->afi_valid
== VALID_AFI
)
600 if (!peer
->afc_recv
[t
->afi
][safi
])
602 if (!peer
->afc_nego
[t
->afi
][safi
])
607 if (as4
!= t
->peek_for
)
609 printf ("as4 %u != %u\n", as4
, t
->peek_for
);
613 printf ("parsed?: %s\n", ret
? "no" : "yes");
615 if (ret
!= t
->parses
)
619 printf ("%s", (failed
> oldfailed
) ? VT100_RED
"failed!" VT100_RESET
620 : VT100_GREEN
"OK" VT100_RESET
);
622 printf ("%s", (failed
> oldfailed
) ? "failed!" : "OK" );
625 printf (" (%u)", failed
);
630 static struct bgp
*bgp
;
631 static as_t asn
= 100;
639 conf_bgp_debug_neighbor_events
= -1UL;
640 conf_bgp_debug_packet
= -1UL;
641 conf_bgp_debug_as4
= -1UL;
642 term_bgp_debug_neighbor_events
= -1UL;
643 term_bgp_debug_packet
= -1UL;
644 term_bgp_debug_as4
= -1UL;
646 master
= thread_master_create ();
649 bgp_option_set (BGP_OPT_NO_LISTEN
);
651 if (fileno (stdout
) >= 0)
652 tty
= isatty (fileno (stdout
));
654 if (bgp_get (&bgp
, &asn
, NULL
, BGP_INSTANCE_TYPE_DEFAULT
))
657 peer
= peer_create_accept (bgp
);
658 peer
->host
= (char *) "foo";
660 for (i
= AFI_IP
; i
< AFI_MAX
; i
++)
661 for (j
= SAFI_UNICAST
; j
< SAFI_MAX
; j
++)
664 peer
->afc_adv
[i
][j
] = 1;
668 while (mp_segments
[i
].name
)
669 parse_test (peer
, &mp_segments
[i
++], CAPABILITY
);
671 /* These tests assume mp_segments tests set at least
672 * one of the afc_nego's
675 while (test_segments
[i
].name
)
676 parse_test (peer
, &test_segments
[i
++], CAPABILITY
);
679 while (misc_segments
[i
].name
)
680 parse_test (peer
, &misc_segments
[i
++], CAPABILITY
);
683 while (opt_params
[i
].name
)
684 parse_test (peer
, &opt_params
[i
++], OPT_PARAM
);
686 SET_FLAG (peer
->cap
, PEER_CAP_DYNAMIC_ADV
);
687 peer
->status
= Established
;
690 while (dynamic_cap_msgs
[i
].name
)
691 parse_test (peer
, &dynamic_cap_msgs
[i
++], DYNCAP
);
693 printf ("failures: %d\n", failed
);