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