blob: ccecb51b3c3dca2f7e49b270c9b457a3fc52fb90 [file] [log] [blame]
Amit Ghosh8951f042017-08-10 13:48:10 +01001/*
2 * Copyright 2017-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 */
16
Matteo Scandolo57af5d12019-04-29 17:11:41 -070017package org.opencord.dhcpl2relay.impl;
Amit Ghosh8951f042017-08-10 13:48:10 +010018
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030019import static com.google.common.base.Preconditions.checkState;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.fail;
22
23import java.nio.ByteBuffer;
24import java.nio.charset.StandardCharsets;
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Dictionary;
28import java.util.Hashtable;
29import java.util.LinkedList;
30import java.util.List;
31import java.util.Set;
32import java.util.concurrent.Callable;
33import java.util.concurrent.ExecutionException;
34import java.util.concurrent.Future;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030035import java.util.concurrent.ScheduledExecutorService;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -070036import java.util.concurrent.ScheduledFuture;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030037import java.util.concurrent.TimeUnit;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -070038import java.util.concurrent.TimeoutException;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030039
Amit Ghosh8951f042017-08-10 13:48:10 +010040import org.onlab.packet.BasePacket;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030041import org.onlab.packet.ChassisId;
Amit Ghosh8951f042017-08-10 13:48:10 +010042import org.onlab.packet.DHCP;
Amit Ghosh8951f042017-08-10 13:48:10 +010043import org.onlab.packet.Ethernet;
44import org.onlab.packet.IPv4;
45import org.onlab.packet.Ip4Address;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -070046import org.onlab.packet.IpAddress;
Amit Ghosh8951f042017-08-10 13:48:10 +010047import org.onlab.packet.MacAddress;
48import org.onlab.packet.UDP;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030049import org.onlab.packet.VlanId;
Jonathan Hartedbf6422018-05-02 17:30:05 -070050import org.onlab.packet.dhcp.DhcpOption;
Saurav Dasb4e3e102018-10-02 15:31:17 -070051import org.onosproject.core.ApplicationId;
52import org.onosproject.core.CoreServiceAdapter;
53import org.onosproject.core.DefaultApplicationId;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030054import org.onosproject.event.DefaultEventSinkRegistry;
55import org.onosproject.event.Event;
56import org.onosproject.event.EventDeliveryService;
57import org.onosproject.event.EventSink;
58import org.onosproject.mastership.MastershipServiceAdapter;
59import org.onosproject.net.AnnotationKeys;
60import org.onosproject.net.Annotations;
Amit Ghosh8951f042017-08-10 13:48:10 +010061import org.onosproject.net.ConnectPoint;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030062import org.onosproject.net.DefaultAnnotations;
63import org.onosproject.net.DefaultDevice;
64import org.onosproject.net.DefaultHost;
65import org.onosproject.net.Device;
66import org.onosproject.net.DeviceId;
67import org.onosproject.net.Element;
68import org.onosproject.net.Host;
69import org.onosproject.net.HostId;
70import org.onosproject.net.HostLocation;
71import org.onosproject.net.Port;
72import org.onosproject.net.PortNumber;
73import org.onosproject.net.device.DeviceServiceAdapter;
74import org.onosproject.net.host.HostServiceAdapter;
Amit Ghosh8951f042017-08-10 13:48:10 +010075import org.onosproject.net.packet.DefaultInboundPacket;
76import org.onosproject.net.packet.DefaultPacketContext;
77import org.onosproject.net.packet.InboundPacket;
78import org.onosproject.net.packet.OutboundPacket;
79import org.onosproject.net.packet.PacketContext;
80import org.onosproject.net.packet.PacketProcessor;
81import org.onosproject.net.packet.PacketServiceAdapter;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030082import org.onosproject.net.provider.ProviderId;
Saurav Das45861d42020-10-07 00:03:23 -070083import org.opencord.dhcpl2relay.impl.packet.DhcpOption82Data;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030084import org.opencord.sadis.BandwidthProfileInformation;
85import org.opencord.sadis.BaseInformationService;
86import org.opencord.sadis.SadisService;
87import org.opencord.sadis.SubscriberAndDeviceInformation;
Gamze Abakaa64b3bc2020-01-31 06:51:43 +000088import org.opencord.sadis.UniTagInformation;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -030089import org.osgi.framework.Bundle;
90import org.osgi.framework.BundleContext;
91import org.osgi.framework.ServiceReference;
92import org.osgi.service.component.ComponentContext;
93import org.osgi.service.component.ComponentInstance;
Amit Ghosh8951f042017-08-10 13:48:10 +010094import org.slf4j.Logger;
95import org.slf4j.LoggerFactory;
96
Saurav Dasbd5ce9c2020-09-04 18:46:45 -070097import com.google.common.collect.ImmutableSet;
98
Amit Ghosh8951f042017-08-10 13:48:10 +010099
100/**
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700101 * Common methods for DHCP app testing.
Amit Ghosh8951f042017-08-10 13:48:10 +0100102 */
103public class DhcpL2RelayTestBase {
104 private final Logger log = LoggerFactory.getLogger(getClass());
105
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000106 static final VlanId CLIENT_C_TAG = VlanId.vlanId((short) 2);
107 static final VlanId CLIENT_S_TAG = VlanId.vlanId((short) 4);
108 static final short CLIENT_C_PBIT = 7;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300109 static final String CLIENT_ID_1 = "SUBSCRIBER_ID_1";
110 static final String CLIENT_NAS_PORT_ID = "PON 1/1";
111 static final String CLIENT_CIRCUIT_ID = "CIR-PON 1/1";
Saurav Das45861d42020-10-07 00:03:23 -0700112 static final String CLIENT32_CIRCUIT_ID = "";
113 static final String CLIENT4112_CIRCUIT_ID = null;
114 public static final String CLIENT_REMOTE_ID = "I am an RG";
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000115 static final short NOT_PROVIDED = 0;
Amit Ghosh8951f042017-08-10 13:48:10 +0100116
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300117 static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
118 static final MacAddress SERVER_MAC = MacAddress.valueOf("bb:bb:bb:bb:bb:bb");
119 static final String DESTINATION_ADDRESS_IP = "1.1.1.1";
120 static final String DHCP_CLIENT_IP_ADDRESS = "2.2.2.2";
121 static final int UPLINK_PORT = 5;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700122 static final int CLIENT_PORT = 1;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300123
124 static final String EXPECTED_IP = "10.2.0.2";
125 static final String OLT_DEV_ID = "of:00000000000000aa";
126 static final DeviceId DEVICE_ID_1 = DeviceId.deviceId(OLT_DEV_ID);
127 static final int TRANSACTION_ID = 1000;
128 static final String SCHEME_NAME = "dhcpl2relay";
129 static final MacAddress OLT_MAC_ADDRESS = MacAddress.valueOf("01:02:03:04:05:06");
130
131 static final ConnectPoint SERVER_CONNECT_POINT =
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700132 ConnectPoint.deviceConnectPoint("of:00000000000000aa/" +
133 String.valueOf(UPLINK_PORT));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300134
135 static final DefaultAnnotations DEVICE_ANNOTATIONS = DefaultAnnotations.builder()
136 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase()).build();
Amit Ghosh8951f042017-08-10 13:48:10 +0100137
Saurav Das45861d42020-10-07 00:03:23 -0700138
Amit Ghosh8951f042017-08-10 13:48:10 +0100139 List<BasePacket> savedPackets = new LinkedList<>();
140 PacketProcessor packetProcessor;
141
142
143 /**
144 * Saves the given packet onto the saved packets list.
145 *
146 * @param packet packet to save
147 */
148 void savePacket(BasePacket packet) {
149 savedPackets.add(packet);
150 }
151
152 BasePacket getPacket() {
153 return savedPackets.remove(0);
154 }
155
156 /**
Saurav Dasb4e3e102018-10-02 15:31:17 -0700157 * Mock core service adaptor that provides an appId.
158 */
159 class MockCoreServiceAdapter extends CoreServiceAdapter {
160
161 @Override
162 public ApplicationId registerApplication(String name) {
163 return new DefaultApplicationId(10, name);
164 }
165 }
166
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300167 class MockDeviceService extends DeviceServiceAdapter {
168
169 private ProviderId providerId = new ProviderId("of", "foo");
170 private final Device device1 = new DhcpL2RelayTestBase.MockDevice(providerId, DEVICE_ID_1, Device.Type.SWITCH,
171 "foo.inc", "0", "0", OLT_DEV_ID, new ChassisId(),
172 DEVICE_ANNOTATIONS);
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700173 private final Device otherDevice = new DhcpL2RelayTestBase.MockDevice(
174 providerId,
175 DeviceId.deviceId("of:0000b86a974385f7"),
176 Device.Type.SWITCH,
177 "foo.inc", "0", "0", "EC1838000853", new ChassisId(),
178 DEVICE_ANNOTATIONS);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300179 @Override
180 public Device getDevice(DeviceId devId) {
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700181 if (devId.equals(DEVICE_ID_1)) {
182 return device1;
183 } else {
184 return otherDevice;
185 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300186 }
187
188 @Override
189 public Port getPort(ConnectPoint cp) {
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700190 return new DhcpL2RelayTestBase.MockPort(cp);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300191 }
192
193 @Override
194 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700195 return new DhcpL2RelayTestBase.MockPort(new ConnectPoint(deviceId,
196 portNumber));
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300197 }
198
199 @Override
200 public boolean isAvailable(DeviceId d) {
201 return true;
202 }
203 }
204
205 class MockDevice extends DefaultDevice {
206
207 public MockDevice(ProviderId providerId, DeviceId id, Type type,
208 String manufacturer, String hwVersion, String swVersion,
209 String serialNumber, ChassisId chassisId, Annotations... annotations) {
210 super(providerId, id, type, manufacturer, hwVersion, swVersion, serialNumber,
211 chassisId, annotations);
212 }
213 }
214
215 class MockHostService extends HostServiceAdapter {
216
217 @Override
218 public Set<Host> getHostsByMac(MacAddress mac) {
219
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700220 HostLocation loc = new HostLocation(DEVICE_ID_1, PortNumber
221 .portNumber(CLIENT_PORT), 0);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300222
223 IpAddress ip = IpAddress.valueOf("10.100.200.10");
224
225 Host h = new DefaultHost(ProviderId.NONE, HostId.hostId(mac, VlanId.NONE),
226 mac, VlanId.NONE, loc, ImmutableSet.of(ip));
227
228 return ImmutableSet.of(h);
229 }
230 }
231
232 class MockMastershipService extends MastershipServiceAdapter {
233 @Override
234 public boolean isLocalMaster(DeviceId d) {
235 return true;
236 }
237 }
238
239 class MockPort implements Port {
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700240 private ConnectPoint cp;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300241
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700242 public MockPort(ConnectPoint cp) {
243 this.cp = cp;
244 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300245 @Override
246 public boolean isEnabled() {
247 return true;
248 }
249 @Override
250 public long portSpeed() {
251 return 1000;
252 }
253 @Override
254 public Element element() {
255 return null;
256 }
257 @Override
258 public PortNumber number() {
259 return null;
260 }
261 @Override
262 public Annotations annotations() {
263 return new MockAnnotations();
264 }
265 @Override
266 public Type type() {
267 return Port.Type.FIBER;
268 }
269
270 private class MockAnnotations implements Annotations {
271
272 @Override
273 public String value(String val) {
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700274 if (cp.port().toLong() == 32) {
275 return "ALPHe3d1cea3-1";
276 } else if (cp.port().toLong() == 4112) {
277 return "ALPHe3d1ceb7-1";
278 } else {
279 return "PON 1/1";
280 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300281 }
282 @Override
283 public Set<String> keys() {
284 return null;
285 }
286 }
287 }
288
Saurav Dasb4e3e102018-10-02 15:31:17 -0700289 /**
Amit Ghosh8951f042017-08-10 13:48:10 +0100290 * Keeps a reference to the PacketProcessor and saves the OutboundPackets.
291 */
292 class MockPacketService extends PacketServiceAdapter {
293
294 @Override
295 public void addProcessor(PacketProcessor processor, int priority) {
296 packetProcessor = processor;
297 }
298
299 @Override
300 public void emit(OutboundPacket packet) {
301 try {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530302 Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(),
Amit Ghosh8951f042017-08-10 13:48:10 +0100303 0, packet.data().array().length);
304 savePacket(eth);
305 } catch (Exception e) {
306 fail(e.getMessage());
307 }
308 }
309 }
310
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300311 class MockSadisService implements SadisService {
312 @Override
313 public BaseInformationService<SubscriberAndDeviceInformation> getSubscriberInfoService() {
314 return new DhcpL2RelayTestBase.MockSubService();
315 }
316
317 @Override
318 public BaseInformationService<BandwidthProfileInformation> getBandwidthProfileService() {
319 return null;
320 }
321 }
322
323 class MockSubService implements BaseInformationService<SubscriberAndDeviceInformation> {
324 DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation device =
325 new DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation(OLT_DEV_ID, VlanId.NONE, VlanId.NONE, null,
326 null, OLT_MAC_ADDRESS, Ip4Address.valueOf("10.10.10.10"), UPLINK_PORT);
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700327 DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation otherDevice =
328 new DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation(
329 "EC1838000853", VlanId.NONE, VlanId.NONE, null,
330 null, OLT_MAC_ADDRESS, Ip4Address.valueOf("10.10.10.10"), UPLINK_PORT);
331
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300332 DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation sub =
333 new DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation(CLIENT_ID_1, CLIENT_C_TAG,
334 CLIENT_S_TAG, CLIENT_NAS_PORT_ID, CLIENT_CIRCUIT_ID, null, null, -1);
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700335 DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation sub32 =
336 new DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation("ALPHe3d1cea3-1", VlanId.vlanId((short) 801),
Saurav Das45861d42020-10-07 00:03:23 -0700337 VlanId.vlanId((short) 111), CLIENT_NAS_PORT_ID, CLIENT32_CIRCUIT_ID, null, null, -1);
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700338 DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation sub4112 =
339 new DhcpL2RelayTestBase.MockSubscriberAndDeviceInformation("ALPHe3d1ceb7-1", VlanId.vlanId((short) 101),
Saurav Das45861d42020-10-07 00:03:23 -0700340 VlanId.vlanId((short) 222), CLIENT_NAS_PORT_ID, CLIENT4112_CIRCUIT_ID, null, null, -1);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300341 @Override
342 public SubscriberAndDeviceInformation get(String id) {
343 if (id.equals(OLT_DEV_ID)) {
344 return device;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700345 } else if (id.equals("EC1838000853")) {
346 return otherDevice;
347 } else if (id.equals("ALPHe3d1cea3-1")) {
348 return sub32;
349 } else if (id.equals("ALPHe3d1ceb7-1")) {
350 return sub4112;
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300351 } else {
352 return sub;
353 }
354 }
355
356 @Override
357 public void invalidateAll() {}
358 @Override
359 public void invalidateId(String id) {}
360 @Override
361 public SubscriberAndDeviceInformation getfromCache(String id) {
362 return null;
363 }
364 }
365
366 class MockSubscriberAndDeviceInformation extends SubscriberAndDeviceInformation {
367
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000368 MockSubscriberAndDeviceInformation(String id, VlanId cTag,
369 VlanId sTag, String nasPortId,
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300370 String circuitId, MacAddress hardId,
371 Ip4Address ipAddress, int uplinkPort) {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300372 this.setHardwareIdentifier(hardId);
373 this.setId(id);
374 this.setIPAddress(ipAddress);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300375 this.setNasPortId(nasPortId);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300376 this.setUplinkPort(uplinkPort);
Saurav Das45861d42020-10-07 00:03:23 -0700377 this.setCircuitId(circuitId);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000378
379 List<UniTagInformation> uniTagInformationList = new ArrayList<>();
380
Saurav Das45861d42020-10-07 00:03:23 -0700381 UniTagInformation.Builder b = new UniTagInformation.Builder()
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000382 .setPonCTag(cTag)
383 .setPonSTag(sTag)
384 .setUsPonCTagPriority(CLIENT_C_PBIT)
Saurav Das45861d42020-10-07 00:03:23 -0700385 .setIsDhcpRequired(true);
386
387 if (id.equals("ALPHe3d1ceb7-1")) {
388 // null remoteId, ds pbit is defined
389 b.setDsPonCTagPriority(5);
390 } else {
391 this.setRemoteId(CLIENT_REMOTE_ID);
392 }
393
394 uniTagInformationList.add(b.build());
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700395
396 if (id.equals("ALPHe3d1cea3-1")) {
397 // a second service on the same UNI
Saurav Das45861d42020-10-07 00:03:23 -0700398 UniTagInformation uniTagInformation = new UniTagInformation.Builder()
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700399 .setPonCTag(VlanId.vlanId(((short) (cTag.toShort() + 1))))
400 .setPonSTag(sTag)
401 .setUsPonCTagPriority(CLIENT_C_PBIT)
402 .setIsDhcpRequired(true)
403 .build();
404 uniTagInformationList.add(uniTagInformation);
405 }
406
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000407 this.setUniTagList(uniTagInformationList);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300408 }
409 }
410
411 class MockComponentContext implements ComponentContext {
412
413 @Override
414 public Dictionary<String, Object> getProperties() {
415 Dictionary<String, Object> cfgDict = new Hashtable<String, Object>();
416 cfgDict.put("publishCountersRate", 10);
417 return cfgDict;
418 }
419
420 @Override
421 public Object locateService(String name) {
422 // TODO Auto-generated method stub
423 return null;
424 }
425
426 @Override
427 public Object locateService(String name, ServiceReference reference) {
428 // TODO Auto-generated method stub
429 return null;
430 }
431
432 @Override
433 public Object[] locateServices(String name) {
434 // TODO Auto-generated method stub
435 return null;
436 }
437
438 @Override
439 public BundleContext getBundleContext() {
440 // TODO Auto-generated method stub
441 return null;
442 }
443
444 @Override
445 public Bundle getUsingBundle() {
446 // TODO Auto-generated method stub
447 return null;
448 }
449
450 @Override
451 public ComponentInstance getComponentInstance() {
452 // TODO Auto-generated method stub
453 return null;
454 }
455
456 @Override
457 public void enableComponent(String name) {
458 // TODO Auto-generated method stub
459 }
460
461 @Override
462 public void disableComponent(String name) {
463 // TODO Auto-generated method stub
464 }
465
466 @Override
467 public ServiceReference getServiceReference() {
468 // TODO Auto-generated method stub
469 return null;
470 }
471 }
472
473
Amit Ghosh8951f042017-08-10 13:48:10 +0100474 /**
475 * Mocks the DefaultPacketContext.
476 */
477 final class TestPacketContext extends DefaultPacketContext {
478
479 private TestPacketContext(long time, InboundPacket inPkt,
480 OutboundPacket outPkt, boolean block) {
481 super(time, inPkt, outPkt, block);
482 }
483
484 @Override
485 public void send() {
486 // We don't send anything out.
487 }
488 }
489
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300490 public static class TestEventDispatcher extends DefaultEventSinkRegistry
491 implements EventDeliveryService {
492 @Override
493 @SuppressWarnings("unchecked")
494 public synchronized void post(Event event) {
495 EventSink sink = getSink(event.getClass());
496 checkState(sink != null, "No sink for event %s", event);
497 sink.process(event);
498 }
499
500 @Override
501 public void setDispatchTimeLimit(long millis) {
502 }
503
504 @Override
505 public long getDispatchTimeLimit() {
506 return 0;
507 }
508 }
509
510 /**
511 * Creates a mock object for a scheduled executor service.
512 *
513 */
514 public static final class MockExecutor implements ScheduledExecutorService {
515 private ScheduledExecutorService executor;
516
517 MockExecutor(ScheduledExecutorService executor) {
518 this.executor = executor;
519 }
520
521 String lastMethodCalled = "";
522 long lastInitialDelay;
523 long lastDelay;
524 TimeUnit lastUnit;
525
526 public void assertLastMethodCalled(String method, long initialDelay, long delay, TimeUnit unit) {
527 assertEquals(method, lastMethodCalled);
528 assertEquals(initialDelay, lastInitialDelay);
529 assertEquals(delay, lastDelay);
530 assertEquals(unit, lastUnit);
531 }
532
533 @Override
534 public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
535 lastMethodCalled = "scheduleRunnable";
536 lastDelay = delay;
537 lastUnit = unit;
538 return null;
539 }
540
541 @Override
542 public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
543 lastMethodCalled = "scheduleCallable";
544 lastDelay = delay;
545 lastUnit = unit;
546 return null;
547 }
548
549 @Override
550 public ScheduledFuture<?> scheduleAtFixedRate(
551 Runnable command, long initialDelay, long period, TimeUnit unit) {
552 lastMethodCalled = "scheduleAtFixedRate";
553 lastInitialDelay = initialDelay;
554 lastDelay = period;
555 lastUnit = unit;
556 return null;
557 }
558
559 @Override
560 public ScheduledFuture<?> scheduleWithFixedDelay(
561 Runnable command, long initialDelay, long delay, TimeUnit unit) {
562 lastMethodCalled = "scheduleWithFixedDelay";
563 lastInitialDelay = initialDelay;
564 lastDelay = delay;
565 lastUnit = unit;
566 command.run();
567 return null;
568 }
569
570 @Override
571 public boolean awaitTermination(long timeout, TimeUnit unit) {
572 throw new UnsupportedOperationException();
573 }
574
575 @Override
576 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
577 throws InterruptedException {
578 throw new UnsupportedOperationException();
579 }
580
581 @Override
582 public <T> List<Future<T>> invokeAll(
583 Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
584 throws InterruptedException {
585 throw new UnsupportedOperationException();
586 }
587
588 @Override
Matteo Scandoloabcc73e2020-11-25 16:02:17 -0800589 @SuppressWarnings({"TypeParameterUnusedInFormals"})
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300590 public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
591 throws ExecutionException, InterruptedException {
592 throw new UnsupportedOperationException();
593 }
594
595 @Override
Matteo Scandoloabcc73e2020-11-25 16:02:17 -0800596 @SuppressWarnings({"TypeParameterUnusedInFormals"})
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300597 public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
598 throws ExecutionException, InterruptedException, TimeoutException {
599 throw new UnsupportedOperationException();
600 }
601
602 @Override
603 public boolean isShutdown() {
604 throw new UnsupportedOperationException();
605 }
606
607 @Override
608 public boolean isTerminated() {
609 throw new UnsupportedOperationException();
610 }
611
612 @Override
613 public void shutdown() {
614 throw new UnsupportedOperationException();
615 }
616
617 @Override
618 public List<Runnable> shutdownNow() {
619 return null;
620 }
621
622 @Override
Matteo Scandoloabcc73e2020-11-25 16:02:17 -0800623 @SuppressWarnings({"TypeParameterUnusedInFormals"})
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300624 public <T> Future<T> submit(Callable<T> task) {
625 throw new UnsupportedOperationException();
626 }
627
628 @Override
629 public Future<?> submit(Runnable task) {
630 throw new UnsupportedOperationException();
631 }
632
633 @Override
634 public <T> Future<T> submit(Runnable task, T result) {
635 throw new UnsupportedOperationException();
636 }
637
638 @Override
639 public void execute(Runnable command) {
640 throw new UnsupportedOperationException();
641 }
642 }
643
Amit Ghosh8951f042017-08-10 13:48:10 +0100644 /**
645 * Sends an Ethernet packet to the process method of the Packet Processor.
646 *
647 * @param pkt Ethernet packet
648 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530649 void sendPacket(Ethernet pkt, ConnectPoint cp) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100650 final ByteBuffer byteBuffer = ByteBuffer.wrap(pkt.serialize());
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530651 InboundPacket inPacket = new DefaultInboundPacket(cp, pkt, byteBuffer);
Amit Ghosh8951f042017-08-10 13:48:10 +0100652
653 PacketContext context = new TestPacketContext(127L, inPacket, null, false);
654 packetProcessor.process(context);
655 }
656
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700657 private Ethernet constructEthernetPacket(MacAddress srcMac, MacAddress dstMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100658 String dstIp, byte dhcpReqRsp,
659 MacAddress clientHwAddress,
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700660 Ip4Address dhcpClientIpAddress,
661 VlanId clientVlan, short clientPbit) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100662 // Ethernet Frame.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530663 Ethernet ethPkt = new Ethernet();
664 ethPkt.setSourceMACAddress(srcMac);
665 ethPkt.setDestinationMACAddress(dstMac);
Amit Ghosh8951f042017-08-10 13:48:10 +0100666 ethPkt.setEtherType(Ethernet.TYPE_IPV4);
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700667 ethPkt.setVlanID(clientVlan.toShort());
668 ethPkt.setPriorityCode((byte) clientPbit);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000669
670 if (DHCP.OPCODE_REPLY == dhcpReqRsp) {
671 ethPkt.setQinQPriorityCode((byte) 3);
672 ethPkt.setQinQVID((short) 4);
673 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100674
675 // IP Packet
676 IPv4 ipv4Reply = new IPv4();
677 ipv4Reply.setSourceAddress(0);
678 ipv4Reply.setDestinationAddress(dstIp);
679
680 ipv4Reply.setTtl((byte) 127);
681
682 // UDP Datagram.
683 UDP udpReply = new UDP();
684 udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
685 udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
686
687 // DHCP Payload.
688 DHCP dhcpReply = new DHCP();
689 dhcpReply.setOpCode(dhcpReqRsp);
690
691 dhcpReply.setYourIPAddress(dhcpClientIpAddress.toInt());
692 dhcpReply.setServerIPAddress(0);
693
694 final byte[] serverNameBytes = new byte[64];
695 String result = new String(serverNameBytes, StandardCharsets.US_ASCII).trim();
696 dhcpReply.setServerName(result);
697
698 final byte[] bootFileBytes = new byte[128];
699 String result1 = new String(bootFileBytes, StandardCharsets.US_ASCII).trim();
700 dhcpReply.setBootFileName(result1);
701
702 dhcpReply.setTransactionId(TRANSACTION_ID);
703 dhcpReply.setClientHardwareAddress(clientHwAddress.toBytes());
704 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
705 dhcpReply.setHardwareAddressLength((byte) 6);
706
707 udpReply.setPayload(dhcpReply);
708 ipv4Reply.setPayload(udpReply);
709 ethPkt.setPayload(ipv4Reply);
710
711 return ethPkt;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700712
713 }
714
715 /**
716 * Constructs an Ethernet packet with IP/UDP/DHCP payload and client
717 * VLAN information.
718 *
719 * @return Ethernet packet
720 */
721 private Ethernet construcEthernetPacket(MacAddress srcMac, MacAddress dstMac,
722 String dstIp, byte dhcpReqRsp,
723 MacAddress clientHwAddress,
724 Ip4Address dhcpClientIpAddress) {
725 return constructEthernetPacket(srcMac, dstMac, dstIp, dhcpReqRsp,
726 clientHwAddress, dhcpClientIpAddress,
727 CLIENT_C_TAG, CLIENT_C_PBIT);
728
Amit Ghosh8951f042017-08-10 13:48:10 +0100729 }
730
731 /**
732 * Constructs DHCP Discover Packet.
733 *
734 * @return Ethernet packet
735 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530736 Ethernet constructDhcpDiscoverPacket(MacAddress clientMac) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530737 Ethernet pkt = construcEthernetPacket(clientMac, MacAddress.BROADCAST,
Saurav Das45861d42020-10-07 00:03:23 -0700738 "255.255.255.255",
739 DHCP.OPCODE_REQUEST, clientMac,
740 Ip4Address.valueOf("0.0.0.0"));
Amit Ghosh8951f042017-08-10 13:48:10 +0100741
742 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
743 UDP udpPacket = (UDP) ipv4Packet.getPayload();
744 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
745
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700746 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPDISCOVER));
Saurav Das45861d42020-10-07 00:03:23 -0700747 log.info("Sending discover packet {}", dhcpPacket.getOptions());
Amit Ghosh8951f042017-08-10 13:48:10 +0100748
749 return pkt;
750 }
751
752 /**
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700753 * Constructs DHCP Discover Packet with client VLAN information.
754 *
755 * @return Ethernet packet
756 */
757 Ethernet constructDhcpDiscoverPacket(MacAddress clientMac, VlanId clientVlan,
758 short clientPbit) {
759 Ethernet pkt = constructEthernetPacket(clientMac, MacAddress.BROADCAST,
760 "255.255.255.255", DHCP.OPCODE_REQUEST, clientMac,
761 Ip4Address.valueOf("0.0.0.0"), clientVlan, clientPbit);
762
763 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
764 UDP udpPacket = (UDP) ipv4Packet.getPayload();
765 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
766
767 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPDISCOVER));
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700768 return pkt;
769 }
770
771 /**
Amit Ghosh8951f042017-08-10 13:48:10 +0100772 * Constructs DHCP Request Packet.
773 *
774 * @return Ethernet packet
775 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530776 Ethernet constructDhcpRequestPacket(MacAddress clientMac) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530777 Ethernet pkt = construcEthernetPacket(clientMac, MacAddress.BROADCAST,
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700778 "255.255.255.255", DHCP.OPCODE_REQUEST, clientMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100779 Ip4Address.valueOf("0.0.0.0"));
780
781 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
782 UDP udpPacket = (UDP) ipv4Packet.getPayload();
783 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
784
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700785 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPREQUEST));
Amit Ghosh8951f042017-08-10 13:48:10 +0100786
787 return pkt;
788 }
789
790 /**
791 * Constructs DHCP Offer Packet.
792 *
793 * @return Ethernet packet
794 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530795 Ethernet constructDhcpOfferPacket(MacAddress servMac, MacAddress clientMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100796 String ipAddress, String dhcpClientIpAddress) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530797 Ethernet pkt = construcEthernetPacket(servMac, clientMac, ipAddress, DHCP.OPCODE_REPLY,
Amit Ghosh8951f042017-08-10 13:48:10 +0100798 clientMac, Ip4Address.valueOf(dhcpClientIpAddress));
799
800 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
801 UDP udpPacket = (UDP) ipv4Packet.getPayload();
802 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
803
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700804 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPOFFER));
Saurav Das45861d42020-10-07 00:03:23 -0700805 log.info("Sending offer packet {}", dhcpPacket.getOptions());
Amit Ghosh8951f042017-08-10 13:48:10 +0100806 return pkt;
807 }
808
809 /**
810 * Constructs DHCP Ack Packet.
811 *
812 * @return Ethernet packet
813 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530814 Ethernet constructDhcpAckPacket(MacAddress servMac, MacAddress clientMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100815 String ipAddress, String dhcpClientIpAddress) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530816 Ethernet pkt = construcEthernetPacket(servMac, clientMac, ipAddress, DHCP.OPCODE_REPLY,
Amit Ghosh8951f042017-08-10 13:48:10 +0100817 clientMac, Ip4Address.valueOf(dhcpClientIpAddress));
818
819 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
820 UDP udpPacket = (UDP) ipv4Packet.getPayload();
821 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
822
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700823 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPACK));
Amit Ghosh8951f042017-08-10 13:48:10 +0100824
825 return pkt;
826 }
827
828 /**
Arjun E K05ad20b2020-03-13 13:25:17 +0000829 * Constructs DHCP Nak Packet.
830 *
831 * @return Ethernet packet
832 */
833 Ethernet constructDhcpNakPacket(MacAddress servMac, MacAddress clientMac,
Saurav Das45861d42020-10-07 00:03:23 -0700834 String ipAddress, String dhcpClientIpAddress,
835 VlanId clientVlan, short clientPcp) {
Arjun E K05ad20b2020-03-13 13:25:17 +0000836
Saurav Das45861d42020-10-07 00:03:23 -0700837 Ethernet pkt = constructEthernetPacket(servMac, clientMac, ipAddress,
838 DHCP.OPCODE_REPLY, clientMac,
839 Ip4Address.valueOf(dhcpClientIpAddress),
840 clientVlan, clientPcp);
Arjun E K05ad20b2020-03-13 13:25:17 +0000841
842 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
843 UDP udpPacket = (UDP) ipv4Packet.getPayload();
844 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
845
846 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPNAK));
847
848 return pkt;
849 }
850
851 /**
852 * Constructs DHCP Decline Packet.
853 *
854 * @return Ethernet packet
855 */
856 Ethernet constructDhcpDeclinePacket(MacAddress clientMac) {
857
858 Ethernet pkt = construcEthernetPacket(clientMac, MacAddress.BROADCAST,
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700859 "255.255.255.255", DHCP.OPCODE_REQUEST, clientMac,
Arjun E K05ad20b2020-03-13 13:25:17 +0000860 Ip4Address.valueOf("0.0.0.0"));
861
862 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
863 UDP udpPacket = (UDP) ipv4Packet.getPayload();
864 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
865
866 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPDECLINE));
867
868 return pkt;
869 }
870
871 /**
Amit Ghosh8951f042017-08-10 13:48:10 +0100872 * Constructs DHCP Discover Options.
873 *
874 * @return Ethernet packet
875 */
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700876 private List<DhcpOption> constructDhcpOptions(DHCP.MsgType packetType) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100877
878 // DHCP Options.
Jonathan Hartedbf6422018-05-02 17:30:05 -0700879 DhcpOption option = new DhcpOption();
880 List<DhcpOption> optionList = new ArrayList<>();
Amit Ghosh8951f042017-08-10 13:48:10 +0100881
882
883 // DHCP Message Type.
884 option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
885 option.setLength((byte) 1);
886 byte[] optionData = {(byte) packetType.getValue()};
887 option.setData(optionData);
888 optionList.add(option);
889
890 // DHCP Requested IP.
Jonathan Hartedbf6422018-05-02 17:30:05 -0700891 option = new DhcpOption();
Amit Ghosh8951f042017-08-10 13:48:10 +0100892 option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
893 option.setLength((byte) 4);
894 optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
895 option.setData(optionData);
896 optionList.add(option);
897
Saurav Das45861d42020-10-07 00:03:23 -0700898 // Tests app defined Option82
899 if (packetType.equals(DHCP.MsgType.DHCPOFFER)) {
900 option = new DhcpOption();
901 option.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
902 DhcpOption82Data option82 = new DhcpOption82Data();
903 option82.setAgentCircuitId(OLT_DEV_ID + "/" + CLIENT_PORT + ":vlan"
904 + CLIENT_C_TAG + ":pcp" + CLIENT_C_PBIT);
905 option82.setAgentRemoteId("bababababa");
906 option.setData(option82.toByteArray());
907 option.setLength(option82.length());
908 log.info("Added option82 {}", option);
909 optionList.add(option);
910 }
911 // Tests operator configured Option82, resulting in host lookup
912 if (packetType.equals(DHCP.MsgType.DHCPACK)) {
913 option = new DhcpOption();
914 option.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
915 DhcpOption82Data option82 = new DhcpOption82Data();
916 option82.setAgentCircuitId(CLIENT_CIRCUIT_ID);
917 option82.setAgentRemoteId(CLIENT_REMOTE_ID);
918 option.setData(option82.toByteArray());
919 option.setLength(option82.length());
920 log.info("Added option82 {}", option);
921 optionList.add(option);
922 }
923 // Tests app-defined option82, but uses incorrect connectPoint - packet
924 // should still be forwarded to this connectPoint (ie without host lookup).
925 // Also pbit in circuitId is -1, which means original pbit should be retained
926 // Finally remoteId is missing
927 if (packetType.equals(DHCP.MsgType.DHCPNAK)) {
928 option = new DhcpOption();
929 option.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
930 DhcpOption82Data option82 = new DhcpOption82Data();
931 option82.setAgentCircuitId("of:0000b86a974385f7/32" + ":vlan"
932 + VlanId.vlanId((short) 111) + ":pcp-1");
933 option.setData(option82.toByteArray());
934 option.setLength(option82.length());
935 log.info("Added option82 {}", option);
936 optionList.add(option);
937 }
938
Amit Ghosh8951f042017-08-10 13:48:10 +0100939 // End Option.
Jonathan Hartedbf6422018-05-02 17:30:05 -0700940 option = new DhcpOption();
Amit Ghosh8951f042017-08-10 13:48:10 +0100941 option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
942 option.setLength((byte) 1);
943 optionList.add(option);
944
945 return optionList;
946 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300947}