blob: 1206ce3d298f3ad237ca4239406cd89a662e35fc [file] [log] [blame]
Jian Li3e70d8a2018-03-28 13:56:41 +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;
Daniel Parkd9d4c292018-06-26 20:33:58 +090019import com.google.common.collect.Lists;
Jian Li3e70d8a2018-03-28 13:56:41 +090020import org.junit.After;
21import org.junit.Before;
22import org.junit.Test;
23import org.onlab.packet.DHCP;
24import org.onlab.packet.Ethernet;
25import org.onlab.packet.IPv4;
26import org.onlab.packet.Ip4Address;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.MacAddress;
29import org.onlab.packet.UDP;
30import org.onlab.packet.dhcp.DhcpOption;
31import org.onosproject.cfg.ComponentConfigAdapter;
32import org.onosproject.cluster.ClusterServiceAdapter;
33import org.onosproject.cluster.LeadershipServiceAdapter;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreServiceAdapter;
36import org.onosproject.core.DefaultApplicationId;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.HostId;
39import org.onosproject.net.PortNumber;
40import org.onosproject.net.packet.DefaultInboundPacket;
41import org.onosproject.net.packet.DefaultPacketContext;
42import org.onosproject.net.packet.InboundPacket;
43import org.onosproject.net.packet.OutboundPacket;
44import org.onosproject.net.packet.PacketContext;
45import org.onosproject.net.packet.PacketProcessor;
46import org.onosproject.net.packet.PacketServiceAdapter;
47import org.onosproject.openstacknetworking.api.InstancePort;
48import org.openstack4j.model.network.AllowedAddressPair;
49import org.openstack4j.model.network.HostRoute;
50import org.openstack4j.model.network.IP;
51import org.openstack4j.model.network.IPVersionType;
52import org.openstack4j.model.network.Ipv6AddressMode;
53import org.openstack4j.model.network.Ipv6RaMode;
54import org.openstack4j.model.network.Pool;
55import org.openstack4j.model.network.Port;
56import org.openstack4j.model.network.State;
57import org.openstack4j.model.network.Subnet;
58import org.openstack4j.model.network.builder.PortBuilder;
59import org.openstack4j.model.network.builder.SubnetBuilder;
60import org.openstack4j.openstack.networking.domain.NeutronIP;
61
62import java.nio.ByteBuffer;
63import java.util.ArrayList;
64import java.util.List;
65import java.util.Map;
66import java.util.Set;
67
68import static org.junit.Assert.assertEquals;
69import static org.junit.Assert.fail;
70import static org.onosproject.net.NetTestTools.connectPoint;
71
72/**
73 * Unit tests for Openstack switching DHCP handler.
74 */
75public class OpenstackSwitchingDhcpHandlerTest {
76
77 private OpenstackSwitchingDhcpHandler dhcpHandler;
78
79 protected PacketProcessor packetProcessor;
80
81 private static final HostId CLIENT_HOST =
82 HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a"));
83 private static final String EXPECTED_IP = "10.2.0.2";
84 private static final String EXPECTED_CIDR = "10.2.0.0/24";
85 private static final String EXPECTED_GATEWAY = "10.2.0.1";
86 private static final Ip4Address BROADCAST =
87 Ip4Address.valueOf("255.255.255.255");
88 private static final int TRANSACTION_ID = 1986;
89
90 private static final String IP_SUBNET_ID = "1";
91
92 private DHCP.MsgType testMsgType;
93
94 @Before
95 public void setUp() {
96 dhcpHandler = new OpenstackSwitchingDhcpHandler();
97 dhcpHandler.coreService = new TestCoreService();
98 dhcpHandler.configService = new TestConfigService();
99 dhcpHandler.packetService = new TestPacketService();
100 dhcpHandler.instancePortService = new TestInstancePortService();
101 dhcpHandler.osNetworkService = new TestOpenstackNetworkService();
102 dhcpHandler.osNodeService = new TestOpenstackNodeService();
103 dhcpHandler.osFlowRuleService = new TestOpenstackFlowRuleService();
104 dhcpHandler.clusterService = new TestClusterService();
105 dhcpHandler.leadershipService = new TestLeadershipService();
106 dhcpHandler.activate();
107 }
108
109 @After
110 public void tearDown() {
111 dhcpHandler.deactivate();
112 }
113
114 /**
115 * Tests the response to a DHCP Discover Packet.
116 */
117 @Test
118 public void testDiscover() {
119 Ethernet dhcpDiscover = constructDhcpPacket(DHCP.MsgType.DHCPDISCOVER);
120 testMsgType = DHCP.MsgType.DHCPDISCOVER;
121 sendPacket(dhcpDiscover);
122 }
123
124 /**
125 * Tests the response to a DHCP Request Packet.
126 */
127 @Test
128 public void testRequest() {
129 Ethernet dhcpRequest = constructDhcpPacket(DHCP.MsgType.DHCPREQUEST);
130 testMsgType = DHCP.MsgType.DHCPREQUEST;
131 sendPacket(dhcpRequest);
132 }
133
134 /**
135 * Sends an Ethernet packet to the process method of the Packet Processor.
136 *
137 * @param ethernet Ethernet packet
138 */
139 private void sendPacket(Ethernet ethernet) {
140 final ByteBuffer byteBuffer = ByteBuffer.wrap(ethernet.serialize());
141 InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1),
142 ethernet,
143 byteBuffer);
144
145 PacketContext context = new TestPacketContext(127L, inPacket, null, false);
146 packetProcessor.process(context);
147 }
148
149 /**
150 * Validates the contents of the packet sent by the OpenstackSwitchingDhcpHandler.
151 *
152 * @param packet Ethernet packet received
153 */
154 private void validatePacket(Ethernet packet) {
155 DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload();
156 assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT_HOST.mac());
157 assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP));
158 assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID);
159
160 if (testMsgType == DHCP.MsgType.DHCPDISCOVER) {
161 assertEquals(dhcpPacket.getPacketType(), DHCP.MsgType.DHCPOFFER);
162 }
163
164 if (testMsgType == DHCP.MsgType.DHCPREQUEST) {
165 assertEquals(dhcpPacket.getPacketType(), DHCP.MsgType.DHCPACK);
166 }
167 }
168
169 /**
170 * Constructs an Ethernet packet containing a DHCP payload.
171 *
172 * @param msgType DHCP message type
173 * @return Ethernet packet
174 */
175 private Ethernet constructDhcpPacket(DHCP.MsgType msgType) {
176
177 // Ethernet frame
178 Ethernet ethFrame = new Ethernet();
179 ethFrame.setSourceMACAddress(CLIENT_HOST.mac());
180 ethFrame.setDestinationMACAddress(MacAddress.BROADCAST);
181 ethFrame.setEtherType(Ethernet.TYPE_IPV4);
182 ethFrame.setVlanID((short) 2);
183
184 // IP packet
185 IPv4 ipv4Pkt = new IPv4();
186 ipv4Pkt.setSourceAddress(0);
187 ipv4Pkt.setDestinationAddress(BROADCAST.toInt());
188 ipv4Pkt.setTtl((byte) 127);
189
190 // UDP datagram
191 UDP udpDatagram = new UDP();
192 udpDatagram.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
193 udpDatagram.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
194
195 // DHCP payload
196 DHCP dhcp = new DHCP();
197
198 dhcp.setOpCode(DHCP.OPCODE_REQUEST);
199
200 dhcp.setYourIPAddress(0);
201 dhcp.setServerIPAddress(0);
202
203 dhcp.setTransactionId(TRANSACTION_ID);
204 dhcp.setClientHardwareAddress(CLIENT_HOST.mac().toBytes());
205 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
206 dhcp.setHardwareAddressLength((byte) 6);
207
208 // DHCP options start...
209 DhcpOption option = new DhcpOption();
210 List<DhcpOption> optionList = new ArrayList<>();
211
212 // DHCP message type
213 option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
214 option.setLength((byte) 1);
215 byte[] optionData = {(byte) msgType.getValue()};
216 option.setData(optionData);
217 optionList.add(option);
218
219 // DHCP requested IP address
220 option = new DhcpOption();
221 option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
222 option.setLength((byte) 4);
223 optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
224 option.setData(optionData);
225 optionList.add(option);
226
227 // DHCP options end...
228 option = new DhcpOption();
229 option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
230 option.setLength((byte) 1);
231 optionList.add(option);
232
233 dhcp.setOptions(optionList);
234
235 udpDatagram.setPayload(dhcp);
236 ipv4Pkt.setPayload(udpDatagram);
237 ethFrame.setPayload(ipv4Pkt);
238
239 return ethFrame;
240 }
241
242 /**
243 * Mocks the CoreService.
244 */
245 private class TestCoreService extends CoreServiceAdapter {
246
247 @Override
248 public ApplicationId registerApplication(String name) {
249 return new DefaultApplicationId(100, "dhcpTestApp");
250 }
251 }
252
253 /**
254 * Mocks the ComponentConfigRegistry.
255 */
256 private class TestConfigService extends ComponentConfigAdapter {
257 }
258
259 /**
260 * Mocks the ClusterService.
261 */
262 private class TestClusterService extends ClusterServiceAdapter {
263 }
264
265 /**
266 * Mocks the LeadershipService.
267 */
268 private class TestLeadershipService extends LeadershipServiceAdapter {
269 }
270
271 /**
272 * Mocks the InstancePortService.
273 */
274 private class TestInstancePortService extends InstancePortServiceAdapter {
275
276 @Override
277 public InstancePort instancePort(MacAddress macAddress) {
278 return new TestInstancePort();
279 }
280 }
281
282 /**
283 * Mocks the OpenstackNetworkService.
284 */
285 private class TestOpenstackNetworkService extends OpenstackNetworkServiceAdapter {
286 @Override
287 public Port port(String portId) {
288 return new TestPort();
289 }
290
291 @Override
292 public Subnet subnet(String subnetId) {
293 return new TestSubnet();
294 }
295
296 /**
297 * Mocks the Neutron port.
298 */
299 private class TestPort implements Port {
300
301 @Override
302 public State getState() {
303 return null;
304 }
305
306 @Override
307 public boolean isAdminStateUp() {
308 return false;
309 }
310
311 @Override
312 public String getNetworkId() {
313 return null;
314 }
315
316 @Override
317 public String getDeviceId() {
318 return null;
319 }
320
321 @Override
322 public String getDeviceOwner() {
323 return null;
324 }
325
326 @Override
327 public Set<? extends IP> getFixedIps() {
328 return ImmutableSet.of(new NeutronIP(EXPECTED_IP, IP_SUBNET_ID));
329 }
330
331 @Override
332 public Set<? extends AllowedAddressPair> getAllowedAddressPairs() {
333 return null;
334 }
335
336 @Override
337 public String getMacAddress() {
338 return null;
339 }
340
341 @Override
342 public List<String> getSecurityGroups() {
343 return null;
344 }
345
346 @Override
347 public Boolean isPortSecurityEnabled() {
348 return null;
349 }
350
351 @Override
352 public String getHostId() {
353 return null;
354 }
355
356 @Override
357 public String getVifType() {
358 return null;
359 }
360
361 @Override
362 public Map<String, Object> getVifDetails() {
363 return null;
364 }
365
366 @Override
367 public String getvNicType() {
368 return null;
369 }
370
371 @Override
372 public Map<String, Object> getProfile() {
373 return null;
374 }
375
376 @Override
377 public PortBuilder toBuilder() {
378 return null;
379 }
380
381 @Override
382 public String getTenantId() {
383 return null;
384 }
385
386 @Override
387 public void setTenantId(String tenantId) {
388
389 }
390
391 @Override
392 public String getName() {
393 return null;
394 }
395
396 @Override
397 public void setName(String name) {
398
399 }
400
401 @Override
402 public String getId() {
403 return null;
404 }
405
406 @Override
407 public void setId(String id) {
408
409 }
410 }
411
412 /**
413 * Mocks the Neutron subnet.
414 */
415 private class TestSubnet implements Subnet {
416
417 @Override
418 public boolean isDHCPEnabled() {
419 return false;
420 }
421
422 @Override
423 public String getNetworkId() {
424 return null;
425 }
426
427 @Override
428 public List<String> getDnsNames() {
Daniel Park4d421002018-07-27 23:36:57 +0900429 return Lists.newArrayList();
Jian Li3e70d8a2018-03-28 13:56:41 +0900430 }
431
432 @Override
433 public List<? extends Pool> getAllocationPools() {
434 return null;
435 }
436
437 @Override
438 public List<? extends HostRoute> getHostRoutes() {
Daniel Parkd9d4c292018-06-26 20:33:58 +0900439 return Lists.newArrayList();
Jian Li3e70d8a2018-03-28 13:56:41 +0900440 }
441
442 @Override
443 public IPVersionType getIpVersion() {
444 return null;
445 }
446
447 @Override
448 public String getGateway() {
449 return EXPECTED_GATEWAY;
450 }
451
452 @Override
453 public String getCidr() {
454 return EXPECTED_CIDR;
455 }
456
457 @Override
458 public Ipv6AddressMode getIpv6AddressMode() {
459 return null;
460 }
461
462 @Override
463 public Ipv6RaMode getIpv6RaMode() {
464 return null;
465 }
466
467 @Override
468 public SubnetBuilder toBuilder() {
469 return null;
470 }
471
472 @Override
473 public String getTenantId() {
474 return null;
475 }
476
477 @Override
478 public void setTenantId(String tenantId) {
479
480 }
481
482 @Override
483 public String getName() {
484 return null;
485 }
486
487 @Override
488 public void setName(String name) {
489
490 }
491
492 @Override
493 public String getId() {
494 return null;
495 }
496
497 @Override
498 public void setId(String id) {
499
500 }
501 }
502 }
503
504 /**
505 * Mocks the OpenstackNodeService.
506 */
507 private class TestOpenstackNodeService extends OpenstackNodeServiceAdapter {
508
509 }
510
511 /**
512 * Mocks the OpenstackFlowRuleService.
513 */
514 private class TestOpenstackFlowRuleService extends OpenstackFlowRuleServiceAdapter {
515 }
516
517 /**
518 * Mocks the instance port.
519 */
520 private final class TestInstancePort implements InstancePort {
521
522 @Override
523 public String networkId() {
524 return null;
525 }
526
527 @Override
528 public String portId() {
529 return null;
530 }
531
532 @Override
533 public MacAddress macAddress() {
534 return null;
535 }
536
537 @Override
538 public IpAddress ipAddress() {
539 return IpAddress.valueOf(EXPECTED_IP);
540 }
541
542 @Override
543 public DeviceId deviceId() {
544 return null;
545 }
546
547 @Override
Jian Liec5c32b2018-07-13 14:28:58 +0900548 public DeviceId oldDeviceId() {
549 return null;
550 }
551
552 @Override
Jian Li3e70d8a2018-03-28 13:56:41 +0900553 public PortNumber portNumber() {
554 return null;
555 }
Jian Liecae4382018-06-28 17:41:12 +0900556
557 @Override
Jian Liec5c32b2018-07-13 14:28:58 +0900558 public PortNumber oldPortNumber() {
559 return null;
560 }
561
562 @Override
Jian Liecae4382018-06-28 17:41:12 +0900563 public State state() {
564 return null;
565 }
566
567 @Override
568 public InstancePort updateState(State newState) {
569 return null;
570 }
Jian Liec5c32b2018-07-13 14:28:58 +0900571
572 @Override
Jian Li46b74002018-07-15 18:39:08 +0900573 public InstancePort updatePrevLocation(DeviceId oldDeviceId, PortNumber oldPortNumber) {
Jian Liec5c32b2018-07-13 14:28:58 +0900574 return null;
575 }
Jian Li3e70d8a2018-03-28 13:56:41 +0900576 }
577
578 /**
579 * Mocks the DefaultPacket context.
580 */
581 private final class TestPacketContext extends DefaultPacketContext {
582 private TestPacketContext(long time, InboundPacket inPkt,
583 OutboundPacket outPkt, boolean block) {
584 super(time, inPkt, outPkt, block);
585 }
586
587 @Override
588 public void send() {
589 // We don't send anything out.
590 }
591 }
592
593 /**
594 * Keeps a reference to the PacketProcessor and verifies the OutboundPackets.
595 */
596 private class TestPacketService extends PacketServiceAdapter {
597
598 @Override
599 public void addProcessor(PacketProcessor processor, int priority) {
600 packetProcessor = processor;
601 }
602
603 @Override
604 public void emit(OutboundPacket packet) {
605 try {
606 Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
607 0, packet.data().array().length);
608 validatePacket(eth);
609 } catch (Exception e) {
610 fail(e.getMessage());
611 }
612 }
613 }
614}