Bug 611 - BGP Update message serialization
[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
21 import io.netty.buffer.ByteBuf;
22 import io.netty.buffer.Unpooled;
23
24 import java.net.UnknownHostException;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.junit.BeforeClass;
30 import org.junit.Test;
31 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
32 import org.opendaylight.protocol.bgp.parser.BGPError;
33 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
34 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
35 import org.opendaylight.protocol.bgp.parser.spi.MessageRegistry;
36 import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext;
37 import org.opendaylight.protocol.util.ByteArray;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateAddressFamily;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkstateSubsequentAddressFamily;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Keepalive;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.KeepaliveBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Notify;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.NotifyBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Open;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.OpenBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.ProtocolVersion;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParametersBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.MultiprotocolCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.multiprotocol._case.MultiprotocolCapabilityBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
55 import org.opendaylight.yangtools.yang.binding.Notification;
56
57 public class ParserTest {
58
59     public static final byte[] openBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
60         (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
61         (byte) 0xff, (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4,
62         (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
63
64     public static final byte[] keepAliveBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
65         (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
66         (byte) 0xff, (byte) 0x00, (byte) 0x13, (byte) 0x04 };
67
68     public static final byte[] notificationBMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
69         (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
70         (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x17, (byte) 0x03, (byte) 0x02, (byte) 0x04, (byte) 0x04, (byte) 0x09 };
71
72     public static final byte[] openWithCpblt1 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
73         (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
74         (byte) 0xff, (byte) 0x00, (byte) 0x2d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x48, (byte) 0x00, (byte) 0xb4,
75         (byte) 0xac, (byte) 0x14, (byte) 0xa0, (byte) 0xaa, (byte) 0x10, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04,
76         (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x40,
77         (byte) 0x04, (byte) 0x00, (byte) 0x47 };
78
79     public static final byte[] openWithCpblt2 = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
80         (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
81         (byte) 0xff, (byte) 0x00, (byte) 0x2d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x48, (byte) 0x00, (byte) 0xb4,
82         (byte) 0xac, (byte) 0x14, (byte) 0xa0, (byte) 0xaa, (byte) 0x10, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04,
83         (byte) 0x40, (byte) 0x04, (byte) 0x00, (byte) 0x47, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x04, (byte) 0x00,
84         (byte) 0x01, (byte) 0x00, (byte) 0x01 };
85
86     static MessageRegistry reg;
87
88     @BeforeClass
89     public static void setupClass() throws Exception {
90         reg = ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getMessageRegistry();
91     }
92
93     @Test
94     public void testHeaderErrors() throws BGPParsingException, BGPDocumentedException {
95         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 };
96         wrong = ByteArray.cutBytes(wrong, 16);
97         try {
98             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(wrong));
99             fail("Exception should have occcured.");
100         } catch (final IllegalArgumentException e) {
101             assertEquals("Too few bytes in passed array. Passed: " + wrong.length + ". Expected: >= 19.", e.getMessage());
102             return;
103         }
104         fail();
105     }
106
107     @Test
108     public void testBadMsgType() throws BGPParsingException {
109         final byte[] bytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
110             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
111             (byte) 0x00, (byte) 0x13, (byte) 0x08 };
112         try {
113             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
114             fail("Exception should have occured.");
115         } catch (final BGPDocumentedException e) {
116             assertEquals(BGPError.BAD_MSG_TYPE, e.getError());
117             return;
118         }
119         fail();
120     }
121
122     @Test
123     public void testKeepAliveMsg() throws BGPParsingException, BGPDocumentedException {
124         final Notification keepAlive = new KeepaliveBuilder().build();
125         ByteBuf buffer = Unpooled.buffer();
126         ParserTest.reg.serializeMessage(keepAlive, buffer);
127         assertArrayEquals(keepAliveBMsg, ByteArray.getAllBytes(buffer));
128
129         final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(ByteArray.getAllBytes(buffer)));
130
131         assertTrue(m instanceof Keepalive);
132     }
133
134     @Test
135     public void testBadKeepAliveMsg() throws BGPParsingException {
136         final byte[] bytes = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
137             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
138             (byte) 0x00, (byte) 0x14, (byte) 0x04, (byte) 0x05 };
139
140         try {
141             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
142             fail("Exception should have occured.");
143         } catch (final BGPDocumentedException e) {
144             assertThat(e.getMessage(), containsString("Message length field not within valid range."));
145             assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
146             return;
147         }
148         fail();
149     }
150
151     @Test
152     public void testOpenMessage() throws UnknownHostException, BGPParsingException, BGPDocumentedException {
153         final Notification open = new OpenBuilder().setMyAsNumber(100).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("20.20.20.20")).setVersion(
154                 new ProtocolVersion((short) 4)).build();
155         ByteBuf bytes = Unpooled.buffer();
156         ParserTest.reg.serializeMessage(open, bytes);
157         assertArrayEquals(openBMsg, ByteArray.getAllBytes(bytes));
158
159         final Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
160
161         assertTrue(m instanceof Open);
162         assertEquals(100, ((Open) m).getMyAsNumber().intValue());
163         assertEquals(180, ((Open) m).getHoldTimer().intValue());
164         assertEquals(new Ipv4Address("20.20.20.20"), ((Open) m).getBgpIdentifier());
165         assertTrue(((Open) m).getBgpParameters().isEmpty());
166     }
167
168     @Test
169     public void testBadHoldTimeError() throws BGPParsingException {
170         final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
171             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
172             (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x01, (byte) 0x14,
173             (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
174
175         try {
176             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
177             fail("Exception should have occured.");
178         } catch (final BGPDocumentedException e) {
179             assertEquals("Hold time value not acceptable.", e.getMessage());
180             assertEquals(BGPError.HOLD_TIME_NOT_ACC, e.getError());
181             return;
182         }
183         fail();
184     }
185
186     @Test
187     public void testBadMsgLength() throws BGPParsingException {
188         final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
189             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
190             (byte) 0x00, (byte) 0x1b, (byte) 0x01, (byte) 0x04, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0xff,
191             (byte) 0xff, (byte) 0xff };
192
193         try {
194             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
195             fail("Exception should have occured.");
196         } catch (final BGPDocumentedException e) {
197             assertEquals("Open message too small.", e.getMessage());
198             assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
199         }
200     }
201
202     @Test
203     public void testBadVersion() throws BGPParsingException {
204         final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
205             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
206             (byte) 0x00, (byte) 0x1d, (byte) 0x01, (byte) 0x08, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0xb4, (byte) 0x14,
207             (byte) 0x14, (byte) 0x14, (byte) 0x14, (byte) 0x00 };
208
209         try {
210             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
211             fail("Exception should have occured.");
212         } catch (final BGPDocumentedException e) {
213             assertEquals("BGP Protocol version 8 not supported.", e.getMessage());
214             assertEquals(BGPError.VERSION_NOT_SUPPORTED, e.getError());
215             return;
216         }
217         fail();
218     }
219
220     @Test
221     public void testNotificationMsg() throws BGPParsingException, BGPDocumentedException {
222         Notification notMsg = new NotifyBuilder().setErrorCode(BGPError.OPT_PARAM_NOT_SUPPORTED.getCode()).setErrorSubcode(
223                 BGPError.OPT_PARAM_NOT_SUPPORTED.getSubcode()).setData(new byte[] { 4, 9 }).build();
224         ByteBuf bytes = Unpooled.buffer();
225         ParserTest.reg.serializeMessage(notMsg, bytes);
226         assertArrayEquals(notificationBMsg, ByteArray.subByte(bytes.array(),0,bytes.writerIndex()));
227
228         Notification m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
229
230         assertTrue(m instanceof Notify);
231         assertEquals(BGPError.OPT_PARAM_NOT_SUPPORTED, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
232         assertArrayEquals(new byte[] { 4, 9 }, ((Notify) m).getData());
233
234         notMsg = new NotifyBuilder().setErrorCode(BGPError.CONNECTION_NOT_SYNC.getCode()).setErrorSubcode(
235                 BGPError.CONNECTION_NOT_SYNC.getSubcode()).build();
236
237         bytes.clear();
238
239         ParserTest.reg.serializeMessage(notMsg, bytes);
240
241         m = ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bytes));
242
243         assertTrue(m instanceof Notify);
244         assertEquals(BGPError.CONNECTION_NOT_SYNC, BGPError.forValue(((Notify) m).getErrorCode(), ((Notify) m).getErrorSubcode()));
245         assertNull(((Notify) m).getData());
246     }
247
248     @Test
249     public void testWrongLength() throws BGPParsingException {
250         final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
251             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
252             (byte) 0x00, (byte) 0x14, (byte) 0x03, (byte) 0x02 };
253
254         try {
255             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
256             fail("Exception should have occured.");
257         } catch (final BGPDocumentedException e) {
258             assertEquals("Notification message too small.", e.getMessage());
259             assertEquals(BGPError.BAD_MSG_LENGTH, e.getError());
260             return;
261         }
262         fail();
263     }
264
265     @Test
266     public void testUnrecognizedError() throws BGPParsingException, BGPDocumentedException {
267         final byte[] bMsg = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
268             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
269             (byte) 0x00, (byte) 0x15, (byte) 0x03, (byte) 0x02, (byte) 0xaa };
270
271         try {
272             ParserTest.reg.parseMessage(Unpooled.copiedBuffer(bMsg));
273             fail("Exception should have occured.");
274         } catch (final IllegalArgumentException e) {
275             assertEquals("BGP Error code 2 and subcode 170 not recognized.", e.getMessage());
276             return;
277         }
278         fail();
279     }
280
281     @Test
282     public void testTLVParser() throws UnknownHostException {
283
284         final BgpTableType t1 = new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
285         final BgpTableType t2 = new BgpTableTypeImpl(LinkstateAddressFamily.class, UnicastSubsequentAddressFamily.class);
286
287         final List<BgpParameters> tlvs = Lists.newArrayList();
288
289         tlvs.add(new BgpParametersBuilder().setCParameters(
290                 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
291                         new MultiprotocolCapabilityBuilder().setAfi(LinkstateAddressFamily.class).setSafi(
292                                 LinkstateSubsequentAddressFamily.class).build()).build()).build());
293         tlvs.add(new BgpParametersBuilder().setCParameters(
294                 new MultiprotocolCaseBuilder().setMultiprotocolCapability(
295                         new MultiprotocolCapabilityBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).build()).build()).build());
296
297         final Map<BgpTableType, Boolean> tableTypes = Maps.newHashMap();
298         tableTypes.put(t1, true);
299         tableTypes.put(t2, true);
300         final Open open = new OpenBuilder().setMyAsNumber(72).setHoldTimer(180).setBgpIdentifier(new Ipv4Address("172.20.160.170")).setVersion(
301                 new ProtocolVersion((short) 4)).setBgpParameters(tlvs).build();
302
303         ByteBuf result = Unpooled.buffer();
304         ParserTest.reg.serializeMessage(open, result);
305
306         // the capabilities can be swapped.
307         assertTrue(Arrays.equals(openWithCpblt1, ByteArray.getAllBytes(result)) || Arrays.equals(openWithCpblt2, ByteArray.getAllBytes(result)));
308     }
309 }