DHCP Relay Application, addressed the review comments for patch-2.
Change-Id: If447f3786c661c667460f43fc659ea71dd198be7
diff --git a/BUCK b/BUCK
index e138ae3..f37506c 100644
--- a/BUCK
+++ b/BUCK
@@ -98,6 +98,7 @@
# Apps
'//apps/dhcp:onos-apps-dhcp-oar',
+ '//apps/dhcprelay:onos-apps-dhcprelay-oar',
'//apps/fwd:onos-apps-fwd-oar',
'//apps/acl:onos-apps-acl-oar',
'//apps/bgprouter:onos-apps-bgprouter-oar',
@@ -147,6 +148,7 @@
'//apps/routing-api:onos-apps-routing-api',
'//apps/dhcp/api:onos-apps-dhcp-api',
'//apps/dhcp/app:onos-apps-dhcp-app',
+ '//apps/dhcprelay:onos-apps-dhcprelay',
'//apps/fwd:onos-apps-fwd',
'//apps/iptopology-api:onos-apps-iptopology-api',
'//apps/openstacknode:onos-apps-openstacknode',
diff --git a/apps/dhcprelay/BUCK b/apps/dhcprelay/BUCK
new file mode 100644
index 0000000..aad1a8d
--- /dev/null
+++ b/apps/dhcprelay/BUCK
@@ -0,0 +1,15 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+]
+
+osgi_jar (
+ deps = COMPILE_DEPS,
+)
+
+onos_app (
+ app_name = 'org.onosproject.dhcprelay',
+ title = 'DHCP Relay Agent App',
+ category = 'default',
+ url = 'http://onosproject.org',
+ description = 'DHCP Relay Agent Application.',
+)
diff --git a/apps/dhcprelay/pom.xml b/apps/dhcprelay/pom.xml
new file mode 100644
index 0000000..31795fd
--- /dev/null
+++ b/apps/dhcprelay/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016 Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-app-dhcprelay</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>DHCP Relay Agent</description>
+ <url>http://onosproject.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <onos.version>1.6.0-SNAPSHOT</onos.version>
+ <onos.app.name>org.onosproject.dhcprelay</onos.app.name>
+ <onos.app.title>DHCP Relay Agent App</onos.app.title>
+ <onos.app.origin>ON.Lab</onos.app.origin>
+ <onos.app.category>default</onos.app.category>
+ <onos.app.url>http://onosproject.org</onos.app.url>
+ <onos.app.readme>DHCP Relay Agent Application.</onos.app.readme>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${onos.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-api</artifactId>
+ <version>${onos.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <version>1.9.12</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
new file mode 100644
index 0000000..5731b31
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.dhcprelay;
+
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.DHCP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.UDP;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+/**
+ * DHCP Relay Agent Application Component.
+ */
+@Component(immediate = true)
+public class DhcpRelay {
+
+ public static final String DHCP_RELAY_APP = "org.onosproject.dhcp-relay";
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final InternalConfigListener cfgListener = new InternalConfigListener();
+
+ private final Set<ConfigFactory> factories = ImmutableSet.of(
+ new ConfigFactory<ApplicationId, DhcpRelayConfig>(APP_SUBJECT_FACTORY,
+ DhcpRelayConfig.class,
+ "dhcprelay") {
+ @Override
+ public DhcpRelayConfig createConfig() {
+ return new DhcpRelayConfig();
+ }
+ }
+ );
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected NetworkConfigRegistry cfgService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
+ private ConnectPoint dhcpServerConnectPoint = null;
+ private ApplicationId appId;
+
+ @Activate
+ protected void activate() {
+ //start the dhcp relay agent
+
+ appId = coreService.registerApplication(DHCP_RELAY_APP);
+
+ cfgService.addListener(cfgListener);
+ factories.forEach(cfgService::registerConfigFactory);
+ //update the dhcp server configuration.
+ updateConfig();
+ //add the packet services.
+ packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
+ requestPackets();
+ log.info("DHCP-RELAY Started");
+ log.info("started the apps dhcp relay");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ cfgService.removeListener(cfgListener);
+ factories.forEach(cfgService::unregisterConfigFactory);
+ packetService.removeProcessor(dhcpRelayPacketProcessor);
+ cancelPackets();
+ log.info("DHCP-RELAY Stopped");
+ }
+
+ private void updateConfig() {
+ DhcpRelayConfig cfg = cfgService.getConfig(appId, DhcpRelayConfig.class);
+
+ if (cfg == null) {
+ log.warn("Dhcp Server info not available");
+ return;
+ }
+
+ dhcpServerConnectPoint = cfg.getDhcpServerConnectPoint();
+ log.info("Reconfigured the dhcp server info");
+ log.info("dhcp server connect points are " + dhcpServerConnectPoint);
+ }
+
+ /**
+ * Request packet in via PacketService.
+ */
+ private void requestPackets() {
+
+ TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
+ packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
+
+ TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
+ packetService.requestPackets(selectorClient.build(), PacketPriority.CONTROL, appId);
+ }
+
+ /**
+ * Cancel requested packets in via packet service.
+ */
+ private void cancelPackets() {
+ TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
+ packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
+
+ TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
+ packetService.cancelPackets(selectorClient.build(), PacketPriority.CONTROL, appId);
+ }
+
+ private class DhcpRelayPacketProcessor implements PacketProcessor {
+
+ @Override
+ public void process(PacketContext context) {
+ // process the packet and get the payload
+ Ethernet packet = context.inPacket().parsed();
+
+ if (packet == null) {
+ return;
+ }
+
+ if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
+ IPv4 ipv4Packet = (IPv4) packet.getPayload();
+
+ if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
+ UDP udpPacket = (UDP) ipv4Packet.getPayload();
+ DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
+ if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
+ udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
+ //This packet is dhcp client request.
+ forwardPacket(context, dhcpPayload);
+ } else {
+ //This packet is a dhcp reply from DHCP server.
+ sendReply(context, dhcpPayload);
+ }
+ }
+ }
+ }
+
+ //forward the packet to ConnectPoint where the DHCP server is attached.
+ private void forwardPacket(PacketContext context, DHCP dhcpPayload) {
+ if (dhcpPayload == null) {
+ log.debug("DHCP packet without payload, do nothing");
+ return;
+ }
+
+ //send Packetout to dhcp server connectpoint.
+ if (dhcpServerConnectPoint != null) {
+ TrafficTreatment t = DefaultTrafficTreatment.builder()
+ .setOutput(dhcpServerConnectPoint.port()).build();
+ OutboundPacket o = new DefaultOutboundPacket(
+ dhcpServerConnectPoint.deviceId(), t, context.inPacket().unparsed());
+ packetService.emit(o);
+ }
+ }
+
+ /*//process the dhcp packet before sending to server
+ private void processDhcpPacket(PacketContext context, DHCP dhcpPayload) {
+ if (dhcpPayload == null) {
+ return;
+ }
+ Ethernet packet = context.inPacket().parsed();
+ DHCPPacketType incomingPacketType = null;
+ for (DHCPOption option : dhcpPayload.getOptions()) {
+ if (option.getCode() == OptionCode_MessageType.getValue()) {
+ byte[] data = option.getData();
+ incomingPacketType = DHCPPacketType.getType(data[0]);
+ }
+ }
+ switch (incomingPacketType) {
+ case DHCPDISCOVER:
+ break;
+ default:
+ break;
+ }
+ }*/
+
+ //send the response to the requestor host.
+ private void sendReply(PacketContext context, DHCP dhcpPayload) {
+ if (dhcpPayload == null) {
+ log.debug("DHCP packet without payload, do nothing");
+ return;
+ }
+ //get the host info
+ Ethernet packet = context.inPacket().parsed();
+ Host host = hostService.getHost(HostId.hostId(packet.getDestinationMAC()));
+ ConnectPoint dhcpRequestor = new ConnectPoint(host.location().elementId(),
+ host.location().port());
+
+ //send Packetout to requestor host.
+ if (dhcpRequestor != null) {
+ TrafficTreatment t = DefaultTrafficTreatment.builder()
+ .setOutput(dhcpRequestor.port()).build();
+ OutboundPacket o = new DefaultOutboundPacket(
+ dhcpRequestor.deviceId(), t, context.inPacket().unparsed());
+ packetService.emit(o);
+ }
+ }
+ }
+
+ /**
+ * Listener for network config events.
+ */
+ private class InternalConfigListener implements NetworkConfigListener {
+
+ @Override
+ public void event(NetworkConfigEvent event) {
+
+ if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+ event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+ event.configClass().equals(DhcpRelayConfig.class)) {
+ updateConfig();
+ log.info("Reconfigured");
+ }
+ }
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java
new file mode 100644
index 0000000..24ad67b
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+ */
+package org.onosproject.dhcprelay;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.config.Config;
+
+import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
+/**
+ * DHCP Relay Config class.
+ */
+public class DhcpRelayConfig extends Config<ApplicationId> {
+
+ private static final String DHCP_CONNECT_POINT = "dhcpserverConnectPoint";
+
+ @Override
+ public boolean isValid() {
+
+ return hasOnlyFields(DHCP_CONNECT_POINT) &&
+ isConnectPoint(DHCP_CONNECT_POINT, MANDATORY);
+ }
+
+ /**
+ * Returns the dhcp server connect point.
+ *
+ * @return dhcp server connect point
+ */
+ public ConnectPoint getDhcpServerConnectPoint() {
+ return ConnectPoint.deviceConnectPoint(object.path(DHCP_CONNECT_POINT).asText());
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/package-info.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/package-info.java
new file mode 100644
index 0000000..f788818
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014-present Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * DHCP-RELAY application.
+ */
+package org.onosproject.dhcprelay;
diff --git a/apps/dhcprelay/src/main/resources/dhcp-relay.json b/apps/dhcprelay/src/main/resources/dhcp-relay.json
new file mode 100644
index 0000000..f94f15c
--- /dev/null
+++ b/apps/dhcprelay/src/main/resources/dhcp-relay.json
@@ -0,0 +1,9 @@
+{
+ "apps": {
+ "org.onosproject.dhcp-relay" : {
+ "dhcprelay" : {
+ "dhcpserverConnectPoint": "of:0000000000000002/2"
+ }
+ }
+ }
+}
diff --git a/apps/pom.xml b/apps/pom.xml
index c8be00f..5b82e85 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -53,6 +53,7 @@
<module>flowanalyzer</module>
<module>vtn</module>
<module>dhcp</module>
+ <module>dhcprelay</module>
<module>mfwd</module>
<module>pim</module>
<module>mlb</module>