blob: f508f5d663ab29d2c091d610b6204569b134e887 [file] [log] [blame]
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);
}
}