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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
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"
45 /* need these to link in libbgp */
46 struct zebra_privs_t
*bgpd_privs
= NULL
;
47 struct thread_master
*master
= NULL
;
49 static int failed
= 0;
52 /* test segments to parse and validate, and use for other tests */
53 static struct test_segment
{
56 const u_char data
[1024];
58 #define SHOULD_PARSE 0
60 int parses
; /* whether it should parse or not */
61 as_t peek_for
; /* what peek_for_as4_capability should say */
63 /* AFI/SAFI validation */
74 "capability header, and no more",
75 {CAPABILITY_CODE_REFRESH
, 0x0},
82 "header, no data but length says there is",
90 "valid, with padding",
91 {CAPABILITY_CODE_REFRESH
, 0x2, 0x0, 0x0},
98 "violates minsize requirement",
99 {CAPABILITY_CODE_ORF
, 0x2, 0x0, 0x0},
103 {NULL
, NULL
, {0}, 0, 0},
106 static struct test_segment mp_segments
[] = {
110 {0x1, 0x4, 0x0, 0x1, 0x0, 0x1},
122 {0x1, 0x4, 0x0, 0x2, 0x0, 0x1},
135 {CAPABILITY_CODE_MP
, 0x4, 0x0, 0x1, 0x0, 0x2},
147 "MP IP6/MPLS-labeled VPN",
148 {CAPABILITY_CODE_MP
, 0x4, 0x0, 0x2, 0x0, 0x80},
161 {CAPABILITY_CODE_MP
, 0x4, 0x0, 0x2, 0x0, 0x4},
173 "MP IP4/MPLS-laveled VPN",
174 {CAPABILITY_CODE_MP
, 0x4, 0x0, 0x1, 0x0, 0x80},
186 "MP unknown AFI/SAFI",
187 {CAPABILITY_CODE_MP
, 0x4, 0x0, 0xa, 0x0, 0x81},
194 INVALID_AFI
, /* parses, but unknown */
199 "MP IP4/Unicast, length too short (< minimum)",
200 {CAPABILITY_CODE_MP
, 0x2, 0x0, 0x1, 0x0, 0x1},
207 "MP IP4/Unicast, length too long",
208 {CAPABILITY_CODE_MP
, 0x6, 0x0, 0x1, 0x0, 0x1},
217 {NULL
, NULL
, {0}, 0, 0}};
219 static struct test_segment misc_segments
[] =
224 "ORF, simple, single entry, single tuple",
225 {/* hdr */ CAPABILITY_CODE_ORF
, 0x7,
226 /* mpc */ 0x0, 0x1, 0x0, 0x1,
228 /* tuples */ 0x40, 0x3},
235 "ORF, multi entry/tuple",
237 /* hdr */ CAPABILITY_CODE_ORF
,
279 "ORF, multi entry/tuple, hdr length too short",
281 /* hdr */ CAPABILITY_CODE_ORF
,
318 SHOULD_ERR
, /* It should error on invalid
323 "ORF, multi entry/tuple, length too long",
366 "ORF, multi entry/tuple, entry number too long",
405 SHOULD_PARSE
, /* parses, but last few tuples should be
411 "ORF, multi entry/tuple, entry number too short",
450 SHOULD_PARSE
, /* Parses, but should get gibberish
456 "ORF, multi entry/tuple, padded to align",
502 {0x41, 0x4, 0xab, 0xcd, 0xef,
503 0x12}, /* AS: 2882400018 */
510 "AS4 capability: short",
511 {0x41, 0x4, 0xab, 0xcd, 0xef}, /* AS: 2882400018 */
517 "AS4 capability: long",
518 {0x41, 0x4, 0xab, 0xcd, 0xef, 0x12, 0x12},
527 /* hdr */ CAPABILITY_CODE_RESTART
, 0xe,
528 /* R-bit, time */ 0xf1, 0x12,
544 "GR capability, but header length too short",
547 /* R-bit, time */ 0xf1, 0x12,
558 15 /* array is 16 though */,
563 "GR capability, but header length too long",
566 /* R-bit, time */ 0xf1, 0x12,
582 "GR capability, but truncated",
585 /* R-bit, time */ 0xf1, 0x12,
601 "GR capability, but empty.",
610 "MP capability, but empty.",
619 "ORF capability, but empty.",
628 "AS4 capability, but empty.",
637 "Dynamic capability, but empty.",
646 "Dynamic capability (deprecated version)",
647 {CAPABILITY_CODE_DYNAMIC
, 0x0},
651 {NULL
, NULL
, {0}, 0, 0}};
653 /* DYNAMIC message */
654 struct test_segment dynamic_cap_msgs
[] = {
657 "Dynamic Capability Message, IP/Multicast",
658 {0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2},
660 SHOULD_PARSE
, /* horrible alignment, just as with ORF */
664 "Dynamic Capability Message, IP/Multicast, truncated",
665 {0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2},
671 "Dynamic Capability Message, IP/Multicast, padded",
672 {0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2, 0x0},
674 SHOULD_ERR
, /* No way to tell padding from data.. */
678 "Dynamic Capability Message, IP/Multicast, cap data padded",
679 {0x0, 0x1, 0x5, 0x0, 0x1, 0x0, 0x2, 0x0},
681 SHOULD_PARSE
, /* You can though add padding to the capability
686 "Dynamic Capability Message, IP/Multicast, cap data != length",
687 {0x0, 0x1, 0x3, 0x0, 0x1, 0x0, 0x2, 0x0},
691 {NULL
, NULL
, {0}, 0, 0}};
693 /* Entire Optional-Parameters block */
694 struct test_segment opt_params
[] = {
697 "One capability per Optional-Param",
699 0x02, 0x06, 0x01, 0x04,
700 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
701 0x02, 0x06, 0x01, 0x04,
702 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
703 0x02, 0x02, 0x80, 0x00, /* RR (old) */
704 0x02, 0x02, 0x02, 0x00, /* RR */
711 "Series of capability, one Optional-Param",
713 0x02, 0x10, 0x01, 0x04, 0x00, 0x01, 0x00,
714 0x01, /* MP IPv4/Uni */
715 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
716 0x80, 0x00, /* RR (old) */
724 "AS4 capability after other caps (singlets)",
726 0x02, 0x06, 0x01, 0x04,
727 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
728 0x02, 0x06, 0x01, 0x04,
729 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
730 0x02, 0x02, 0x80, 0x00, /* RR (old) */
731 0x02, 0x02, 0x02, 0x00, /* RR */
732 0x02, 0x06, 0x41, 0x04,
733 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */
741 "AS4 capability, in series of capabilities",
743 0x02, 0x16, 0x01, 0x04, 0x00, 0x01,
744 0x00, 0x01, /* MP IPv4/Uni */
745 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
746 0x80, 0x00, /* RR (old) */
748 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */
756 "AS4 capability, in series of capabilities",
758 0x02, 0x06, 0x01, 0x04,
759 0x00, 0x01, 0x00, 0x01, /* MP IPv4/uni */
760 0x02, 0x06, 0x01, 0x04,
761 0x00, 0x02, 0x00, 0x01, /* MP IPv6/uni */
762 0x02, 0x02, 0x80, 0x00, /* RR old */
763 0x02, 0x02, 0x02, 0x00, /* RR */
764 0x02, 0x06, 0x41, 0x04,
765 0x00, 0x03, 0x00, 0x06, /* AS4 */
773 "AS4 capability, in series of capabilities",
775 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02,
776 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02,
777 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x06, 0x41,
778 0x04, 0x00, 0x00, 0xfc, 0x03, 0x02, 0x09, 0x82, 0x07,
779 0x00, 0x01, 0x00, 0x01, 0x01, 0x80, 0x03, 0x02, 0x09,
780 0x03, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x40, 0x03,
781 0x02, 0x02, 0x42, 0x00,
788 {NULL
, NULL
, {0}, 0, 0}};
790 /* basic parsing test */
791 static void parse_test(struct peer
*peer
, struct test_segment
*t
, int type
)
796 int oldfailed
= failed
;
798 #define RANDOM_FUZZ 35
799 stream_reset(peer
->ibuf
);
800 stream_put(peer
->ibuf
, NULL
, RANDOM_FUZZ
);
801 stream_set_getp(peer
->ibuf
, RANDOM_FUZZ
);
805 stream_putc(peer
->ibuf
, BGP_OPEN_OPT_CAP
);
806 stream_putc(peer
->ibuf
, t
->len
);
809 /* for (i = 0; i < BGP_MARKER_SIZE; i++)
810 stream_putc (peer->, 0xff);
812 stream_putc (s, BGP_MSG_CAPABILITY);*/
815 stream_write(peer
->ibuf
, t
->data
, t
->len
);
817 printf("%s: %s\n", t
->name
, t
->desc
);
821 len
+= 2; /* to cover the OPT-Param header */
823 printf("len: %u\n", len
);
824 /* peek_for_as4 wants getp at capibility*/
825 as4
= peek_for_as4_capability(peer
, len
);
826 printf("peek_for_as4: as4 is %u\n", as4
);
827 /* and it should leave getp as it found it */
828 assert(stream_get_getp(peer
->ibuf
) == RANDOM_FUZZ
);
830 ret
= bgp_open_option_parse(peer
, len
, &capability
);
833 ret
= bgp_capability_receive(peer
, t
->len
);
836 printf("unknown type %u\n", type
);
840 if (!ret
&& t
->validate_afi
) {
844 /* Convert AFI, SAFI to internal values, check. */
845 if (bgp_map_afi_safi_iana2int(afi_int2iana(t
->afi
), t
->safi
,
847 if (t
->afi_valid
== VALID_AFI
)
850 printf("MP: %u(%u)/%u(%u): recv %u, nego %u\n", t
->afi
, afi
,
851 t
->safi
, safi
, peer
->afc_recv
[afi
][safi
],
852 peer
->afc_nego
[afi
][safi
]);
854 if (t
->afi_valid
== VALID_AFI
) {
856 if (!peer
->afc_recv
[afi
][safi
])
858 if (!peer
->afc_nego
[afi
][safi
])
863 if (as4
!= t
->peek_for
) {
864 printf("as4 %u != %u\n", as4
, t
->peek_for
);
868 printf("parsed?: %s\n", ret
? "no" : "yes");
870 if (ret
!= t
->parses
)
875 (failed
> oldfailed
) ? VT100_RED
"failed!" VT100_RESET
876 : VT100_GREEN
"OK" VT100_RESET
);
878 printf("%s", (failed
> oldfailed
) ? "failed!" : "OK");
881 printf(" (%u)", failed
);
886 static struct bgp
*bgp
;
887 static as_t asn
= 100;
894 conf_bgp_debug_neighbor_events
= -1UL;
895 conf_bgp_debug_packet
= -1UL;
896 conf_bgp_debug_as4
= -1UL;
897 term_bgp_debug_neighbor_events
= -1UL;
898 term_bgp_debug_packet
= -1UL;
899 term_bgp_debug_as4
= -1UL;
902 master
= thread_master_create(NULL
);
903 bgp_master_init(master
);
904 vrf_init(NULL
, NULL
, NULL
, NULL
);
905 bgp_option_set(BGP_OPT_NO_LISTEN
);
907 if (fileno(stdout
) >= 0)
908 tty
= isatty(fileno(stdout
));
910 if (bgp_get(&bgp
, &asn
, NULL
, BGP_INSTANCE_TYPE_DEFAULT
))
913 peer
= peer_create_accept(bgp
);
914 peer
->host
= (char *)"foo";
916 for (i
= AFI_IP
; i
< AFI_MAX
; i
++)
917 for (j
= SAFI_UNICAST
; j
< SAFI_MAX
; j
++) {
919 peer
->afc_adv
[i
][j
] = 1;
923 while (mp_segments
[i
].name
)
924 parse_test(peer
, &mp_segments
[i
++], CAPABILITY
);
926 /* These tests assume mp_segments tests set at least
927 * one of the afc_nego's
930 while (test_segments
[i
].name
)
931 parse_test(peer
, &test_segments
[i
++], CAPABILITY
);
934 while (misc_segments
[i
].name
)
935 parse_test(peer
, &misc_segments
[i
++], CAPABILITY
);
938 while (opt_params
[i
].name
)
939 parse_test(peer
, &opt_params
[i
++], OPT_PARAM
);
941 SET_FLAG(peer
->cap
, PEER_CAP_DYNAMIC_ADV
);
942 peer
->status
= Established
;
945 while (dynamic_cap_msgs
[i
].name
)
946 parse_test(peer
, &dynamic_cap_msgs
[i
++], DYNCAP
);
948 printf("failures: %d\n", failed
);