blob: ece96ee1c8bd18127c0b2809df50112091ee3308 [file] [log] [blame]
Daniel Park4d486842018-07-24 17:06:43 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.impl;
17
18import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Maps;
20import com.google.common.util.concurrent.MoreExecutors;
21import org.junit.After;
22import org.junit.Before;
23import org.junit.Test;
24import org.onlab.junit.TestUtils;
25import org.onlab.packet.DeserializationException;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.ICMP;
28import org.onlab.packet.IPv4;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.MacAddress;
31import org.onlab.packet.VlanId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreServiceAdapter;
34import org.onosproject.core.DefaultApplicationId;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.PortNumber;
37import org.onosproject.net.packet.DefaultInboundPacket;
38import org.onosproject.net.packet.DefaultPacketContext;
39import org.onosproject.net.packet.InboundPacket;
40import org.onosproject.net.packet.OutboundPacket;
41import org.onosproject.net.packet.PacketContext;
42import org.onosproject.net.packet.PacketProcessor;
43import org.onosproject.net.packet.PacketServiceAdapter;
44import org.onosproject.openstacknetworking.api.Constants;
45import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
46import org.onosproject.openstacknetworking.api.InstancePort;
47import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
48import org.onosproject.openstacknode.api.OpenstackNode;
49import org.onosproject.openstacknode.api.OpenstackNodeAdapter;
50import org.onosproject.store.service.TestStorageService;
51import org.openstack4j.model.network.ExternalGateway;
52import org.openstack4j.model.network.Port;
53import org.openstack4j.model.network.Router;
54import org.openstack4j.model.network.RouterInterface;
55import org.openstack4j.model.network.Subnet;
56import org.openstack4j.openstack.networking.domain.NeutronPort;
57import org.openstack4j.openstack.networking.domain.NeutronRouter;
58import org.openstack4j.openstack.networking.domain.NeutronSubnet;
59
60import java.io.InputStream;
61import java.nio.ByteBuffer;
62import java.util.Map;
63import java.util.Objects;
64import java.util.Set;
65import java.util.stream.Collectors;
66
67import static org.junit.Assert.assertEquals;
68import static org.junit.Assert.fail;
69import static org.onlab.packet.Ethernet.TYPE_IPV4;
70import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
71import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
72import static org.onosproject.net.NetTestTools.connectPoint;
73
74public class OpenstackRoutingIcmpHandlerTest {
75 private OpenstackRoutingIcmpHandler icmpHandler;
76 private static final byte CODE_ECHO_REQUEST = 0x00;
77 private static final byte CODE_ECHO_REPLY = 0x00;
78
79 protected PacketProcessor packetProcessor;
80 private InstancePort instancePort1;
81 private InstancePort instancePort2;
82 private InstancePort instancePort3;
83 private RouterInterface routerInterface1;
84 private Router router1;
85
86 private MacAddress srcMacPort1 = MacAddress.valueOf("11:22:33:44:55:66");
87 private IpAddress srcIpPort1 = IpAddress.valueOf("10.0.0.3");
88 private DeviceId srcDeviceId1 = DeviceId.deviceId("of:000000000000000a");
89 private PortNumber srcPortNum1 = PortNumber.portNumber(1);
90 private IpAddress targetIpToGw = IpAddress.valueOf("10.0.0.1");
91 private IpAddress targetIpToExternal = IpAddress.valueOf("8.8.8.8");
92 private IpAddress sNatIp = IpAddress.valueOf("172.27.0.13");
93 private MacAddress targetMac = Constants.DEFAULT_GATEWAY_MAC;
94 private MacAddress peerRouterMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
95 private Port port1;
96 private Port externalPort;
97 private Subnet subnet1;
98
99 Map<String, Port> portMap = Maps.newHashMap();
100 Map<String, InstancePort> instancePortMap = Maps.newHashMap();
101 Map<String, Router> osRouterMap = Maps.newHashMap();
102 Map<String, RouterInterface> osRouterInterfaceMap = Maps.newHashMap();
103
104 /**
105 * Initial setup for this unit test.
106 */
107 @Before
108 public void setUp() {
109
110 icmpHandler = new OpenstackRoutingIcmpHandler();
111
112 icmpHandler.coreService = new TestCoreService();
113 icmpHandler.packetService = new TestPacketService();
114 icmpHandler.storageService = new TestStorageService();
115 icmpHandler.osNodeService = new TestOpenstackNodeService();
116 icmpHandler.instancePortService = new TestInstancePortService();
117 icmpHandler.osNetworkService = new TestOpenstackNetworkService();
118 icmpHandler.osRouterService = new TestOpenstackRouterService();
119 TestUtils.setField(icmpHandler, "eventExecutor", MoreExecutors.newDirectExecutorService());
120 icmpHandler.activate();
121
122 createPort();
123 createSubnet();
124 createInstancePortMap();
125 createRouterInterfaceMap();
126 createRouterMap();
127 }
128
129 /**
130 * Tears down all of this unit test.
131 */
132 @After
133 public void tearDown() {
134 icmpHandler.deactivate();
135
136 }
137
138 /**
139 * Tests the icmp request to gateway.
140 */
141 @Test
142 public void testRequestToGw() {
143 Ethernet icmpRequest = constructIcmpRequestPacket(srcIpPort1,
144 srcMacPort1,
145 targetIpToGw,
146 targetMac,
147 TYPE_ECHO_REQUEST);
148 sendPacket(icmpRequest);
149 }
150
151 /**
152 * Tests the icmp request to external.
153 */
154 @Test
155 public void testRequestToExternal() {
156 Ethernet icmpRequest = constructIcmpRequestPacket(srcIpPort1,
157 srcMacPort1,
158 targetIpToExternal,
159 targetMac,
160 TYPE_ECHO_REQUEST);
161
162 sendPacket(icmpRequest);
163
164 Ethernet icmpResponse = constructIcmpRequestPacket(targetIpToExternal,
165 peerRouterMac,
166 sNatIp,
167 targetMac,
168 TYPE_ECHO_REPLY);
169
170 sendPacket(icmpResponse);
171 }
172
173 private void sendPacket(Ethernet ethernet) {
174 final ByteBuffer byteBuffer = ByteBuffer.wrap(ethernet.serialize());
175 InboundPacket inPacket = new DefaultInboundPacket(connectPoint(srcDeviceId1.toString(),
176 Integer.parseInt(srcPortNum1.toString())),
177 ethernet,
178 byteBuffer);
179
180 PacketContext context = new TestPacketContext(127L, inPacket, null, false);
181 packetProcessor.process(context);
182 }
183
184 private void validatePacket(Ethernet ethernet) {
185 IPv4 ipPacket = (IPv4) ethernet.getPayload();
186
187 if (IPv4.fromIPv4Address(ipPacket.getSourceAddress()).equals(targetIpToGw.toString())) {
188 validateIcmpReqToGw(ipPacket);
189 } else if (IPv4.fromIPv4Address(ipPacket.getSourceAddress())
190 .equals(sNatIp.toString())) {
191 validateIcmpReqToExternal(ipPacket);
192 } else if (IPv4.fromIPv4Address(ipPacket.getSourceAddress())
193 .equals(targetIpToExternal.toString())) {
194 validateIcmpRespFromExternal(ipPacket);
195 }
196 }
197
198 private void validateIcmpRespFromExternal(IPv4 ipPacket) {
199 ICMP icmpResp = (ICMP) ipPacket.getPayload();
200 short icmpId = ByteBuffer.wrap(icmpResp.serialize(), 4, 2).getShort();
201 short seqNum = ByteBuffer.wrap(icmpResp.serialize(), 6, 2).getShort();
202
203 assertEquals(icmpResp.getIcmpType(), TYPE_ECHO_REPLY);
204 assertEquals(icmpResp.getIcmpCode(), CODE_ECHO_REPLY);
205 assertEquals(icmpId, 0);
206 assertEquals(seqNum, 0);
207 assertEquals(IPv4.fromIPv4Address(ipPacket.getSourceAddress()), targetIpToExternal.toString());
208 assertEquals(IPv4.fromIPv4Address(ipPacket.getDestinationAddress()), srcIpPort1.toString());
209 }
210
211 private void validateIcmpReqToExternal(IPv4 ipPacket) {
212 ICMP icmpReq = (ICMP) ipPacket.getPayload();
213 short icmpId = ByteBuffer.wrap(icmpReq.serialize(), 4, 2).getShort();
214 short seqNum = ByteBuffer.wrap(icmpReq.serialize(), 6, 2).getShort();
215
216
217 assertEquals(icmpReq.getIcmpType(), TYPE_ECHO_REQUEST);
218 assertEquals(icmpReq.getIcmpCode(), CODE_ECHO_REQUEST);
219 assertEquals(icmpId, 0);
220 assertEquals(seqNum, 0);
221 assertEquals(IPv4.fromIPv4Address(ipPacket.getSourceAddress()), sNatIp.toString());
222 assertEquals(IPv4.fromIPv4Address(ipPacket.getDestinationAddress()), targetIpToExternal.toString());
223
224 }
225 private void validateIcmpReqToGw(IPv4 ipPacket) {
226 ICMP icmpReq = (ICMP) ipPacket.getPayload();
227 short icmpId = ByteBuffer.wrap(icmpReq.serialize(), 4, 2).getShort();
228 short seqNum = ByteBuffer.wrap(icmpReq.serialize(), 6, 2).getShort();
229
230 assertEquals(icmpReq.getIcmpType(), TYPE_ECHO_REPLY);
231 assertEquals(icmpReq.getIcmpCode(), CODE_ECHO_REPLY);
232 assertEquals(icmpId, 0);
233 assertEquals(seqNum, 0);
234 assertEquals(IPv4.fromIPv4Address(ipPacket.getSourceAddress()), targetIpToGw.toString());
235 assertEquals(IPv4.fromIPv4Address(ipPacket.getDestinationAddress()), srcIpPort1.toString());
236 }
237
238 private Ethernet constructIcmpRequestPacket(IpAddress srcIp,
239 MacAddress srcMac,
240 IpAddress dstIp,
241 MacAddress dstMac, byte icmpType) {
242 try {
243 IcmpEcho icmp = new IcmpEcho();
244 if (icmpType == TYPE_ECHO_REQUEST) {
245 icmp.setIcmpType(TYPE_ECHO_REQUEST)
246 .setIcmpCode(CODE_ECHO_REQUEST);
247 } else {
248 icmp.setIcmpType(TYPE_ECHO_REPLY)
249 .setIcmpCode(CODE_ECHO_REPLY);
250 }
251
252 icmp.setChecksum((short) 0)
253 .setIdentifier((short) 0)
254 .setSequenceNum((short) 0);
255
256 ByteBuffer bb = ByteBuffer.wrap(icmp.serialize());
257
258 IPv4 iPacket = new IPv4();
259 iPacket.setDestinationAddress(dstIp.toString());
260 iPacket.setSourceAddress(srcIp.toString());
261 iPacket.setTtl((byte) 64);
262 iPacket.setChecksum((short) 0);
263 iPacket.setDiffServ((byte) 0);
264 iPacket.setProtocol(IPv4.PROTOCOL_ICMP);
265
266 iPacket.setPayload(ICMP.deserializer().deserialize(bb.array(), 0, 8));
267
268 Ethernet ethPacket = new Ethernet();
269
270 ethPacket.setEtherType(TYPE_IPV4);
271 ethPacket.setSourceMACAddress(srcMac);
272 ethPacket.setDestinationMACAddress(dstMac);
273 ethPacket.setPayload(iPacket);
274
275 return ethPacket;
276 } catch (DeserializationException e) {
277 return null;
278 }
279 }
280
281 private class TestCoreService extends CoreServiceAdapter {
282 @Override
283 public ApplicationId registerApplication(String name) {
284 return new DefaultApplicationId(200, "test");
285 }
286 }
287
288 /**
289 * Mocks the PacketService.
290 */
291 private class TestPacketService extends PacketServiceAdapter {
292 @Override
293 public void addProcessor(PacketProcessor processor, int priority) {
294 packetProcessor = processor;
295 }
296
297 @Override
298 public void emit(OutboundPacket packet) {
299 try {
300 Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
301 0, packet.data().array().length);
302 validatePacket(eth);
303 } catch (Exception e) {
304 fail(e.getMessage());
305 }
306 }
307 }
308
309 /**
310 * Mocks the OpenstackNodeService.
311 */
312 private class TestOpenstackNodeService extends OpenstackNodeServiceAdapter {
313
314 @Override
315 public OpenstackNode node(DeviceId deviceId) {
316 return new TestOpenstackNode();
317 }
318 }
319
320 /**
321 * Mocks the InstancePortService.
322 */
323 private class TestInstancePortService extends InstancePortServiceAdapter {
324 @Override
325 public InstancePort instancePort(MacAddress macAddress) {
326 return instancePortMap.values().stream()
327 .filter(port -> Objects.equals(port.macAddress(), macAddress))
328 .findAny().orElse(null);
329 }
330
331 @Override
332 public InstancePort instancePort(IpAddress ipAddress, String osNetId) {
333 return instancePortMap.values().stream()
334 .filter(port -> port.networkId().equals(osNetId))
335 .filter(port -> port.ipAddress().equals(ipAddress))
336 .findFirst().orElse(null);
337 }
338
339 @Override
340 public InstancePort instancePort(String osPortId) {
341 return instancePortMap.get(osPortId);
342 }
343
344 @Override
345 public Set<InstancePort> instancePorts() {
346 return ImmutableSet.copyOf(instancePortMap.values());
347 }
348
349 @Override
350 public Set<InstancePort> instancePorts(String osNetId) {
351 Set<InstancePort> ports = instancePortMap.values().stream()
352 .filter(port -> port.networkId().equals(osNetId))
353 .collect(Collectors.toSet());
354
355 return ImmutableSet.copyOf(ports);
356 }
357 }
358
359 /**
360 * Mocks the OpenstackNetworkService.
361 */
362 private class TestOpenstackNetworkService extends OpenstackNetworkServiceAdapter {
363 @Override
364 public Set<Port> ports(String netId) {
365 return ImmutableSet.copyOf(portMap.values());
366 }
367 @Override
368 public Port port(String portId) {
369
370 return port1;
371 }
372
373 @Override
374 public Subnet subnet(String subnetId) {
375
376 return subnet1;
377 }
378
379 @Override
380 public ExternalPeerRouter externalPeerRouter(ExternalGateway externalGateway) {
381 return DefaultExternalPeerRouter.builder()
382 .ipAddress(IpAddress.valueOf("172.27.0.1"))
383 .macAddress(peerRouterMac)
384 .vlanId(VlanId.NONE)
385 .build();
386 }
387 }
388
389 /**
390 * Mocks the OpenstackRouterService.
391 */
392 private class TestOpenstackRouterService extends OpenstackRouterServiceAdapter {
393 @Override
394 public Set<RouterInterface> routerInterfaces() {
395 return ImmutableSet.copyOf(osRouterInterfaceMap.values());
396 }
397
398 @Override
399 public Router router(String osRouterId) {
400 return osRouterMap.get(osRouterId);
401 }
402 public Set<RouterInterface> routerInterfaces(String osRouterId) {
403 return osRouterInterfaceMap.values().stream()
404 .filter(iface -> iface.getId().equals(osRouterId))
405 .collect(Collectors.toSet());
406 }
407
408 }
409
410 /**
411 * Mocks the DefaultPacket context.
412 */
413 private final class TestPacketContext extends DefaultPacketContext {
414 private TestPacketContext(long time, InboundPacket inPkt,
415 OutboundPacket outPkt, boolean block) {
416 super(time, inPkt, outPkt, block);
417 }
418
419 @Override
420 public void send() {
421 // We don't send anything out.
422 }
423 }
424
425
426 private void createPort() {
427 InputStream portJsonStream1 = OpenstackRoutingIcmpHandlerTest.class
428 .getResourceAsStream("openstack-port-1.json");
429 port1 = (Port) OpenstackNetworkingUtil.jsonToModelEntity(portJsonStream1, NeutronPort.class);
430
431 InputStream portJsonStream2 = OpenstackRoutingIcmpHandlerTest.class
432 .getResourceAsStream("openstack-port-external.json");
433 externalPort = (Port) OpenstackNetworkingUtil.jsonToModelEntity(portJsonStream2, NeutronPort.class);
434
435 portMap.put(port1.getId(), port1);
436 portMap.put(externalPort.getId(), externalPort);
437
438 }
439
440 private void createSubnet() {
441 InputStream subnetJsonStream1 = OpenstackRoutingIcmpHandlerTest.class
442 .getResourceAsStream("openstack-subnet-1.json");
443 subnet1 = (Subnet) OpenstackNetworkingUtil.jsonToModelEntity(subnetJsonStream1, NeutronSubnet.class);
444 }
445
446 private void createRouterInterfaceMap() {
447 routerInterface1 = new TestRouterInterface("router-id-1",
448 "subnet-id-1",
449 "router-interface-id-1",
450 "tenant-id-1");
451
452 osRouterInterfaceMap.put(routerInterface1.getPortId(), routerInterface1);
453 }
454
455 private void createRouterMap() {
456 InputStream routerStream1 = OpenstackRoutingIcmpHandlerTest.class
457 .getResourceAsStream("openstack-router-1.json");
458 router1 = (Router)
459 OpenstackNetworkingUtil.jsonToModelEntity(routerStream1, NeutronRouter.class);
460 osRouterMap.put(router1.getId(), router1);
461
462 }
463 private void createInstancePortMap() {
464 instancePort1 = DefaultInstancePort.builder()
465 .networkId("net-id-1")
466 .portId("ce705c24-c1ef-408a-bda3-7bbd946164ab")
467 .deviceId(srcDeviceId1)
468 .portNumber(srcPortNum1)
469 .ipAddress(srcIpPort1)
470 .macAddress(srcMacPort1)
471 .state(InstancePort.State.valueOf("ACTIVE"))
472 .build();
473
474 instancePort2 = DefaultInstancePort.builder()
475 .networkId("net-id-2")
476 .portId("port-id-2")
477 .deviceId(DeviceId.deviceId("of:000000000000000b"))
478 .portNumber(PortNumber.portNumber(2))
479 .ipAddress(IpAddress.valueOf("10.10.10.2"))
480 .macAddress(MacAddress.valueOf("22:33:44:55:66:11"))
481 .state(InstancePort.State.valueOf("ACTIVE"))
482 .build();
483
484 instancePort3 = DefaultInstancePort.builder()
485 .networkId("net-id-3")
486 .portId("port-id-3")
487 .deviceId(DeviceId.deviceId("of:000000000000000c"))
488 .oldDeviceId(DeviceId.deviceId("of:000000000000000d"))
489 .oldPortNumber(PortNumber.portNumber(4, "tap-4"))
490 .portNumber(PortNumber.portNumber(3, "tap-3"))
491 .ipAddress(IpAddress.valueOf("10.10.10.3"))
492 .macAddress(MacAddress.valueOf("33:44:55:66:11:22"))
493 .state(InstancePort.State.valueOf("ACTIVE"))
494 .build();
495
496 instancePortMap.put(instancePort1.portId(), instancePort1);
497 instancePortMap.put(instancePort2.portId(), instancePort2);
498 instancePortMap.put(instancePort3.portId(), instancePort3);
499 }
500
501
502 private class TestOpenstackNode extends OpenstackNodeAdapter {
503 public TestOpenstackNode() {
504 super();
505 }
506 @Override
507 public PortNumber uplinkPortNum() {
508 return PortNumber.portNumber(1);
509 }
510 }
511}