Use Assert.assertThrows()
[genius.git] / ipv6util / impl / src / test / java / org / opendaylight / genius / ipv6util / nd / Ipv6NsHelperTest.java
1 /*
2  * Copyright (c) 2017 Red Hat, 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.genius.ipv6util.nd;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertThrows;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.times;
15 import static org.mockito.Mockito.verify;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import org.junit.Before;
20 import org.junit.Test;
21 import org.mockito.Mockito;
22 import org.opendaylight.genius.mdsalutil.ActionInfo;
23 import org.opendaylight.genius.mdsalutil.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
38 import org.opendaylight.yangtools.yang.common.Uint64;
39
40 public class Ipv6NsHelperTest {
41     private Ipv6NsHelper instance;
42     private PacketProcessingService pktProcessService;
43
44     @Before
45     public void initTest() {
46         pktProcessService = Mockito.mock(PacketProcessingService.class);
47         instance = new Ipv6NsHelper(pktProcessService);
48     }
49
50     /**
51      *  Test transmitNeighborSolicitation.
52      */
53     @Test
54     public void testTransmitNeighborSolicitation() {
55         doReturn(RpcResultBuilder.status(true).buildFuture()).when(pktProcessService)
56             .transmitPacket(any(TransmitPacketInput.class));
57
58         Uint64 dpnId = Uint64.ONE;
59         String macAddr = "08:00:27:FE:8F:95";
60         boolean retValue;
61         Ipv6Address srcIpv6Address = new Ipv6Address("2001:db8::1");
62         Ipv6Address targetIpv6Address = new Ipv6Address("2001:db8::2");
63         InstanceIdentifier<Node> ncId = InstanceIdentifier.builder(Nodes.class)
64                 .child(Node.class, new NodeKey(new NodeId("openflow:1"))).build();
65         NodeConnectorRef nodeRef = new NodeConnectorRef(ncId);
66         retValue = instance.transmitNeighborSolicitation(dpnId, nodeRef, new MacAddress(macAddr),
67                 srcIpv6Address, targetIpv6Address);
68         assertEquals(true, retValue);
69         verify(pktProcessService, times(1)).transmitPacket(any(TransmitPacketInput.class));
70
71         byte[] expectedPayload = buildPacket(
72                 "33 33 00 00 00 02",                               // Destination MAC
73                 "08 00 27 FE 8F 95",                               // Source MAC
74                 "86 DD",                                           // Ethertype - IPv6
75                 "60 00 00 00",                                     // Version 6, traffic class 0, no flowlabel
76                 "00 20",                                           // Payload length
77                 "3A",                                              // Next header is ICMPv6
78                 "FF",                                              // Hop limit
79                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 01", // Source IP
80                 "FF 02 00 00 00 00 00 00 00 00 00 01 FF 00 00 02", // Destination IP
81                 "87",                                              // ICMPv6 neighbor solicitation.
82                 "00",                                              // Code
83                 "5E 94",                                           // Checksum (valid)
84                 "00 00 00 00",                                     // Flags
85                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 02", // Target Address
86                 "01",                                              // Type: Source Link-Layer Option
87                 "01",                                              // Option length
88                 "08 00 27 FE 8F 95"                                // Source Link layer address
89         );
90         NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
91         verify(pktProcessService).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
92                 .setNode(new NodeRef(ncId)).setEgress(nodeRef).setIngress(nodeConnectorRef).build());
93     }
94
95     @Test
96     public void testTransmitNeighborSolicitationWithInvalidPayload() {
97         doReturn(RpcResultBuilder.status(true).buildFuture()).when(pktProcessService)
98             .transmitPacket(any(TransmitPacketInput.class));
99
100         Uint64 dpnId = Uint64.ONE;
101         String macAddr = "08:00:27:FE:8F:95";
102         boolean retValue;
103         Ipv6Address srcIpv6Address = new Ipv6Address("2001:db8::1");
104         Ipv6Address targetIpv6Address = new Ipv6Address("2001:db8::2");
105         InstanceIdentifier<Node> ncId = InstanceIdentifier.builder(Nodes.class)
106                 .child(Node.class, new NodeKey(new NodeId("openflow:1"))).build();
107         NodeConnectorRef nodeRef = new NodeConnectorRef(ncId);
108         retValue = instance.transmitNeighborSolicitation(dpnId, nodeRef, new MacAddress(macAddr),
109                 srcIpv6Address, targetIpv6Address);
110         assertEquals(true, retValue);
111         verify(pktProcessService, times(1)).transmitPacket(any(TransmitPacketInput.class));
112
113         // case: 1 - Invalid checksum
114         byte[] expectedPayload = buildPacket(
115                 "33 33 00 00 00 02",                               // Destination MAC
116                 "08 00 27 FE 8F 95",                               // Source MAC
117                 "86 DD",                                           // Ethertype - IPv6
118                 "60 00 00 00",                                     // Version 6, traffic class 0, no flowlabel
119                 "00 20",                                           // Payload length
120                 "3A",                                              // Next header is ICMPv6
121                 "FF",                                              // Hop limit
122                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 01", // Source IP
123                 "FF 02 00 00 00 00 00 00 00 00 00 01 FF 00 00 02", // Destination IP
124                 "87",                                              // ICMPv6 neighbor solicitation.
125                 "00",                                              // Code
126                 "5E 95",                                           // Checksum (invalid)
127                 "00 00 00 00",                                     // Flags
128                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 02", // Target Address
129                 "01",                                              // Type: Source Link-Layer Option
130                 "01",                                              // Option length
131                 "08 00 27 FE 8F 95"                                // Source Link layer address
132         );
133         NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId, "0xfffffffd");
134         verify(pktProcessService, times(0)).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
135                 .setNode(new NodeRef(ncId)).setEgress(nodeRef).setIngress(nodeConnectorRef).build());
136
137         // case: 2 - Invalid ICMPv6 type
138         expectedPayload = buildPacket(
139                 "33 33 00 00 00 02",                               // Destination MAC
140                 "08 00 27 FE 8F 95",                               // Source MAC
141                 "86 DD",                                           // Ethertype - IPv6
142                 "60 00 00 00",                                     // Version 6, traffic class 0, no flowlabel
143                 "00 20",                                           // Payload length
144                 "3A",                                              // Next header is ICMPv6
145                 "FF",                                              // Hop limit
146                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 01", // Source IP
147                 "FF 02 00 00 00 00 00 00 00 00 00 01 FF 00 00 02", // Destination IP
148                 "88",                                              // ICMPv6 neighbor advertisement (invalid).
149                 "00",                                              // Code
150                 "5E 94",                                           // Checksum (valid), should be "5E 94"
151                 "00 00 00 00",                                     // Flags
152                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 02", // Target Address
153                 "01",                                              // Type: Source Link-Layer Option
154                 "01",                                              // Option length
155                 "08 00 27 FE 8F 95"                                // Source Link layer address
156         );
157         verify(pktProcessService, times(0)).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
158                 .setNode(new NodeRef(ncId)).setEgress(nodeRef).setIngress(nodeConnectorRef).build());
159     }
160
161     @Test
162     public void testTransmitNeighborSolicitationToOfGroup() {
163         doReturn(RpcResultBuilder.status(true).buildFuture()).when(pktProcessService)
164                 .transmitPacket(any(TransmitPacketInput.class));
165
166         Uint64 dpnId = Uint64.ONE;
167         MacAddress srcMacAddress = new MacAddress("08:00:27:FE:8F:95");
168         Ipv6Address srcIpv6Address = new Ipv6Address("2001:db8::1");
169         Ipv6Address targetIpv6Address = new Ipv6Address("2001:db8::2");
170         long ofGroupId = 20000;
171
172         instance.transmitNeighborSolicitationToOfGroup(dpnId, srcMacAddress, srcIpv6Address, targetIpv6Address,
173                 ofGroupId);
174         verify(pktProcessService, times(1)).transmitPacket(any(TransmitPacketInput.class));
175     }
176
177     @Test
178     public void testTransmitNeighborSolicitationToOfGroupWithInvalidInput() {
179         doReturn(RpcResultBuilder.status(true).buildFuture()).when(pktProcessService)
180                 .transmitPacket(any(TransmitPacketInput.class));
181
182         Uint64 dpnId = Uint64.ONE;
183         MacAddress srcMacAddress = new MacAddress("08:00:27:FE:8F:95");
184         Ipv6Address srcIpv6Address = new Ipv6Address("2001:db8::1");
185         Ipv6Address targetIpv6Address = new Ipv6Address("2001:db8::2");
186         long invalidOfGroupId = -1;
187
188         // case: 1 - Invalid OF group ID
189         assertThrows(IllegalArgumentException.class, () -> {
190             instance.transmitNeighborSolicitationToOfGroup(dpnId, srcMacAddress, srcIpv6Address, targetIpv6Address,
191                     invalidOfGroupId);
192         });
193         verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
194
195         // case: 2 - Invalid checksum
196         long ofGroupId = 20000;
197         byte[] expectedPayload = buildPacket(
198                 "33 33 00 00 00 02",                               // Destination MAC
199                 "08 00 27 FE 8F 95",                               // Source MAC
200                 "86 DD",                                           // Ethertype - IPv6
201                 "60 00 00 00",                                     // Version 6, traffic class 0, no flowlabel
202                 "00 20",                                           // Payload length
203                 "3A",                                              // Next header is ICMPv6
204                 "FF",                                              // Hop limit
205                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 01", // Source IP
206                 "FF 02 00 00 00 00 00 00 00 00 00 01 FF 00 00 02", // Destination IP
207                 "87",                                              // ICMPv6 neighbor solicitation.
208                 "00",                                              // Code
209                 "5E 95",                                           // Checksum (invalid), should be "5E 94"
210                 "00 00 00 00",                                     // Flags
211                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 02", // Target Address
212                 "01",                                              // Type: Source Link-Layer Option
213                 "01",                                              // Option length
214                 "08 00 27 FE 8F 95"                                // Source Link layer address
215         );
216         List<ActionInfo> lstActionInfo = new ArrayList<>();
217         lstActionInfo.add(new ActionGroup(ofGroupId));
218         TransmitPacketInput expectedInput = MDSALUtil.getPacketOutDefault(lstActionInfo, expectedPayload, dpnId);
219
220         instance.transmitNeighborSolicitationToOfGroup(dpnId, srcMacAddress, srcIpv6Address, targetIpv6Address,
221                 ofGroupId);
222         verify(pktProcessService, times(0)).transmitPacket(expectedInput);
223
224         // case: 3 - Invalid Icmpv6 Type
225         expectedPayload = buildPacket(
226                 "33 33 00 00 00 02",                               // Destination MAC
227                 "08 00 27 FE 8F 95",                               // Source MAC
228                 "86 DD",                                           // Ethertype - IPv6
229                 "60 00 00 00",                                     // Version 6, traffic class 0, no flowlabel
230                 "00 20",                                           // Payload length
231                 "3A",                                              // Next header is ICMPv6
232                 "FF",                                              // Hop limit
233                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 01", // Source IP
234                 "FF 02 00 00 00 00 00 00 00 00 00 01 FF 00 00 02", // Destination IP
235                 "88",                                              // ICMPv6 neighbor advertisement (invalid).
236                 "00",                                              // Code
237                 "5E 94",                                           // Checksum (valid)
238                 "00 00 00 00",                                     // Flags
239                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 02", // Target Address
240                 "01",                                              // Type: Source Link-Layer Option
241                 "01",                                              // Option length
242                 "08 00 27 FE 8F 95"                                // Source Link layer address
243         );
244         expectedInput = MDSALUtil.getPacketOutDefault(lstActionInfo, expectedPayload, dpnId);
245
246         instance.transmitNeighborSolicitationToOfGroup(dpnId, srcMacAddress, srcIpv6Address, targetIpv6Address,
247                 ofGroupId);
248         verify(pktProcessService, times(0)).transmitPacket(expectedInput);
249     }
250
251     public byte[] buildPacket(String... contents) {
252         List<String[]> splitContents = new ArrayList<>();
253         int packetLength = 0;
254         for (String content : contents) {
255             String[] split = content.split(" ");
256             packetLength += split.length;
257             splitContents.add(split);
258         }
259         byte[] packet = new byte[packetLength];
260         int index = 0;
261         for (String[] split : splitContents) {
262             for (String component : split) {
263                 // We can't use Byte.parseByte() here, it refuses anything > 7F
264                 packet[index] = (byte) Integer.parseInt(component, 16);
265                 index++;
266             }
267         }
268         return packet;
269     }
270 }