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 private 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 private 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 private 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 private 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 private 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 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, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00 };
93 wrong = ByteArray.cutBytes(wrong, 16);
95 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(wrong));
96 fail("Exception should have occcured.");
97 } catch (final IllegalArgumentException e) {
98 assertEquals("Too few bytes in passed array. Passed: " + wrong.length + ". Expected: >= 19.", e.getMessage());
105 public void testBadMsgType() throws BGPParsingException {
106 final byte[] bytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
107 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
108 (byte) 0x00, (byte) 0x13, (byte) 0x08 };
110 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
111 fail("Exception should have occured.");
112 } catch (final BGPDocumentedException e) {
113 assertEquals(BGPError.BAD_MSG_TYPE, e.getError());
120 public void testKeepAliveMsg() throws BGPParsingException, BGPDocumentedException {
121 final Notification keepAlive = new KeepaliveBuilder().build();
122 final ByteBuf buffer = Unpooled.buffer();
123 ParserTest.reg.serializeMessage(keepAlive, buffer);
124 assertArrayEquals(keepAliveBMsg, ByteArray.getAllBytes(buffer));
126 final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(ByteArray.getAllBytes(buffer)));
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 ByteBuf bytes = Unpooled.buffer();
153 ParserTest.reg.serializeMessage(open, bytes);
154 assertArrayEquals(openBMsg, ByteArray.getAllBytes(bytes));
156 final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
158 assertTrue(m instanceof Open);
159 assertEquals(100, ((Open) m).getMyAsNumber().intValue());
160 assertEquals(180, ((Open) m).getHoldTimer().intValue());
161 assertEquals(new Ipv4Address("20.20.20.20"), ((Open) m).getBgpIdentifier());
162 assertTrue(((Open) m).getBgpParameters().isEmpty());
166 public void testBadHoldTimeError() throws BGPParsingException {
167 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
168 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
169 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x01, (byte) 0x14,
170 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
173 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
174 fail("Exception should have occured.");
175 } catch (final BGPDocumentedException e) {
176 assertEquals("Hold time value not acceptable.", e.getMessage());
177 assertEquals(BGPError.HOLD_TIME_NOT_ACC, e.getError());
184 public void testBadMsgLength() throws BGPParsingException {
185 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
186 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
187 (byte) 0x00, (byte) 0x1b, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0xff,
188 (byte) 0xff, (byte) 0xff };
191 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
192 fail("Exception should have occured.");
193 } catch (final BGPDocumentedException e) {
194 assertEquals("Open message too small.", e.getMessage());
195 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
200 public void testBadVersion() throws BGPParsingException {
201 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
202 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
203 (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x08, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0x14,
204 (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
207 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
208 fail("Exception should have occured.");
209 } catch (final BGPDocumentedException e) {
210 assertEquals("BGP Protocol version 8 not supported.", e.getMessage());
211 assertEquals(BGPError.VERSION_NOT_SUPPORTED, e.getError());
218 public void testNotificationMsg() throws BGPParsingException, BGPDocumentedException {
219 Notification notMsg = new NotifyBuilder().setErrorCode(BGPError.OPT_PARAM_NOT_SUPPORTED.getCode()).setErrorSubcode(
220 BGPError.OPT_PARAM_NOT_SUPPORTED.getSubcode()).setData(new byte[] { 4, 9 }).build();
221 final ByteBuf bytes = Unpooled.buffer();
222 ParserTest.reg.serializeMessage(notMsg, bytes);
223 assertArrayEquals(notificationBMsg, ByteArray.subByte(bytes.array(),0,bytes.writerIndex()));
225 Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
227 assertTrue(m instanceof Notify);
228 assertEquals(BGPError.OPT_PARAM_NOT_SUPPORTED, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
229 assertArrayEquals(new byte[] { 4, 9 }, ((Notify) m).getData());
231 notMsg = new NotifyBuilder().setErrorCode(BGPError.CONNECTION_NOT_SYNC.getCode()).setErrorSubcode(
232 BGPError.CONNECTION_NOT_SYNC.getSubcode()).build();
236 ParserTest.reg.serializeMessage(notMsg, bytes);
238 m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
240 assertTrue(m instanceof Notify);
241 assertEquals(BGPError.CONNECTION_NOT_SYNC, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
242 assertNull(((Notify) m).getData());
246 public void testWrongLength() throws BGPParsingException {
247 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
248 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
249 (byte) 0x00, (byte) 0x14, (byte) 0x03, (byte) 0x02 };
252 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
253 fail("Exception should have occured.");
254 } catch (final BGPDocumentedException e) {
255 assertEquals("Notification message too small.", e.getMessage());
256 assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
263 public void testUnrecognizedError() throws BGPParsingException, BGPDocumentedException {
264 final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
265 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
266 (byte) 0x00, (byte) 0x15, (byte) 0x03, (byte) 0x02, (byte) 0xaa };
269 ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
270 fail("Exception should have occured.");
271 } catch (final IllegalArgumentException e) {
272 assertEquals("BGP Error code 2 and subcode 170 not recognized.", e.getMessage());
279 public void testTLVParser() throws UnknownHostException {
281 final BgpTableType t1 = new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
282 final BgpTableType t2 = new BgpTableTypeImpl(LinkstateAddressFamily.class, UnicastSubsequentAddressFamily.class);
284 final List<BgpParameters> tlvs = Lists.newArrayList();
286 tlvs.add(new BgpParametersBuilder().setCParameters(
287 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
288 new MultiprotocolCapabilityBuilder().setAfi(LinkstateAddressFamily.class).setSafi(
289 LinkstateSubsequentAddressFamily.class).build()).build()).build());
290 tlvs.add(new BgpParametersBuilder().setCParameters(
291 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
292 new MultiprotocolCapabilityBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).build()).build()).build());
294 final Map<BgpTableType, Boolean> tableTypes = Maps.newHashMap();
295 tableTypes.put(t1, true);
296 tableTypes.put(t2, true);
297 final Open open = new OpenBuilder().setMyAsNumber(72).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("172.20.160.170")).setVersion(
298 new ProtocolVersion((short) 4)).setBgpParameters(tlvs).build();
300 final ByteBuf result = Unpooled.buffer();
301 ParserTest.reg.serializeMessage(open, result);
303 // the capabilities can be swapped.
304 assertTrue(Arrays.equals(openWithCpblt1, ByteArray.getAllBytes(result)) || Arrays.equals(openWithCpblt2, ByteArray.getAllBytes(result)));