[CORD-1616] Supports PD by DHCP relay App
Change-Id: I9a23534023ca2847bd3f77a3f9ee2b468c5bb422
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index e1b3933..44653bd 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -1598,4 +1598,9 @@
flowObjectiveService.apply(deviceId, fwd);
});
}
+
+ @Override
+ public void setDhcpFpmEnabled(Boolean enabled) {
+ // v4 does not use fpm. Do nothing.
+ }
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index 05c639c..4023327 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -55,8 +55,10 @@
import org.onosproject.dhcprelay.api.DhcpServerInfo;
import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
+import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
+import org.onosproject.routing.fpm.api.FpmRecord;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -161,6 +163,9 @@
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -171,6 +176,8 @@
protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
private InternalHostListener hostListener = new InternalHostListener();
+ private Boolean dhcpFpmEnabled = false;
+
private List<DhcpServerInfo> defaultServerInfoList = Lists.newArrayList();
private List<DhcpServerInfo> indirectServerInfoList = Lists.newArrayList();
@@ -664,6 +671,9 @@
HexString.toHexString(nextHopIp.toOctets(), ":"));
routeStore.removeRoute(routeForPrefix);
+ if (this.dhcpFpmEnabled) {
+ dhcpFpmPrefixStore.removeFpmRecord(ipPrefix);
+ }
}
}
}
@@ -745,6 +755,10 @@
Route routeForPrefix = new Route(Route.Source.STATIC, ipPrefix, nextHopIp);
log.warn("adding Route of PD for indirectly connected.");
routeStore.updateRoute(routeForPrefix);
+ if (this.dhcpFpmEnabled) {
+ FpmRecord record = new FpmRecord(ipPrefix, nextHopIp, FpmRecord.Type.DHCP_RELAY);
+ dhcpFpmPrefixStore.addFpmRecord(ipPrefix, record);
+ }
}
}
}
@@ -834,19 +848,15 @@
etherReply.setDestinationMACAddress(dhcpConnectMac);
etherReply.setVlanID(dhcpConnectVlan.toShort());
-
IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
byte[] peerAddress = clientIpv6.getSourceAddress();
ipv6Packet.setSourceAddress(ipFacingServer.toOctets());
ipv6Packet.setDestinationAddress(dhcpServerIp.toOctets());
-
UDP udpPacket = (UDP) ipv6Packet.getPayload();
udpPacket.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
DHCP6 dhcp6Packet = (DHCP6) udpPacket.getPayload();
byte[] dhcp6PacketByte = dhcp6Packet.serialize();
- // notify onos and quagga to release PD
- //releasePD(dhcp6Packet);
ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
@@ -857,8 +867,6 @@
DHCP6 dhcp6Relay = new DHCP6();
dhcp6Relay.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
- // link address: server uses the address to identify the link on which the client
- // is located.
if (directConnFlag) {
dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
log.debug("direct connection: relayAgentIp obtained dynamically {}",
@@ -882,7 +890,6 @@
etherReply.setDestinationMACAddress(indirectDhcpConnectMac);
etherReply.setVlanID(indirectDhcpConnectVlan.toShort());
ipv6Packet.setDestinationAddress(indirectDhcpServerIp.toOctets());
-
}
if (indirectRelayAgentIpFromCfg == null) {
dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
@@ -1114,6 +1121,11 @@
}
@Override
+ public void setDhcpFpmEnabled(Boolean enabled) {
+ dhcpFpmEnabled = enabled;
+ }
+
+ @Override
public void setDefaultDhcpServerConfigs(Collection<DhcpServerConfig> configs) {
setDhcpServerConfigs(configs, defaultServerInfoList);
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index 15026eb..fc8bedc 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -45,6 +45,7 @@
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
import org.onlab.util.Tools;
@@ -57,8 +58,11 @@
import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
+import org.onosproject.dhcprelay.config.EnableDhcpFpmConfig;
import org.onosproject.dhcprelay.store.DhcpRecord;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
+import org.onosproject.dhcprelay.store.DhcpFpmPrefixStore;
+import org.onosproject.routing.fpm.api.FpmRecord;
import org.onosproject.net.Device;
import org.onosproject.dhcprelay.config.DhcpServerConfig;
import org.onosproject.net.Host;
@@ -85,6 +89,7 @@
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
+
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -111,31 +116,40 @@
private final Set<ConfigFactory> factories = ImmutableSet.of(
new ConfigFactory<ApplicationId, DefaultDhcpRelayConfig>(APP_SUBJECT_FACTORY,
- DefaultDhcpRelayConfig.class,
- DefaultDhcpRelayConfig.KEY,
- true) {
+ DefaultDhcpRelayConfig.class,
+ DefaultDhcpRelayConfig.KEY,
+ true) {
@Override
public DefaultDhcpRelayConfig createConfig() {
return new DefaultDhcpRelayConfig();
}
},
new ConfigFactory<ApplicationId, IndirectDhcpRelayConfig>(APP_SUBJECT_FACTORY,
- IndirectDhcpRelayConfig.class,
- IndirectDhcpRelayConfig.KEY,
- true) {
+ IndirectDhcpRelayConfig.class,
+ IndirectDhcpRelayConfig.KEY,
+ true) {
@Override
public IndirectDhcpRelayConfig createConfig() {
return new IndirectDhcpRelayConfig();
}
},
new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
- IgnoreDhcpConfig.class,
- IgnoreDhcpConfig.KEY,
- true) {
+ IgnoreDhcpConfig.class,
+ IgnoreDhcpConfig.KEY,
+ true) {
@Override
public IgnoreDhcpConfig createConfig() {
return new IgnoreDhcpConfig();
}
+ },
+ new ConfigFactory<ApplicationId, EnableDhcpFpmConfig>(APP_SUBJECT_FACTORY,
+ EnableDhcpFpmConfig.class,
+ EnableDhcpFpmConfig.KEY,
+ false) {
+ @Override
+ public EnableDhcpFpmConfig createConfig() {
+ return new EnableDhcpFpmConfig();
+ }
}
);
@@ -163,6 +177,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DhcpFpmPrefixStore dhcpFpmPrefixStore;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
target = "(version=4)")
protected DhcpHandler v4Handler;
@@ -175,10 +192,15 @@
label = "Enable Address resolution protocol")
protected boolean arpEnabled = true;
+ @Property(name = "dhcpFpmEnabled", boolValue = false,
+ label = "Enable DhcpRelay Fpm")
+ protected boolean dhcpFpmEnabled = false;
+
protected DeviceListener deviceListener = new InternalDeviceListener();
private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
private ApplicationId appId;
+
@Activate
protected void activate(ComponentContext context) {
//start the dhcp relay agent
@@ -196,7 +218,7 @@
// Enable distribute route store
compCfgService.preSetProperty(ROUTE_STORE_IMPL,
- "distributed", Boolean.TRUE.toString());
+ "distributed", Boolean.TRUE.toString());
compCfgService.registerProperties(getClass());
deviceService.addListener(deviceListener);
@@ -223,7 +245,7 @@
if (flag != null) {
arpEnabled = flag;
log.info("Address resolution protocol is {}",
- arpEnabled ? "enabled" : "disabled");
+ arpEnabled ? "enabled" : "disabled");
}
if (arpEnabled) {
@@ -231,6 +253,25 @@
} else {
cancelArpPackets();
}
+
+ flag = Tools.isPropertyEnabled(properties, "dhcpFpmEnabled");
+ if (flag != null) {
+ boolean oldValue = dhcpFpmEnabled;
+ dhcpFpmEnabled = flag;
+ log.info("DhcpRelay FPM is {}",
+ dhcpFpmEnabled ? "enabled" : "disabled");
+
+ if (dhcpFpmEnabled && !oldValue) {
+ log.info("Dhcp Fpm is enabled.");
+ processDhcpFpmRoutes(true);
+ }
+ if (!dhcpFpmEnabled && oldValue) {
+ log.info("Dhcp Fpm is disabled.");
+ processDhcpFpmRoutes(false);
+ }
+ v6Handler.setDhcpFpmEnabled(dhcpFpmEnabled);
+ }
+
}
private static List<TrafficSelector> buildClientDhcpSelectors() {
@@ -296,6 +337,14 @@
}
}
+ private void processDhcpFpmRoutes(Boolean add) {
+ // needs to restore/remove fpm
+ }
+
+ public boolean isDhcpFpmEnabled() {
+ return dhcpFpmEnabled;
+ }
+
/**
* Request ARP packet in via PacketService.
*/
@@ -530,4 +579,24 @@
v6Handler.updateIgnoreVlanConfig(config);
}
}
+
+
+
+ public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
+ return dhcpFpmPrefixStore.getFpmRecord(prefix);
+ }
+
+ public Collection<FpmRecord> getFpmRecords() {
+ return dhcpFpmPrefixStore.getFpmRecords();
+ }
+
+ @Override
+ public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
+ dhcpFpmPrefixStore.addFpmRecord(prefix, fpmRecord);
+ }
+
+ @Override
+ public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
+ return dhcpFpmPrefixStore.removeFpmRecord(prefix);
+ }
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
index 5397d18..475a459 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
@@ -169,4 +169,12 @@
* @param config the config
*/
void updateIgnoreVlanConfig(IgnoreDhcpConfig config);
+
+ /**
+ * Sets DHCP FPM Enable state.
+ *
+ * @param dhcpFpmFlag flag indicating dhcpFpmEnable state
+ */
+ default void setDhcpFpmEnabled(Boolean dhcpFpmFlag) { }
+
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpRelayService.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpRelayService.java
index 2711a08..ef700d4 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpRelayService.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpRelayService.java
@@ -17,10 +17,11 @@
package org.onosproject.dhcprelay.api;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.dhcprelay.store.DhcpRecord;
+import org.onosproject.routing.fpm.api.FpmRecord;
import org.onosproject.net.HostId;
-
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -63,4 +64,42 @@
* @return list of indirect DHCP server information
*/
List<DhcpServerInfo> getIndirectDhcpServerInfoList();
+
+ /**
+ * Add DHCP FPM record to store.
+ *
+ * @param prefix the prefix
+ * @param fpmRecord the fpmRecord
+ */
+ void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord);
+
+ /**
+ * Delete DHCP FPM record from store.
+ *
+ * @param prefix the prefix
+ * @return DHCP record from store; empty value if it does not exist.
+ */
+ Optional<FpmRecord> removeFpmRecord(IpPrefix prefix);
+
+ /**
+ * Gets PD route record for specific prefix.
+ *
+ * @param prefix PD prefix
+ * @return the PD route record from store
+ */
+ Optional<FpmRecord> getFpmRecord(IpPrefix prefix);
+
+ /**
+ * Gets all PD route records from store.
+ *
+ * @return all PD records from store
+ */
+ Collection<FpmRecord> getFpmRecords();
+
+ /**
+ * Determine if DHCP FPM feature is enabled or not.
+ *
+ * @return boolean value
+ */
+ public boolean isDhcpFpmEnabled();
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmAddCommand.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmAddCommand.java
new file mode 100644
index 0000000..fd886b9
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmAddCommand.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.cli;
+
+//import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.apache.karaf.shell.commands.Argument;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.IpAddress;
+import org.onosproject.routing.fpm.api.FpmRecord;
+import org.onosproject.dhcprelay.api.DhcpRelayService;
+
+/**
+ * Prints Dhcp FPM Routes information.
+ */
+@Command(scope = "onos", name = "dhcp-fpm-add",
+ description = "Add DHCP FPM prefix in dhcp-fpm-store.")
+public class DhcpFpmAddCommand extends AbstractShellCommand {
+
+ private static final DhcpRelayService DHCP_RELAY_SERVICE = get(DhcpRelayService.class);
+
+ @Argument(index = 0, name = "prefix",
+ description = "prefix",
+ required = true, multiValued = false)
+ String prefixString = null;
+
+ @Argument(index = 1, name = "next hop",
+ description = "next hop",
+ required = true, multiValued = false)
+ String nextHopString = null;
+
+ @Override
+ protected void execute() {
+
+ IpPrefix prefix = IpPrefix.valueOf(prefixString);
+ IpAddress nextHop = IpAddress.valueOf(nextHopString);
+ FpmRecord record = new FpmRecord(prefix, nextHop, FpmRecord.Type.DHCP_RELAY);
+
+ DHCP_RELAY_SERVICE.addFpmRecord(prefix, record);
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmDeleteCommand.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmDeleteCommand.java
new file mode 100644
index 0000000..244bcf8
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmDeleteCommand.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.apache.karaf.shell.commands.Argument;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.dhcprelay.api.DhcpRelayService;
+
+/**
+ * Prints Dhcp FPM Routes information.
+ */
+@Command(scope = "onos", name = "dhcp-fpm-delete",
+ description = "delete DHCP FPM prefix in dhcp-fpm-store")
+public class DhcpFpmDeleteCommand extends AbstractShellCommand {
+
+ private static final DhcpRelayService DHCP_RELAY_SERVICE = get(DhcpRelayService.class);
+
+ @Argument(index = 0, name = "prefix",
+ description = "prefix",
+ required = true, multiValued = false)
+ String prefixString = null;
+
+ @Override
+ protected void execute() {
+ IpPrefix prefix = IpPrefix.valueOf(prefixString);
+
+ DHCP_RELAY_SERVICE.removeFpmRecord(prefix);
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmRoutesCommand.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmRoutesCommand.java
new file mode 100644
index 0000000..9aacac3
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpFpmRoutesCommand.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.cli;
+
+//import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+
+import org.onosproject.dhcprelay.api.DhcpRelayService;
+import org.onosproject.routing.fpm.api.FpmRecord;
+
+import java.util.Collection;
+
+/**
+ * Prints Dhcp FPM Routes information.
+ */
+@Command(scope = "onos", name = "dhcp-fpm-routes",
+ description = "DHCP FPM routes cli.")
+public class DhcpFpmRoutesCommand extends AbstractShellCommand {
+ private static final String NO_RECORDS = "No DHCP FPM Route record found";
+ private static final String HEADER = "DHCP FPM Routes records :";
+ private static final String ROUTE = "prefix=%s, next-hop=%s";
+
+
+ private static final DhcpRelayService DHCP_RELAY_SERVICE = get(DhcpRelayService.class);
+
+ @Override
+ protected void execute() {
+
+ print("Dhcp Fpm Feature is %s !", DHCP_RELAY_SERVICE.isDhcpFpmEnabled() ? "enabled" : "disabled");
+ print("\n");
+ Collection<FpmRecord> records = DHCP_RELAY_SERVICE.getFpmRecords();
+ if (records.isEmpty()) {
+ print(NO_RECORDS);
+ return;
+ }
+ print(HEADER);
+ records.forEach(record -> print(ROUTE,
+ record.ipPrefix(),
+ record.nextHop()));
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/EnableDhcpFpmConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/EnableDhcpFpmConfig.java
new file mode 100644
index 0000000..6eb9cf5
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/EnableDhcpFpmConfig.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.config;
+
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+
+
+/**
+ * Dhcp Fpm Config.
+ */
+public class EnableDhcpFpmConfig extends Config<ApplicationId> {
+ public static final String KEY = "dhcpFpm";
+ private static final String DHCP_FPM_ENABLE = "enabled";
+
+ @Override
+ public boolean isValid() {
+ if (!hasFields(DHCP_FPM_ENABLE)) {
+ return false;
+ }
+ return isBoolean(DHCP_FPM_ENABLE, FieldPresence.OPTIONAL);
+ }
+
+ /**
+ * Returns whether Dhcp Fpm is enabled.
+ *
+ * @return true if enabled, otherwise false
+ */
+ public boolean getDhcpFpmEnable() {
+ return object.path(DHCP_FPM_ENABLE).asBoolean(false);
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpFpmPrefixStore.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpFpmPrefixStore.java
new file mode 100644
index 0000000..694b048
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpFpmPrefixStore.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.store;
+import org.onosproject.routing.fpm.api.FpmRecord;
+import org.onosproject.routing.fpm.api.FpmPrefixStore;
+
+
+
+import org.onlab.packet.IpPrefix;
+import java.util.Optional;
+
+
+
+/**
+ * Interface to store DhcpFpm records.
+ */
+
+public interface DhcpFpmPrefixStore extends FpmPrefixStore {
+
+
+ /**
+ * Add a dhcp fpm record.
+ *
+ * @param prefix the route prefix in the advertisement
+ * @param fpmRecord the route for fpm
+ **/
+ public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord);
+
+ /**
+ * Remove a dhcp fpm entry
+ * and return the removed record; return empty value if not exists.
+ *
+ * @param prefix the route prefix in the advertisement
+ * @return none
+ **/
+ public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix);
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpFpmRecord.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpFpmRecord.java
new file mode 100644
index 0000000..81eadb7
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DhcpFpmRecord.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.store;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import java.util.Objects;
+import com.google.common.base.MoreObjects;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A class to define a Dhcp Fpm record.
+ */
+public class DhcpFpmRecord {
+
+ private IpPrefix prefix;
+ private IpAddress nextHop;
+
+ public DhcpFpmRecord(IpPrefix prefix, IpAddress nextHop) {
+ checkNotNull(prefix, "prefix cannot be null");
+ checkNotNull(nextHop, "ipAddress cannot be null");
+
+ this.prefix = prefix;
+ this.nextHop = nextHop;
+ }
+
+ /**
+ * Gets IP prefix of record.
+ *
+ * @return the IP prefix
+ */
+ public IpPrefix ipPrefix() {
+ return prefix;
+ }
+
+ /**
+ * Gets IP address of record.
+ *
+ * @return the IP address
+ */
+ public IpAddress nextHop() {
+ return nextHop;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(prefix, nextHop);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof DhcpFpmRecord)) {
+ return false;
+ }
+ DhcpFpmRecord that = (DhcpFpmRecord) obj;
+ return Objects.equals(prefix, that.prefix) &&
+ Objects.equals(nextHop, that.nextHop);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("prefix", prefix)
+ .add("ipAddress", nextHop)
+ .toString();
+ }
+}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedFpmPrefixStore.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedFpmPrefixStore.java
new file mode 100644
index 0000000..b82aac9
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/store/DistributedFpmPrefixStore.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.store;
+
+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.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Property;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.store.StoreDelegate;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.EventuallyConsistentMapEvent;
+import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
+import org.onosproject.routing.fpm.api.FpmRecord;
+import org.onosproject.routing.fpm.api.FpmPrefixStoreEvent;
+
+
+
+
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.Optional;
+
+
+
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Persistent Fpm Prefix Store with Listener.
+ */
+@Component(immediate = true)
+@Property(name = "fpm_type", value = "DHCP")
+@Service
+public class DistributedFpmPrefixStore implements DhcpFpmPrefixStore {
+
+ private static final KryoNamespace APP_KRYO = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(FpmRecord.class)
+ .register(FpmRecord.Type.class)
+ .build();
+
+ private Logger log = getLogger(getClass());
+ private StoreDelegate<FpmPrefixStoreEvent> delegate;
+ private EventuallyConsistentMap<IpPrefix, FpmRecord> dhcpFpmRecords;
+ private EventuallyConsistentMapListener<IpPrefix, FpmRecord> listener;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Activate
+ protected void activated() {
+ dhcpFpmRecords = storageService.<IpPrefix, FpmRecord>eventuallyConsistentMapBuilder()
+ .withName("DHCP-FPM-Records")
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .withSerializer(APP_KRYO)
+ .withPersistence()
+ .build();
+ listener = new InternalMapListener();
+ dhcpFpmRecords.addListener(listener);
+ }
+
+ @Deactivate
+ protected void deactivated() {
+ dhcpFpmRecords.removeListener(listener);
+ dhcpFpmRecords.destroy().join();
+ }
+
+ @Override
+ public void setDelegate(StoreDelegate<FpmPrefixStoreEvent> delegate) {
+ checkNotNull("Delegate can't be null", delegate);
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void unsetDelegate(StoreDelegate<FpmPrefixStoreEvent> delegate) {
+ this.delegate = null;
+ }
+
+ @Override
+ public boolean hasDelegate() {
+ return delegate != null;
+ }
+
+ @Override
+ public Optional<FpmRecord> getFpmRecord(IpPrefix prefix) {
+ checkNotNull(prefix, "Prefix can't be null");
+ return Optional.ofNullable(dhcpFpmRecords.get(prefix));
+ }
+
+ @Override
+ public Collection<FpmRecord> getFpmRecords() {
+ return dhcpFpmRecords.values();
+ }
+
+ /**
+ * Add a dhcp fpm entry.
+ *
+ * @param prefix the route prefix in the advertisement
+ * @param fpmRecord the route for fpm
+ **/
+ public void addFpmRecord(IpPrefix prefix, FpmRecord fpmRecord) {
+ checkNotNull(prefix, "Prefix can't be null");
+ checkNotNull(fpmRecord, "Fpm record can't be null");
+ dhcpFpmRecords.put(prefix, fpmRecord);
+ }
+
+ /**
+ * Remove a dhcp fpm entry.
+ *
+ * @param prefix the route prefix in the advertisement
+ * @return none
+ **/
+ public Optional<FpmRecord> removeFpmRecord(IpPrefix prefix) {
+ checkNotNull(prefix, "Prefix can't be null");
+ return Optional.ofNullable(dhcpFpmRecords.remove(prefix));
+ }
+
+ /**
+ * Internal map listener for Fpm records map.
+ */
+ private class InternalMapListener implements EventuallyConsistentMapListener<IpPrefix, FpmRecord> {
+ @Override
+ public void event(EventuallyConsistentMapEvent<IpPrefix, FpmRecord> event) {
+ FpmPrefixStoreEvent.Type eventType;
+ switch (event.type()) {
+ case PUT:
+ eventType = FpmPrefixStoreEvent.Type.ADD;
+ break;
+ case REMOVE:
+ eventType = FpmPrefixStoreEvent.Type.REMOVE;
+ break;
+ default:
+ log.warn("Unknown event type {}", event.type());
+ return;
+ }
+ if (delegate != null) {
+ delegate.notify(new FpmPrefixStoreEvent(eventType, event.value()));
+ }
+ }
+ }
+}