blob: 2392947d5e6308d22f3280751ff42bdef4f47060 [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
Ilayda Ozdemir6b623ea2021-02-23 21:06:38 +0000357 public void clearLocalData() {
358
359 }
360
361 @Override
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300362 public void invalidateAll() {}
363 @Override
364 public void invalidateId(String id) {}
365 @Override
366 public SubscriberAndDeviceInformation getfromCache(String id) {
367 return null;
368 }
369 }
370
371 class MockSubscriberAndDeviceInformation extends SubscriberAndDeviceInformation {
372
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000373 MockSubscriberAndDeviceInformation(String id, VlanId cTag,
374 VlanId sTag, String nasPortId,
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300375 String circuitId, MacAddress hardId,
376 Ip4Address ipAddress, int uplinkPort) {
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300377 this.setHardwareIdentifier(hardId);
378 this.setId(id);
379 this.setIPAddress(ipAddress);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300380 this.setNasPortId(nasPortId);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300381 this.setUplinkPort(uplinkPort);
Saurav Das45861d42020-10-07 00:03:23 -0700382 this.setCircuitId(circuitId);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000383
384 List<UniTagInformation> uniTagInformationList = new ArrayList<>();
385
Saurav Das45861d42020-10-07 00:03:23 -0700386 UniTagInformation.Builder b = new UniTagInformation.Builder()
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000387 .setPonCTag(cTag)
388 .setPonSTag(sTag)
389 .setUsPonCTagPriority(CLIENT_C_PBIT)
Saurav Das45861d42020-10-07 00:03:23 -0700390 .setIsDhcpRequired(true);
391
392 if (id.equals("ALPHe3d1ceb7-1")) {
393 // null remoteId, ds pbit is defined
394 b.setDsPonCTagPriority(5);
395 } else {
396 this.setRemoteId(CLIENT_REMOTE_ID);
397 }
398
399 uniTagInformationList.add(b.build());
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700400
401 if (id.equals("ALPHe3d1cea3-1")) {
402 // a second service on the same UNI
Saurav Das45861d42020-10-07 00:03:23 -0700403 UniTagInformation uniTagInformation = new UniTagInformation.Builder()
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700404 .setPonCTag(VlanId.vlanId(((short) (cTag.toShort() + 1))))
405 .setPonSTag(sTag)
406 .setUsPonCTagPriority(CLIENT_C_PBIT)
407 .setIsDhcpRequired(true)
408 .build();
409 uniTagInformationList.add(uniTagInformation);
410 }
411
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000412 this.setUniTagList(uniTagInformationList);
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300413 }
414 }
415
416 class MockComponentContext implements ComponentContext {
417
418 @Override
419 public Dictionary<String, Object> getProperties() {
420 Dictionary<String, Object> cfgDict = new Hashtable<String, Object>();
421 cfgDict.put("publishCountersRate", 10);
422 return cfgDict;
423 }
424
425 @Override
426 public Object locateService(String name) {
427 // TODO Auto-generated method stub
428 return null;
429 }
430
431 @Override
432 public Object locateService(String name, ServiceReference reference) {
433 // TODO Auto-generated method stub
434 return null;
435 }
436
437 @Override
438 public Object[] locateServices(String name) {
439 // TODO Auto-generated method stub
440 return null;
441 }
442
443 @Override
444 public BundleContext getBundleContext() {
445 // TODO Auto-generated method stub
446 return null;
447 }
448
449 @Override
450 public Bundle getUsingBundle() {
451 // TODO Auto-generated method stub
452 return null;
453 }
454
455 @Override
456 public ComponentInstance getComponentInstance() {
457 // TODO Auto-generated method stub
458 return null;
459 }
460
461 @Override
462 public void enableComponent(String name) {
463 // TODO Auto-generated method stub
464 }
465
466 @Override
467 public void disableComponent(String name) {
468 // TODO Auto-generated method stub
469 }
470
471 @Override
472 public ServiceReference getServiceReference() {
473 // TODO Auto-generated method stub
474 return null;
475 }
476 }
477
478
Amit Ghosh8951f042017-08-10 13:48:10 +0100479 /**
480 * Mocks the DefaultPacketContext.
481 */
482 final class TestPacketContext extends DefaultPacketContext {
483
484 private TestPacketContext(long time, InboundPacket inPkt,
485 OutboundPacket outPkt, boolean block) {
486 super(time, inPkt, outPkt, block);
487 }
488
489 @Override
490 public void send() {
491 // We don't send anything out.
492 }
493 }
494
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300495 public static class TestEventDispatcher extends DefaultEventSinkRegistry
496 implements EventDeliveryService {
497 @Override
498 @SuppressWarnings("unchecked")
499 public synchronized void post(Event event) {
500 EventSink sink = getSink(event.getClass());
501 checkState(sink != null, "No sink for event %s", event);
502 sink.process(event);
503 }
504
505 @Override
506 public void setDispatchTimeLimit(long millis) {
507 }
508
509 @Override
510 public long getDispatchTimeLimit() {
511 return 0;
512 }
513 }
514
515 /**
516 * Creates a mock object for a scheduled executor service.
517 *
518 */
519 public static final class MockExecutor implements ScheduledExecutorService {
520 private ScheduledExecutorService executor;
521
522 MockExecutor(ScheduledExecutorService executor) {
523 this.executor = executor;
524 }
525
526 String lastMethodCalled = "";
527 long lastInitialDelay;
528 long lastDelay;
529 TimeUnit lastUnit;
530
531 public void assertLastMethodCalled(String method, long initialDelay, long delay, TimeUnit unit) {
532 assertEquals(method, lastMethodCalled);
533 assertEquals(initialDelay, lastInitialDelay);
534 assertEquals(delay, lastDelay);
535 assertEquals(unit, lastUnit);
536 }
537
538 @Override
539 public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
540 lastMethodCalled = "scheduleRunnable";
541 lastDelay = delay;
542 lastUnit = unit;
543 return null;
544 }
545
546 @Override
547 public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
548 lastMethodCalled = "scheduleCallable";
549 lastDelay = delay;
550 lastUnit = unit;
551 return null;
552 }
553
554 @Override
555 public ScheduledFuture<?> scheduleAtFixedRate(
556 Runnable command, long initialDelay, long period, TimeUnit unit) {
557 lastMethodCalled = "scheduleAtFixedRate";
558 lastInitialDelay = initialDelay;
559 lastDelay = period;
560 lastUnit = unit;
561 return null;
562 }
563
564 @Override
565 public ScheduledFuture<?> scheduleWithFixedDelay(
566 Runnable command, long initialDelay, long delay, TimeUnit unit) {
567 lastMethodCalled = "scheduleWithFixedDelay";
568 lastInitialDelay = initialDelay;
569 lastDelay = delay;
570 lastUnit = unit;
571 command.run();
572 return null;
573 }
574
575 @Override
576 public boolean awaitTermination(long timeout, TimeUnit unit) {
577 throw new UnsupportedOperationException();
578 }
579
580 @Override
581 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
582 throws InterruptedException {
583 throw new UnsupportedOperationException();
584 }
585
586 @Override
587 public <T> List<Future<T>> invokeAll(
588 Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
589 throws InterruptedException {
590 throw new UnsupportedOperationException();
591 }
592
593 @Override
Matteo Scandoloabcc73e2020-11-25 16:02:17 -0800594 @SuppressWarnings({"TypeParameterUnusedInFormals"})
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300595 public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
596 throws ExecutionException, InterruptedException {
597 throw new UnsupportedOperationException();
598 }
599
600 @Override
Matteo Scandoloabcc73e2020-11-25 16:02:17 -0800601 @SuppressWarnings({"TypeParameterUnusedInFormals"})
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300602 public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
603 throws ExecutionException, InterruptedException, TimeoutException {
604 throw new UnsupportedOperationException();
605 }
606
607 @Override
608 public boolean isShutdown() {
609 throw new UnsupportedOperationException();
610 }
611
612 @Override
613 public boolean isTerminated() {
614 throw new UnsupportedOperationException();
615 }
616
617 @Override
618 public void shutdown() {
619 throw new UnsupportedOperationException();
620 }
621
622 @Override
623 public List<Runnable> shutdownNow() {
624 return null;
625 }
626
627 @Override
Matteo Scandoloabcc73e2020-11-25 16:02:17 -0800628 @SuppressWarnings({"TypeParameterUnusedInFormals"})
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300629 public <T> Future<T> submit(Callable<T> task) {
630 throw new UnsupportedOperationException();
631 }
632
633 @Override
634 public Future<?> submit(Runnable task) {
635 throw new UnsupportedOperationException();
636 }
637
638 @Override
639 public <T> Future<T> submit(Runnable task, T result) {
640 throw new UnsupportedOperationException();
641 }
642
643 @Override
644 public void execute(Runnable command) {
645 throw new UnsupportedOperationException();
646 }
647 }
648
Amit Ghosh8951f042017-08-10 13:48:10 +0100649 /**
650 * Sends an Ethernet packet to the process method of the Packet Processor.
651 *
652 * @param pkt Ethernet packet
653 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530654 void sendPacket(Ethernet pkt, ConnectPoint cp) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100655 final ByteBuffer byteBuffer = ByteBuffer.wrap(pkt.serialize());
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530656 InboundPacket inPacket = new DefaultInboundPacket(cp, pkt, byteBuffer);
Amit Ghosh8951f042017-08-10 13:48:10 +0100657
658 PacketContext context = new TestPacketContext(127L, inPacket, null, false);
659 packetProcessor.process(context);
660 }
661
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700662 private Ethernet constructEthernetPacket(MacAddress srcMac, MacAddress dstMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100663 String dstIp, byte dhcpReqRsp,
664 MacAddress clientHwAddress,
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700665 Ip4Address dhcpClientIpAddress,
666 VlanId clientVlan, short clientPbit) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100667 // Ethernet Frame.
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530668 Ethernet ethPkt = new Ethernet();
669 ethPkt.setSourceMACAddress(srcMac);
670 ethPkt.setDestinationMACAddress(dstMac);
Amit Ghosh8951f042017-08-10 13:48:10 +0100671 ethPkt.setEtherType(Ethernet.TYPE_IPV4);
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700672 ethPkt.setVlanID(clientVlan.toShort());
673 ethPkt.setPriorityCode((byte) clientPbit);
Gamze Abakaa64b3bc2020-01-31 06:51:43 +0000674
675 if (DHCP.OPCODE_REPLY == dhcpReqRsp) {
676 ethPkt.setQinQPriorityCode((byte) 3);
677 ethPkt.setQinQVID((short) 4);
678 }
Amit Ghosh8951f042017-08-10 13:48:10 +0100679
680 // IP Packet
681 IPv4 ipv4Reply = new IPv4();
682 ipv4Reply.setSourceAddress(0);
683 ipv4Reply.setDestinationAddress(dstIp);
684
685 ipv4Reply.setTtl((byte) 127);
686
687 // UDP Datagram.
688 UDP udpReply = new UDP();
689 udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT);
690 udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT);
691
692 // DHCP Payload.
693 DHCP dhcpReply = new DHCP();
694 dhcpReply.setOpCode(dhcpReqRsp);
695
696 dhcpReply.setYourIPAddress(dhcpClientIpAddress.toInt());
697 dhcpReply.setServerIPAddress(0);
698
699 final byte[] serverNameBytes = new byte[64];
700 String result = new String(serverNameBytes, StandardCharsets.US_ASCII).trim();
701 dhcpReply.setServerName(result);
702
703 final byte[] bootFileBytes = new byte[128];
704 String result1 = new String(bootFileBytes, StandardCharsets.US_ASCII).trim();
705 dhcpReply.setBootFileName(result1);
706
707 dhcpReply.setTransactionId(TRANSACTION_ID);
708 dhcpReply.setClientHardwareAddress(clientHwAddress.toBytes());
709 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
710 dhcpReply.setHardwareAddressLength((byte) 6);
711
712 udpReply.setPayload(dhcpReply);
713 ipv4Reply.setPayload(udpReply);
714 ethPkt.setPayload(ipv4Reply);
715
716 return ethPkt;
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700717
718 }
719
720 /**
721 * Constructs an Ethernet packet with IP/UDP/DHCP payload and client
722 * VLAN information.
723 *
724 * @return Ethernet packet
725 */
726 private Ethernet construcEthernetPacket(MacAddress srcMac, MacAddress dstMac,
727 String dstIp, byte dhcpReqRsp,
728 MacAddress clientHwAddress,
729 Ip4Address dhcpClientIpAddress) {
730 return constructEthernetPacket(srcMac, dstMac, dstIp, dhcpReqRsp,
731 clientHwAddress, dhcpClientIpAddress,
732 CLIENT_C_TAG, CLIENT_C_PBIT);
733
Amit Ghosh8951f042017-08-10 13:48:10 +0100734 }
735
736 /**
737 * Constructs DHCP Discover Packet.
738 *
739 * @return Ethernet packet
740 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530741 Ethernet constructDhcpDiscoverPacket(MacAddress clientMac) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530742 Ethernet pkt = construcEthernetPacket(clientMac, MacAddress.BROADCAST,
Saurav Das45861d42020-10-07 00:03:23 -0700743 "255.255.255.255",
744 DHCP.OPCODE_REQUEST, clientMac,
745 Ip4Address.valueOf("0.0.0.0"));
Amit Ghosh8951f042017-08-10 13:48:10 +0100746
747 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
748 UDP udpPacket = (UDP) ipv4Packet.getPayload();
749 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
750
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700751 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPDISCOVER));
Saurav Das45861d42020-10-07 00:03:23 -0700752 log.info("Sending discover packet {}", dhcpPacket.getOptions());
Amit Ghosh8951f042017-08-10 13:48:10 +0100753
754 return pkt;
755 }
756
757 /**
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700758 * Constructs DHCP Discover Packet with client VLAN information.
759 *
760 * @return Ethernet packet
761 */
762 Ethernet constructDhcpDiscoverPacket(MacAddress clientMac, VlanId clientVlan,
763 short clientPbit) {
764 Ethernet pkt = constructEthernetPacket(clientMac, MacAddress.BROADCAST,
765 "255.255.255.255", DHCP.OPCODE_REQUEST, clientMac,
766 Ip4Address.valueOf("0.0.0.0"), clientVlan, clientPbit);
767
768 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
769 UDP udpPacket = (UDP) ipv4Packet.getPayload();
770 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
771
772 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPDISCOVER));
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700773 return pkt;
774 }
775
776 /**
Amit Ghosh8951f042017-08-10 13:48:10 +0100777 * Constructs DHCP Request Packet.
778 *
779 * @return Ethernet packet
780 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530781 Ethernet constructDhcpRequestPacket(MacAddress clientMac) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530782 Ethernet pkt = construcEthernetPacket(clientMac, MacAddress.BROADCAST,
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700783 "255.255.255.255", DHCP.OPCODE_REQUEST, clientMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100784 Ip4Address.valueOf("0.0.0.0"));
785
786 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
787 UDP udpPacket = (UDP) ipv4Packet.getPayload();
788 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
789
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700790 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPREQUEST));
Amit Ghosh8951f042017-08-10 13:48:10 +0100791
792 return pkt;
793 }
794
795 /**
796 * Constructs DHCP Offer Packet.
797 *
798 * @return Ethernet packet
799 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530800 Ethernet constructDhcpOfferPacket(MacAddress servMac, MacAddress clientMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100801 String ipAddress, String dhcpClientIpAddress) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530802 Ethernet pkt = construcEthernetPacket(servMac, clientMac, ipAddress, DHCP.OPCODE_REPLY,
Amit Ghosh8951f042017-08-10 13:48:10 +0100803 clientMac, Ip4Address.valueOf(dhcpClientIpAddress));
804
805 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
806 UDP udpPacket = (UDP) ipv4Packet.getPayload();
807 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
808
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700809 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPOFFER));
Saurav Das45861d42020-10-07 00:03:23 -0700810 log.info("Sending offer packet {}", dhcpPacket.getOptions());
Amit Ghosh8951f042017-08-10 13:48:10 +0100811 return pkt;
812 }
813
814 /**
815 * Constructs DHCP Ack Packet.
816 *
817 * @return Ethernet packet
818 */
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530819 Ethernet constructDhcpAckPacket(MacAddress servMac, MacAddress clientMac,
Amit Ghosh8951f042017-08-10 13:48:10 +0100820 String ipAddress, String dhcpClientIpAddress) {
Deepa Vaddireddy5f278d62017-08-30 05:59:39 +0530821 Ethernet pkt = construcEthernetPacket(servMac, clientMac, ipAddress, DHCP.OPCODE_REPLY,
Amit Ghosh8951f042017-08-10 13:48:10 +0100822 clientMac, Ip4Address.valueOf(dhcpClientIpAddress));
823
824 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
825 UDP udpPacket = (UDP) ipv4Packet.getPayload();
826 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
827
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700828 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPACK));
Amit Ghosh8951f042017-08-10 13:48:10 +0100829
830 return pkt;
831 }
832
833 /**
Arjun E K05ad20b2020-03-13 13:25:17 +0000834 * Constructs DHCP Nak Packet.
835 *
836 * @return Ethernet packet
837 */
838 Ethernet constructDhcpNakPacket(MacAddress servMac, MacAddress clientMac,
Saurav Das45861d42020-10-07 00:03:23 -0700839 String ipAddress, String dhcpClientIpAddress,
840 VlanId clientVlan, short clientPcp) {
Arjun E K05ad20b2020-03-13 13:25:17 +0000841
Saurav Das45861d42020-10-07 00:03:23 -0700842 Ethernet pkt = constructEthernetPacket(servMac, clientMac, ipAddress,
843 DHCP.OPCODE_REPLY, clientMac,
844 Ip4Address.valueOf(dhcpClientIpAddress),
845 clientVlan, clientPcp);
Arjun E K05ad20b2020-03-13 13:25:17 +0000846
847 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
848 UDP udpPacket = (UDP) ipv4Packet.getPayload();
849 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
850
851 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPNAK));
852
853 return pkt;
854 }
855
856 /**
857 * Constructs DHCP Decline Packet.
858 *
859 * @return Ethernet packet
860 */
861 Ethernet constructDhcpDeclinePacket(MacAddress clientMac) {
862
863 Ethernet pkt = construcEthernetPacket(clientMac, MacAddress.BROADCAST,
Saurav Dasbd5ce9c2020-09-04 18:46:45 -0700864 "255.255.255.255", DHCP.OPCODE_REQUEST, clientMac,
Arjun E K05ad20b2020-03-13 13:25:17 +0000865 Ip4Address.valueOf("0.0.0.0"));
866
867 IPv4 ipv4Packet = (IPv4) pkt.getPayload();
868 UDP udpPacket = (UDP) ipv4Packet.getPayload();
869 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
870
871 dhcpPacket.setOptions(constructDhcpOptions(DHCP.MsgType.DHCPDECLINE));
872
873 return pkt;
874 }
875
876 /**
Amit Ghosh8951f042017-08-10 13:48:10 +0100877 * Constructs DHCP Discover Options.
878 *
879 * @return Ethernet packet
880 */
Carmelo Casconede1e6e32019-07-15 19:39:08 -0700881 private List<DhcpOption> constructDhcpOptions(DHCP.MsgType packetType) {
Amit Ghosh8951f042017-08-10 13:48:10 +0100882
883 // DHCP Options.
Jonathan Hartedbf6422018-05-02 17:30:05 -0700884 DhcpOption option = new DhcpOption();
885 List<DhcpOption> optionList = new ArrayList<>();
Amit Ghosh8951f042017-08-10 13:48:10 +0100886
887
888 // DHCP Message Type.
889 option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
890 option.setLength((byte) 1);
891 byte[] optionData = {(byte) packetType.getValue()};
892 option.setData(optionData);
893 optionList.add(option);
894
895 // DHCP Requested IP.
Jonathan Hartedbf6422018-05-02 17:30:05 -0700896 option = new DhcpOption();
Amit Ghosh8951f042017-08-10 13:48:10 +0100897 option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
898 option.setLength((byte) 4);
899 optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
900 option.setData(optionData);
901 optionList.add(option);
902
Saurav Das45861d42020-10-07 00:03:23 -0700903 // Tests app defined Option82
904 if (packetType.equals(DHCP.MsgType.DHCPOFFER)) {
905 option = new DhcpOption();
906 option.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
907 DhcpOption82Data option82 = new DhcpOption82Data();
908 option82.setAgentCircuitId(OLT_DEV_ID + "/" + CLIENT_PORT + ":vlan"
909 + CLIENT_C_TAG + ":pcp" + CLIENT_C_PBIT);
910 option82.setAgentRemoteId("bababababa");
911 option.setData(option82.toByteArray());
912 option.setLength(option82.length());
913 log.info("Added option82 {}", option);
914 optionList.add(option);
915 }
916 // Tests operator configured Option82, resulting in host lookup
917 if (packetType.equals(DHCP.MsgType.DHCPACK)) {
918 option = new DhcpOption();
919 option.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
920 DhcpOption82Data option82 = new DhcpOption82Data();
921 option82.setAgentCircuitId(CLIENT_CIRCUIT_ID);
922 option82.setAgentRemoteId(CLIENT_REMOTE_ID);
923 option.setData(option82.toByteArray());
924 option.setLength(option82.length());
925 log.info("Added option82 {}", option);
926 optionList.add(option);
927 }
928 // Tests app-defined option82, but uses incorrect connectPoint - packet
929 // should still be forwarded to this connectPoint (ie without host lookup).
930 // Also pbit in circuitId is -1, which means original pbit should be retained
931 // Finally remoteId is missing
932 if (packetType.equals(DHCP.MsgType.DHCPNAK)) {
933 option = new DhcpOption();
934 option.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
935 DhcpOption82Data option82 = new DhcpOption82Data();
936 option82.setAgentCircuitId("of:0000b86a974385f7/32" + ":vlan"
937 + VlanId.vlanId((short) 111) + ":pcp-1");
938 option.setData(option82.toByteArray());
939 option.setLength(option82.length());
940 log.info("Added option82 {}", option);
941 optionList.add(option);
942 }
943
Amit Ghosh8951f042017-08-10 13:48:10 +0100944 // End Option.
Jonathan Hartedbf6422018-05-02 17:30:05 -0700945 option = new DhcpOption();
Amit Ghosh8951f042017-08-10 13:48:10 +0100946 option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
947 option.setLength((byte) 1);
948 optionList.add(option);
949
950 return optionList;
951 }
Marcos Aurelio Carreroeaf02b82019-11-25 13:34:25 -0300952}