2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.parser.impl;
10 import static org.junit.Assert.assertArrayEquals;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertThat;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.junit.matchers.JUnitMatchers.containsString;
18 import com.google.common.collect.Lists;
19 import com.google.common.collect.Maps;
21 import io.netty.buffer.Unpooled;
23 import java.net.UnknownHostException;
24 import java.util.Arrays;
25 import java.util.List;
28 import org.junit.BeforeClass;
29 import org.junit.Test;
30 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
31 import org.opendaylight.protocol.bgp.parser.BGPError;
32 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
33 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
34 import org.opendaylight.protocol.bgp.parser.spi.MessageRegistry;
35 import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext;
36 import org.opendaylight.protocol.util.ByteArray;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateAddressFamily;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateSubsequentAddressFamily;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Keepalive;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.KeepaliveBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Notify;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.NotifyBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Open;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.OpenBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.ProtocolVersion;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParametersBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.MultiprotocolCaseBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.multiprotocol._case.MultiprotocolCapabilityBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
54 import org.opendaylight.yangtools.yang.binding.Notification;
56 public class ParserTest {
58 public static final byte[] openBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
59 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
60 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0x14, (byte) 0x14,
61 (byte) 0x14, (byte) 0x14, (byte) 0x00 };
63 public static final byte[] keepAliveBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
64 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
65 (byte) 0x00, (byte) 0x13, (byte) 0x04 };
67 public static final byte[] notificationBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
68 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
69 (byte) 0xff, (byte) 0x00, (byte) 0x17, (byte) 0x03, (byte) 0x02, (byte) 0x04, (byte) 0x04, (byte) 0x09 };
71 public static final byte[] openWithCpblt1 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
72 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
73 (byte) 0x00, (byte) 0x2d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x48, (byte) 0x00, (byte) 0xb4, (byte) 0xac, (byte) 0x14,
74 (byte) 0xa0, (byte) 0xaa, (byte) 0x10, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00,
75 (byte) 0x01, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x40, (byte) 0x04, (byte) 0x00, (byte) 0x47 };
77 public static final byte[] openWithCpblt2 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
78 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
79 (byte) 0x00, (byte) 0x2d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x48, (byte) 0x00, (byte) 0xb4, (byte) 0xac, (byte) 0x14,
80 (byte) 0xa0, (byte) 0xaa, (byte) 0x10, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x40, (byte) 0x04, (byte) 0x00,
81 (byte) 0x47, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01 };
83 static MessageRegistry reg;
86 public static void setupClass() throws Exception {
87 reg = ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getMessageRegistry();
91 public void testHeaderErrors() throws BGPParsingException, BGPDocumentedException {
92 byte[] wrong = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
93 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00 };
94 wrong = ByteArray.cutBytes(wrong, 16);
96 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(wrong));
97 fail("Exception should have occcured.");
98 } catch (final IllegalArgumentException e) {
99 assertEquals("Too few bytes in passed array. Passed: " + wrong.length + ". Expected: >= 19.", e.getMessage());
106 public void testBadMsgType() throws BGPParsingException {
107 final byte[] bytes = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
108 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
109 (byte) 0x00, (byte) 0x13, (byte) 0x08 };
111 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
112 fail("Exception should have occured.");
113 } catch (final BGPDocumentedException e) {
114 assertEquals(BGPError.BAD_MSG_TYPE, e.getError());
121 public void testKeepAliveMsg() throws BGPParsingException, BGPDocumentedException {
122 final Notification keepAlive = new KeepaliveBuilder().build();
123 final byte[] bytes = ParserTest.reg.serializeMessage(keepAlive);
124 assertArrayEquals(keepAliveBMsg, bytes);
126 final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
128 assertTrue(m instanceof Keepalive);
132 public void testBadKeepAliveMsg() throws BGPParsingException {
133 final byte[] bytes = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
134 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
135 (byte) 0x00, (byte) 0x14, (byte) 0x04, (byte) 0x05 };
138 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
139 fail("Exception should have occured.");
140 } catch (final BGPDocumentedException e) {
141 assertThat(e.getMessage(), containsString("Message length field not within valid range."));
142 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
149 public void testOpenMessage() throws UnknownHostException, BGPParsingException, BGPDocumentedException {
150 final Notification open = new OpenBuilder().setMyAsNumber(100).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("20.20.20.20")).setVersion(
151 new ProtocolVersion((short) 4)).build();
152 final byte[] bytes = ParserTest.reg.serializeMessage(open);
153 assertArrayEquals(openBMsg, bytes);
155 final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
157 assertTrue(m instanceof Open);
158 assertEquals(100, ((Open) m).getMyAsNumber().intValue());
159 assertEquals(180, ((Open) m).getHoldTimer().intValue());
160 assertEquals(new Ipv4Address("20.20.20.20"), ((Open) m).getBgpIdentifier());
161 assertTrue(((Open) m).getBgpParameters().isEmpty());
165 public void testBadHoldTimeError() throws BGPParsingException {
166 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
167 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
168 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x01, (byte) 0x14,
169 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
172 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
173 fail("Exception should have occured.");
174 } catch (final BGPDocumentedException e) {
175 assertEquals("Hold time value not acceptable.", e.getMessage());
176 assertEquals(BGPError.HOLD_TIME_NOT_ACC, e.getError());
183 public void testBadMsgLength() throws BGPParsingException {
184 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
185 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
186 (byte) 0x00, (byte) 0x1b, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0xff,
187 (byte) 0xff, (byte) 0xff };
190 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
191 fail("Exception should have occured.");
192 } catch (final BGPDocumentedException e) {
193 assertEquals("Open message too small.", e.getMessage());
194 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
199 public void testBadVersion() throws BGPParsingException {
200 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
201 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
202 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x08, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0x14,
203 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
206 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
207 fail("Exception should have occured.");
208 } catch (final BGPDocumentedException e) {
209 assertEquals("BGP Protocol version 8 not supported.", e.getMessage());
210 assertEquals(BGPError.VERSION_NOT_SUPPORTED, e.getError());
217 public void testNotificationMsg() throws BGPParsingException, BGPDocumentedException {
218 Notification notMsg = new NotifyBuilder().setErrorCode(BGPError.OPT_PARAM_NOT_SUPPORTED.getCode()).setErrorSubcode(
219 BGPError.OPT_PARAM_NOT_SUPPORTED.getSubcode()).setData(new byte[] { 4, 9 }).build();
220 byte[] bytes = ParserTest.reg.serializeMessage(notMsg);
221 assertArrayEquals(notificationBMsg, bytes);
223 Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
225 assertTrue(m instanceof Notify);
226 assertEquals(BGPError.OPT_PARAM_NOT_SUPPORTED, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
227 assertArrayEquals(new byte[] { 4, 9 }, ((Notify) m).getData());
229 notMsg = new NotifyBuilder().setErrorCode(BGPError.CONNECTION_NOT_SYNC.getCode()).setErrorSubcode(
230 BGPError.CONNECTION_NOT_SYNC.getSubcode()).build();
231 bytes = ParserTest.reg.serializeMessage(notMsg);
233 m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
235 assertTrue(m instanceof Notify);
236 assertEquals(BGPError.CONNECTION_NOT_SYNC, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
237 assertNull(((Notify) m).getData());
241 public void testWrongLength() throws BGPParsingException {
242 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
243 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
244 (byte) 0x00, (byte) 0x14, (byte) 0x03, (byte) 0x02 };
247 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
248 fail("Exception should have occured.");
249 } catch (final BGPDocumentedException e) {
250 assertEquals("Notification message too small.", e.getMessage());
251 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
258 public void testUnrecognizedError() throws BGPParsingException, BGPDocumentedException {
259 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
260 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
261 (byte) 0x00, (byte) 0x15, (byte) 0x03, (byte) 0x02, (byte) 0xaa };
264 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
265 fail("Exception should have occured.");
266 } catch (final IllegalArgumentException e) {
267 assertEquals("BGP Error code 2 and subcode 170 not recognized.", e.getMessage());
274 public void testTLVParser() throws UnknownHostException {
276 final BgpTableType t1 = new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
277 final BgpTableType t2 = new BgpTableTypeImpl(LinkstateAddressFamily.class, UnicastSubsequentAddressFamily.class);
279 final List<BgpParameters> tlvs = Lists.newArrayList();
281 tlvs.add(new BgpParametersBuilder().setCParameters(
282 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
283 new MultiprotocolCapabilityBuilder().setAfi(LinkstateAddressFamily.class).setSafi(
284 LinkstateSubsequentAddressFamily.class).build()).build()).build());
285 tlvs.add(new BgpParametersBuilder().setCParameters(
286 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
287 new MultiprotocolCapabilityBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).build()).build()).build());
289 final Map<BgpTableType, Boolean> tableTypes = Maps.newHashMap();
290 tableTypes.put(t1, true);
291 tableTypes.put(t2, true);
292 final Open open = new OpenBuilder().setMyAsNumber(72).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("172.20.160.170")).setVersion(
293 new ProtocolVersion((short) 4)).setBgpParameters(tlvs).build();
295 final byte[] result = ParserTest.reg.serializeMessage(open);
297 // the capabilities can be swapped.
298 assertTrue(Arrays.equals(openWithCpblt1, result) || Arrays.equals(openWithCpblt2, result));