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;
20 import io.netty.buffer.ByteBuf;
21 import io.netty.buffer.Unpooled;
22 import java.net.UnknownHostException;
23 import java.util.Arrays;
24 import java.util.List;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
29 import org.opendaylight.protocol.bgp.parser.BGPError;
30 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
31 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
32 import org.opendaylight.protocol.bgp.parser.spi.MessageRegistry;
33 import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext;
34 import org.opendaylight.protocol.util.ByteArray;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateAddressFamily;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateSubsequentAddressFamily;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Keepalive;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.KeepaliveBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Notify;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.NotifyBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Open;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.OpenBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.ProtocolVersion;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParametersBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.MultiprotocolCaseBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.multiprotocol._case.MultiprotocolCapabilityBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
52 import org.opendaylight.yangtools.yang.binding.Notification;
54 public class ParserTest {
56 public static final byte[] openBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
57 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
58 (byte) 0xff, (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4,
59 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
61 public static final byte[] keepAliveBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
62 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
63 (byte) 0xff, (byte) 0x00, (byte) 0x13, (byte) 0x04 };
65 public static final byte[] notificationBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
66 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
67 (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x17, (byte) 0x03, (byte) 0x02, (byte) 0x04, (byte) 0x04, (byte) 0x09 };
69 public static final byte[] openWithCpblt1 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
70 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
71 (byte) 0xff, (byte) 0x00, (byte) 0x2d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x48, (byte) 0x00, (byte) 0xb4,
72 (byte) 0xac, (byte) 0x14, (byte) 0xa0, (byte) 0xaa, (byte) 0x10, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04,
73 (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x40,
74 (byte) 0x04, (byte) 0x00, (byte) 0x47 };
76 public static final byte[] openWithCpblt2 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
77 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
78 (byte) 0xff, (byte) 0x00, (byte) 0x2d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x48, (byte) 0x00, (byte) 0xb4,
79 (byte) 0xac, (byte) 0x14, (byte) 0xa0, (byte) 0xaa, (byte) 0x10, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04,
80 (byte) 0x40, (byte) 0x04, (byte) 0x00, (byte) 0x47, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x00,
81 (byte) 0x01, (byte) 0x00, (byte) 0x01 };
83 public static final byte[] updateMsg = {
84 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
85 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x51, 0x02, 0x00, 0x00, 0x00, 0x36, 0x40, 0x01, 0x01, 0x00, 0x40, 0x02,
86 0x1a, 0x02, 0x06, 0x00, 0x00, (byte) 0xfe, 0x55, 0x00, 0x00, (byte) 0xfc, 0x12, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x02, (byte) 0xbd, 0x00, 0x00, 0x0d, 0x1c, 0x00, 0x00, 0x6a, 0x74, 0x40, 0x03,
87 0x04, 0x0a, 0x20, 0x00, (byte) 0xfe, (byte) 0x80, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x04, 0x00, 0x00, 0x00, 0x64, 0x18, (byte) 0xa8, (byte) 0xa1, (byte) 0xf7
90 static MessageRegistry reg;
93 public static void setupClass() throws Exception {
94 reg = ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getMessageRegistry();
98 public void testHeaderErrors() throws BGPParsingException, BGPDocumentedException {
99 byte[] wrong = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00 };
100 wrong = ByteArray.cutBytes(wrong, 16);
102 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(wrong));
103 fail("Exception should have occcured.");
104 } catch (final IllegalArgumentException e) {
105 assertEquals("Too few bytes in passed array. Passed: " + wrong.length + ". Expected: >= 19.", e.getMessage());
112 public void testBadMsgType() throws BGPParsingException {
113 final byte[] bytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
114 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
115 (byte) 0x00, (byte) 0x13, (byte) 0x08 };
117 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
118 fail("Exception should have occured.");
119 } catch (final BGPDocumentedException e) {
120 assertEquals(BGPError.BAD_MSG_TYPE, e.getError());
127 public void testKeepAliveMsg() throws BGPParsingException, BGPDocumentedException {
128 final Notification keepAlive = new KeepaliveBuilder().build();
129 ByteBuf buffer = Unpooled.buffer();
130 ParserTest.reg.serializeMessage(keepAlive, buffer);
131 assertArrayEquals(keepAliveBMsg, ByteArray.getAllBytes(buffer));
133 final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(ByteArray.getAllBytes(buffer)));
135 assertTrue(m instanceof Keepalive);
139 public void testBadKeepAliveMsg() throws BGPParsingException {
140 final byte[] bytes = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
141 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
142 (byte) 0x00, (byte) 0x14, (byte) 0x04, (byte) 0x05 };
145 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
146 fail("Exception should have occured.");
147 } catch (final BGPDocumentedException e) {
148 assertThat(e.getMessage(), containsString("Message length field not within valid range."));
149 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
156 public void testOpenMessage() throws UnknownHostException, BGPParsingException, BGPDocumentedException {
157 final Notification open = new OpenBuilder().setMyAsNumber(100).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("20.20.20.20")).setVersion(
158 new ProtocolVersion((short) 4)).build();
159 ByteBuf bytes = Unpooled.buffer();
160 ParserTest.reg.serializeMessage(open, bytes);
161 assertArrayEquals(openBMsg, ByteArray.getAllBytes(bytes));
163 final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
165 assertTrue(m instanceof Open);
166 assertEquals(100, ((Open) m).getMyAsNumber().intValue());
167 assertEquals(180, ((Open) m).getHoldTimer().intValue());
168 assertEquals(new Ipv4Address("20.20.20.20"), ((Open) m).getBgpIdentifier());
169 assertTrue(((Open) m).getBgpParameters().isEmpty());
173 public void testBadHoldTimeError() throws BGPParsingException {
174 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
175 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
176 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x01, (byte) 0x14,
177 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
180 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
181 fail("Exception should have occured.");
182 } catch (final BGPDocumentedException e) {
183 assertEquals("Hold time value not acceptable.", e.getMessage());
184 assertEquals(BGPError.HOLD_TIME_NOT_ACC, e.getError());
191 public void testBadMsgLength() throws BGPParsingException {
192 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
193 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
194 (byte) 0x00, (byte) 0x1b, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0xff,
195 (byte) 0xff, (byte) 0xff };
198 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
199 fail("Exception should have occured.");
200 } catch (final BGPDocumentedException e) {
201 assertEquals("Open message too small.", e.getMessage());
202 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
207 public void testBadVersion() throws BGPParsingException {
208 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
209 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
210 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x08, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0x14,
211 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
214 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
215 fail("Exception should have occured.");
216 } catch (final BGPDocumentedException e) {
217 assertEquals("BGP Protocol version 8 not supported.", e.getMessage());
218 assertEquals(BGPError.VERSION_NOT_SUPPORTED, e.getError());
225 public void testNotificationMsg() throws BGPParsingException, BGPDocumentedException {
226 Notification notMsg = new NotifyBuilder().setErrorCode(BGPError.OPT_PARAM_NOT_SUPPORTED.getCode()).setErrorSubcode(
227 BGPError.OPT_PARAM_NOT_SUPPORTED.getSubcode()).setData(new byte[] { 4, 9 }).build();
228 ByteBuf bytes = Unpooled.buffer();
229 ParserTest.reg.serializeMessage(notMsg, bytes);
230 assertArrayEquals(notificationBMsg, ByteArray.subByte(bytes.array(),0,bytes.writerIndex()));
232 Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
234 assertTrue(m instanceof Notify);
235 assertEquals(BGPError.OPT_PARAM_NOT_SUPPORTED, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
236 assertArrayEquals(new byte[] { 4, 9 }, ((Notify) m).getData());
238 notMsg = new NotifyBuilder().setErrorCode(BGPError.CONNECTION_NOT_SYNC.getCode()).setErrorSubcode(
239 BGPError.CONNECTION_NOT_SYNC.getSubcode()).build();
243 ParserTest.reg.serializeMessage(notMsg, bytes);
245 m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
247 assertTrue(m instanceof Notify);
248 assertEquals(BGPError.CONNECTION_NOT_SYNC, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
249 assertNull(((Notify) m).getData());
253 public void testWrongLength() throws BGPParsingException {
254 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
255 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
256 (byte) 0x00, (byte) 0x14, (byte) 0x03, (byte) 0x02 };
259 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
260 fail("Exception should have occured.");
261 } catch (final BGPDocumentedException e) {
262 assertEquals("Notification message too small.", e.getMessage());
263 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
270 public void testUnrecognizedError() throws BGPParsingException, BGPDocumentedException {
271 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
272 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
273 (byte) 0x00, (byte) 0x15, (byte) 0x03, (byte) 0x02, (byte) 0xaa };
276 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
277 fail("Exception should have occured.");
278 } catch (final IllegalArgumentException e) {
279 assertEquals("BGP Error code 2 and subcode 170 not recognized.", e.getMessage());
286 public void testTLVParser() throws UnknownHostException {
288 final BgpTableType t1 = new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
289 final BgpTableType t2 = new BgpTableTypeImpl(LinkstateAddressFamily.class, UnicastSubsequentAddressFamily.class);
291 final List<BgpParameters> tlvs = Lists.newArrayList();
293 tlvs.add(new BgpParametersBuilder().setCParameters(
294 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
295 new MultiprotocolCapabilityBuilder().setAfi(LinkstateAddressFamily.class).setSafi(
296 LinkstateSubsequentAddressFamily.class).build()).build()).build());
297 tlvs.add(new BgpParametersBuilder().setCParameters(
298 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
299 new MultiprotocolCapabilityBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).build()).build()).build());
301 final Map<BgpTableType, Boolean> tableTypes = Maps.newHashMap();
302 tableTypes.put(t1, true);
303 tableTypes.put(t2, true);
304 final Open open = new OpenBuilder().setMyAsNumber(72).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("172.20.160.170")).setVersion(
305 new ProtocolVersion((short) 4)).setBgpParameters(tlvs).build();
307 ByteBuf result = Unpooled.buffer();
308 ParserTest.reg.serializeMessage(open, result);
310 // the capabilities can be swapped.
311 assertTrue(Arrays.equals(openWithCpblt1, ByteArray.getAllBytes(result)) || Arrays.equals(openWithCpblt2, ByteArray.getAllBytes(result)));
314 // https://bugs.opendaylight.org/show_bug.cgi?id=1370
315 // tests if all bytes are read after deserialization error occurs
317 public void testUpdateMsgParser() throws BGPParsingException {
318 final ByteBuf buffer = Unpooled.copiedBuffer(updateMsg);
320 ParserTest.reg.parseMessage(buffer);
322 } catch(BGPDocumentedException e) {
323 assertEquals(0, buffer.readableBytes());