New module SdnIpConfigReader useful for SDN-IP. It provides configuration to ARP Proxy for nodes not running SDN-IP.
Change-Id: I8e65d774bf0722897898fc2e3aec0c2a29cb566f
diff --git a/src/main/java/net/onrc/onos/apps/sdnip/SdnIpConfigReader.java b/src/main/java/net/onrc/onos/apps/sdnip/SdnIpConfigReader.java
new file mode 100644
index 0000000..f508f5d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/apps/sdnip/SdnIpConfigReader.java
@@ -0,0 +1,201 @@
+package net.onrc.onos.apps.sdnip;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.core.main.config.IConfigInfoService;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.apache.commons.configuration.ConfigurationRuntimeException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
+import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
+import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
+
+/**
+ * SDN-IP Config Reader provides IConfigInfoService
+ * by reading from an SDN-IP configuration file.
+ * It must be enabled on the nodes within the cluster
+ * not running SDN-IP.
+ * <p/>
+ * TODO: As a long term solution, a module providing
+ * general network configuration to ONOS nodes should be used.
+ */
+public class SdnIpConfigReader implements IFloodlightModule, IConfigInfoService {
+
+ private static final Logger log = LoggerFactory.getLogger(SdnIpConfigReader.class);
+
+ private static final String DEFAULT_CONFIG_FILENAME = "config.json";
+ private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
+ private Map<String, Interface> interfaces;
+ private Map<InetAddress, BgpPeer> bgpPeers;
+ private MACAddress bgpdMacAddress;
+ private short vlan;
+ private InvertedRadixTree<Interface> interfaceRoutes;
+ private Set<SwitchPort> externalNetworkSwitchPorts;
+
+ /**
+ * Reads the info contained in the configuration file.
+ *
+ * @param configFilename The name of configuration file for SDN-IP application.
+ */
+ private void readConfiguration(String configFilename) {
+ File gatewaysFile = new File(configFilename);
+ ObjectMapper mapper = new ObjectMapper();
+
+ try {
+ Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
+ interfaces = new HashMap<>();
+ for (Interface intf : config.getInterfaces()) {
+ interfaces.put(intf.getName(), intf);
+ externalNetworkSwitchPorts.add(new SwitchPort(intf.getDpid(),
+ intf.getPort()));
+ }
+ bgpPeers = new HashMap<>();
+ for (BgpPeer peer : config.getPeers()) {
+ bgpPeers.put(peer.getIpAddress(), peer);
+ }
+ bgpdMacAddress = config.getBgpdMacAddress();
+ vlan = config.getVlan();
+ } catch (JsonParseException | JsonMappingException e) {
+ log.error("Error in JSON file", e);
+ throw new ConfigurationRuntimeException("Error in JSON file", e);
+ } catch (IOException e) {
+ log.error("Error reading JSON file", e);
+ throw new ConfigurationRuntimeException("Error in JSON file", e);
+ }
+
+ // Populate the interface InvertedRadixTree
+ for (Interface intf : interfaces.values()) {
+ Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
+ intf.getPrefixLength());
+ interfaceRoutes.put(prefix.toBinaryString(), intf);
+ }
+ }
+
+ /**
+ * To find the Interface which has longest matchable IP prefix (sub-network
+ * prefix) to next hop IP address.
+ *
+ * @param address the IP address of next hop router
+ * @return Interface the Interface which has longest matchable IP prefix
+ */
+ private Interface longestInterfacePrefixMatch(InetAddress address) {
+ Prefix prefixToSearchFor = new Prefix(address.getAddress(),
+ Prefix.MAX_PREFIX_LENGTH);
+ Iterator<Interface> it =
+ interfaceRoutes.getValuesForKeysPrefixing(
+ prefixToSearchFor.toBinaryString()).iterator();
+ Interface intf = null;
+ // Find the last prefix, which will be the longest prefix
+ while (it.hasNext()) {
+ intf = it.next();
+ }
+
+ return intf;
+ }
+
+ @Override
+ public boolean isInterfaceAddress(InetAddress address) {
+ Interface intf = longestInterfacePrefixMatch(address);
+ return (intf != null && intf.getIpAddress().equals(address));
+ }
+
+ @Override
+ public boolean inConnectedNetwork(InetAddress address) {
+ Interface intf = longestInterfacePrefixMatch(address);
+ return (intf != null && !intf.getIpAddress().equals(address));
+ }
+
+ @Override
+ public boolean fromExternalNetwork(long inDpid, short inPort) {
+ for (Interface intf : interfaces.values()) {
+ if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Interface getOutgoingInterface(InetAddress dstIpAddress) {
+ return longestInterfacePrefixMatch(dstIpAddress);
+ }
+
+ @Override
+ public boolean hasLayer3Configuration() {
+ return !interfaces.isEmpty();
+ }
+
+ @Override
+ public MACAddress getRouterMacAddress() {
+ return bgpdMacAddress;
+ }
+
+ @Override
+ public short getVlan() {
+ return vlan;
+ }
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+ Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
+ l.add(IConfigInfoService.class);
+ return l;
+ }
+
+ @Override
+ public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+ Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
+ m.put(IConfigInfoService.class, this);
+ return m;
+ }
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+ return null;
+ }
+
+ @Override
+ public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+ interfaceRoutes = new ConcurrentInvertedRadixTree<>(
+ new DefaultByteArrayNodeFactory());
+ externalNetworkSwitchPorts = new HashSet<SwitchPort>();
+ // Reading config values
+ String configFilenameParameter = context.getConfigParams(this).get("configfile");
+ if (configFilenameParameter != null) {
+ currentConfigFilename = configFilenameParameter;
+ }
+ log.debug("Config file set to {}", currentConfigFilename);
+
+ readConfiguration(currentConfigFilename);
+ }
+
+ @Override
+ public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
+ }
+
+ @Override
+ public Set<SwitchPort> getExternalSwitchPorts() {
+ return Collections.unmodifiableSet(externalNetworkSwitchPorts);
+ }
+}
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index 42c652f..2346e21 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -10,6 +10,7 @@
net.onrc.onos.core.datagrid.HazelcastDatagrid
net.onrc.onos.core.flowprogrammer.FlowProgrammer
net.onrc.onos.apps.sdnip.SdnIp
+net.onrc.onos.apps.sdnip.SdnIpConfigReader
net.onrc.onos.apps.websocket.WebSocketModule
net.onrc.onos.core.registry.ZookeeperRegistry
net.onrc.onos.core.registry.StandaloneRegistry