[VOL-4568] Changes to onos-mac-learner app to forward the DHCP packets
Change-Id: I85c2185238afc788f40d9e32a4a4de96cb3a1ebd
diff --git a/app/src/test/java/org/opencord/maclearner/app/impl/MacLearnerManagerTest.java b/app/src/test/java/org/opencord/maclearner/app/impl/MacLearnerManagerTest.java
index adfbc5a..7ce813e 100644
--- a/app/src/test/java/org/opencord/maclearner/app/impl/MacLearnerManagerTest.java
+++ b/app/src/test/java/org/opencord/maclearner/app/impl/MacLearnerManagerTest.java
@@ -26,8 +26,14 @@
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.packet.OutboundPacket;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
import java.util.Optional;
import static org.junit.Assert.assertEquals;
@@ -54,7 +60,7 @@
}
private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
- private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
+ public static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
private static final VlanId CLIENT_QINQ_VLAN = VlanId.vlanId("200");
public static final DeviceId OLT_DEVICE_ID = DeviceId.deviceId("of:0000b86a974385f7");
public static final PortNumber UNI_PORT = PortNumber.portNumber(16);
@@ -62,6 +68,9 @@
public static final DeviceId AGG_DEVICE_ID = DeviceId.deviceId("of:0000000000000001");
public static final PortNumber AGG_OLT_PORT = PortNumber.portNumber(10);
public static final PortNumber OLT_NNI_PORT = PortNumber.portNumber(1048576);
+ public static final ConnectPoint NNI_CP = new ConnectPoint(OLT_DEVICE_ID, OLT_NNI_PORT);
+ public static final String OLT_SERIAL_NUMBER = "BBSIM_OLT_1";
+ private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:11");
@Test
public void testSingleTagDhcpPacket() {
@@ -112,4 +121,62 @@
});
}
+ @Test
+ public void testDhcpForwardClientRequest() {
+ this.macLearnerManager.enableDhcpForward = true;
+ TestDhcpRequestPacketContext dhcpRequest = new TestDhcpRequestPacketContext(CLIENT_MAC, CLIENT_VLAN,
+ VlanId.NONE, CLIENT_CP);
+ ByteBuffer inBuffer = dhcpRequest.inPacket().unparsed();
+
+ packetService.processPacket(dhcpRequest);
+
+ assertAfter(DELAY, PROCESSING_LENGTH, () -> {
+ OutboundPacket emittedPacket = packetService.emittedPacket;
+ ByteBuffer outBuffer = emittedPacket.data();
+ DeviceId deviceId = emittedPacket.sendThrough();
+ TrafficTreatment treatment = emittedPacket.treatment();
+ List<Instruction> instructions = treatment.allInstructions();
+
+ assertEquals(deviceId, OLT_DEVICE_ID);
+ for (Instruction instruction : instructions) {
+ if (instruction instanceof Instructions.OutputInstruction) {
+ assertEquals(OLT_NNI_PORT, ((Instructions.OutputInstruction) instruction).port());
+ }
+ }
+
+ // Test for packet not modified
+ assertEquals(0, inBuffer.compareTo(outBuffer));
+ });
+ }
+
+ @Test
+ public void testDhcpForwardServerResponse() {
+ this.macLearnerManager.enableDhcpForward = true;
+ testDhcpForwardClientRequest();
+
+ TestDhcpResponsePacketContext dhcpResponse = new TestDhcpResponsePacketContext(CLIENT_MAC, SERVER_MAC,
+ CLIENT_VLAN, VlanId.NONE, NNI_CP);
+ ByteBuffer inBuffer = dhcpResponse.inPacket().unparsed();
+
+ packetService.processPacket(dhcpResponse);
+
+ assertAfter(DELAY, PROCESSING_LENGTH, () -> {
+ OutboundPacket emittedPacket = packetService.emittedPacket;
+ ByteBuffer outBuffer = emittedPacket.data();
+
+ DeviceId deviceId = emittedPacket.sendThrough();
+ TrafficTreatment treatment = emittedPacket.treatment();
+ List<Instruction> instructions = treatment.allInstructions();
+
+ assertEquals(deviceId, OLT_DEVICE_ID);
+ for (Instruction instruction : instructions) {
+ if (instruction instanceof Instructions.OutputInstruction) {
+ assertEquals(UNI_PORT, ((Instructions.OutputInstruction) instruction).port());
+ }
+ }
+
+ // Test for packet not modified
+ assertEquals(0, inBuffer.compareTo(outBuffer));
+ });
+ }
}
diff --git a/app/src/test/java/org/opencord/maclearner/app/impl/TestBaseMacLearner.java b/app/src/test/java/org/opencord/maclearner/app/impl/TestBaseMacLearner.java
index ffbf0c3..c90522f 100644
--- a/app/src/test/java/org/opencord/maclearner/app/impl/TestBaseMacLearner.java
+++ b/app/src/test/java/org/opencord/maclearner/app/impl/TestBaseMacLearner.java
@@ -47,16 +47,20 @@
import org.onosproject.event.Event;
import org.onosproject.event.EventDeliveryService;
import org.onosproject.event.EventSink;
+import org.onosproject.net.Annotations;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultHost;
import org.onosproject.net.DefaultLink;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.Element;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Link;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.ConfigApplyDelegate;
import org.onosproject.net.config.basics.HostLearningConfig;
@@ -93,6 +97,10 @@
import org.onosproject.store.service.SetEventListener;
import org.onosproject.store.service.StorageServiceAdapter;
import org.onosproject.store.service.Versioned;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SadisService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
import java.io.IOException;
import java.io.InputStream;
@@ -113,8 +121,10 @@
import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.AGG_DEVICE_ID;
import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.AGG_OLT_PORT;
import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.CLIENT_CP;
+import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.CLIENT_VLAN;
import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.OLT_DEVICE_ID;
import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.OLT_NNI_PORT;
+import static org.opencord.maclearner.app.impl.MacLearnerManagerTest.OLT_SERIAL_NUMBER;
/**
* Mac Learner mock services class.
@@ -150,6 +160,7 @@
protected MockLinkService linkService = new MockLinkService();
protected MacLearnerHostProvider macLearnerHostProvider = new MacLearnerHostProvider();
protected MockHostService hostService = new MockHostService(Sets.newHashSet());
+ protected MockSadisService sadisService = new MockSadisService();
public void setUpApp() throws IOException {
macLearnerManager = new MacLearnerManager();
@@ -161,6 +172,8 @@
macLearnerManager.deviceService = this.deviceService;
macLearnerManager.topologyService = this.topologyService;
macLearnerManager.linkService = this.linkService;
+ macLearnerManager.sadisService = this.sadisService;
+ macLearnerManager.hostService = this.hostService;
hostLearningConfig = new HostLearningConfig();
InputStream jsonStream = HostLearningConfigTest.class
.getResourceAsStream("/host-learning-config.json");
@@ -316,13 +329,18 @@
if (deviceId.equals(OLT_DEVICE_ID)) {
return new DefaultDevice(null, OLT_DEVICE_ID, Device.Type.SWITCH,
"VOLTHA Project", "open_pon", "open_pon",
- "BBSIM_OLT_1", new ChassisId("a0a0a0a0a01"));
+ OLT_SERIAL_NUMBER, new ChassisId("a0a0a0a0a01"));
} else {
return null;
}
}
@Override
+ public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+ return new TestBaseMacLearner.MockPort(new ConnectPoint(deviceId, portNumber));
+ }
+
+ @Override
public void addListener(DeviceListener listener) {
listeners.add(listener);
}
@@ -333,6 +351,56 @@
}
}
+ static class MockPort implements Port {
+ private ConnectPoint cp;
+
+ public MockPort(ConnectPoint cp) {
+ this.cp = cp;
+ }
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+ @Override
+ public long portSpeed() {
+ return 1000;
+ }
+ @Override
+ public Element element() {
+ return null;
+ }
+ @Override
+ public PortNumber number() {
+ return null;
+ }
+ @Override
+ public Annotations annotations() {
+ return new MockAnnotations();
+ }
+ @Override
+ public Type type() {
+ return Port.Type.FIBER;
+ }
+
+ private class MockAnnotations implements Annotations {
+
+ @Override
+ public String value(String val) {
+ if (cp.port().toLong() == 32) {
+ return "ALPHe3d1cea3-1";
+ } else if (cp.port().toLong() == 4112) {
+ return "ALPHe3d1ceb7-1";
+ } else {
+ return "PON 1/1";
+ }
+ }
+ @Override
+ public Set<String> keys() {
+ return null;
+ }
+ }
+ }
+
/**
* Mocks the topology service of ONOS so that the application under test can
* check fake topology.
@@ -693,6 +761,7 @@
hostDescription.ipAddress(), VlanId.NONE,
EthType.EtherType.UNKNOWN.ethType(), false, false));
hostService = new MockHostService(previousHosts);
+ macLearnerManager.hostService = hostService;
}
@Override
@@ -703,6 +772,7 @@
Host removedHost = hostService.getHost(hostId);
previousHosts.remove(removedHost);
hostService = new MockHostService(previousHosts);
+ macLearnerManager.hostService = hostService;
}
@Override
@@ -778,4 +848,112 @@
}
}
+ /**
+ * Generates DHCP RESPONSE packet.
+ */
+ protected static class TestDhcpResponsePacketContext extends PacketContextAdapter {
+
+ private InboundPacket inPacket;
+
+ public TestDhcpResponsePacketContext(MacAddress clientMacAddress, MacAddress serverMacAddress, VlanId vlanId,
+ VlanId qinqQVid, ConnectPoint connectPoint) {
+ super(0, null, null, false);
+ byte[] dhcpMsgType = new byte[1];
+ dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPOFFER.getValue();
+
+ DhcpOption dhcpOption = new DhcpOption();
+ dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
+ dhcpOption.setData(dhcpMsgType);
+ dhcpOption.setLength((byte) 1);
+ DhcpOption endOption = new DhcpOption();
+ endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
+
+ DHCP dhcp = new DHCP();
+ dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
+ dhcp.setHardwareAddressLength((byte) 6);
+ dhcp.setClientHardwareAddress(clientMacAddress.toBytes());
+ dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
+ dhcp.setYourIPAddress(Ip4Address.valueOf("1.1.1.1").toInt());
+
+ UDP udp = new UDP();
+ udp.setPayload(dhcp);
+ udp.setSourcePort(UDP.DHCP_SERVER_PORT);
+ udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
+
+ IPv4 ipv4 = new IPv4();
+ ipv4.setPayload(udp);
+ ipv4.setDestinationAddress(INTERFACE_IP.toInt());
+ ipv4.setSourceAddress(SERVER_IP.toInt());
+
+ Ethernet eth = new Ethernet();
+ eth.setEtherType(Ethernet.TYPE_IPV4)
+ .setVlanID(vlanId.toShort())
+ .setQinQVID(qinqQVid.toShort())
+ .setSourceMACAddress(serverMacAddress)
+ .setDestinationMACAddress(clientMacAddress)
+ .setPayload(ipv4);
+
+ this.inPacket = new DefaultInboundPacket(connectPoint, eth,
+ ByteBuffer.wrap(eth.serialize()));
+ }
+
+ @Override
+ public InboundPacket inPacket() {
+ return this.inPacket;
+ }
+ }
+
+ /**
+ * Mock Sadis service.
+ */
+ static class MockSadisService implements SadisService {
+ @Override
+ public BaseInformationService<SubscriberAndDeviceInformation> getSubscriberInfoService() {
+ return new TestBaseMacLearner.MockSubService();
+ }
+
+ @Override
+ public BaseInformationService<BandwidthProfileInformation> getBandwidthProfileService() {
+ return null;
+ }
+ }
+
+ static class MockSubService implements BaseInformationService<SubscriberAndDeviceInformation> {
+ TestBaseMacLearner.MockSubscriberAndDeviceInformation device =
+ new TestBaseMacLearner.MockSubscriberAndDeviceInformation(OLT_SERIAL_NUMBER, CLIENT_VLAN, VlanId.NONE,
+ null, null, null, null, (int) OLT_NNI_PORT.toLong());
+ @Override
+ public SubscriberAndDeviceInformation get(String id) {
+ if (id.equals(OLT_SERIAL_NUMBER)) {
+ return device;
+ }
+ return null;
+ }
+
+ @Override
+ public void clearLocalData() {}
+ @Override
+ public void invalidateAll() {}
+ @Override
+ public void invalidateId(String id) {}
+ @Override
+ public SubscriberAndDeviceInformation getfromCache(String id) {
+ return null;
+ }
+ }
+
+ static class MockSubscriberAndDeviceInformation extends SubscriberAndDeviceInformation {
+
+ MockSubscriberAndDeviceInformation(String id, VlanId cTag,
+ VlanId sTag, String nasPortId,
+ String circuitId, MacAddress hardId,
+ Ip4Address ipAddress, int uplinkPort) {
+ this.setHardwareIdentifier(hardId);
+ this.setId(id);
+ this.setIPAddress(ipAddress);
+ this.setNasPortId(nasPortId);
+ this.setUplinkPort(uplinkPort);
+ this.setCircuitId(circuitId);
+ }
+ }
}
diff --git a/app/src/test/java/org/opencord/maclearner/app/impl/package-info.java b/app/src/test/java/org/opencord/maclearner/app/impl/package-info.java
new file mode 100644
index 0000000..dd64e64
--- /dev/null
+++ b/app/src/test/java/org/opencord/maclearner/app/impl/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Mac Learner Tests.
+ */
+package org.opencord.maclearner.app.impl;
\ No newline at end of file