Fixed findbug issues in BGP.
[bgpcep.git] / bgp / parser-impl / src / test / java / org / opendaylight / protocol / bgp / parser / impl / ParserTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.parser.impl;
9
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;
17
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;
25 import java.util.Map;
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;
53
54 public class ParserTest {
55
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 };
60
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 };
64
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 };
68
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 };
75
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 };
82
83     static MessageRegistry reg;
84
85     @BeforeClass
86     public static void setupClass() throws Exception {
87         reg = ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getMessageRegistry();
88     }
89
90     @Test
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);
94         try {
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());
99             return;
100         }
101         fail();
102     }
103
104     @Test
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 };
109         try {
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());
114             return;
115         }
116         fail();
117     }
118
119     @Test
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));
125
126         final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(ByteArray.getAllBytes(buffer)));
127
128         assertTrue(m instanceof Keepalive);
129     }
130
131     @Test
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 };
136
137         try {
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());
143             return;
144         }
145         fail();
146     }
147
148     @Test
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));
155
156         final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
157
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());
163     }
164
165     @Test
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 };
171
172         try {
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());
178             return;
179         }
180         fail();
181     }
182
183     @Test
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 };
189
190         try {
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());
196         }
197     }
198
199     @Test
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 };
205
206         try {
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());
212             return;
213         }
214         fail();
215     }
216
217     @Test
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()));
224
225         Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
226
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());
230
231         notMsg = new NotifyBuilder().setErrorCode(BGPError.CONNECTION_NOT_SYNC.getCode()).setErrorSubcode(
232             BGPError.CONNECTION_NOT_SYNC.getSubcode()).build();
233
234         bytes.clear();
235
236         ParserTest.reg.serializeMessage(notMsg, bytes);
237
238         m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
239
240         assertTrue(m instanceof Notify);
241         assertEquals(BGPError.CONNECTION_NOT_SYNC, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
242         assertNull(((Notify) m).getData());
243     }
244
245     @Test
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 };
250
251         try {
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());
257             return;
258         }
259         fail();
260     }
261
262     @Test
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 };
267
268         try {
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());
273             return;
274         }
275         fail();
276     }
277
278     @Test
279     public void testTLVParser() throws UnknownHostException {
280
281         final BgpTableType t1 = new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
282         final BgpTableType t2 = new BgpTableTypeImpl(LinkstateAddressFamily.class, UnicastSubsequentAddressFamily.class);
283
284         final List<BgpParameters> tlvs = Lists.newArrayList();
285
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());
293
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();
299
300         final ByteBuf result = Unpooled.buffer();
301         ParserTest.reg.serializeMessage(open, result);
302
303         // the capabilities can be swapped.
304         assertTrue(Arrays.equals(openWithCpblt1, ByteArray.getAllBytes(result)) || Arrays.equals(openWithCpblt2, ByteArray.getAllBytes(result)));
305     }
306 }