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