package net.floodlightcontroller.core.internal; import com.google.common.base.Preconditions; import net.floodlightcontroller.core.IOFConnectionBackend; import net.floodlightcontroller.core.IOFSwitchBackend; import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.SwitchDescription; import org.projectfloodlight.openflow.protocol.OFFactory; import org.projectfloodlight.openflow.types.DatapathId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import java.util.*; /** * This implementation of ISwitchDriverRegistry uses a naive algorithm to * perform longest prefix matching on the manufacturer description prefixes * * We maintain a map that maps prefixes to the drivers as well as a sorted * set that contains the prefixes sorted by their length. We exploit the fact * that lexicographical order defines that shorter strings are always less * than longer strings with the same prefix). Thus we can use reverse order for * our purposes. * To perform a lookup we iterate through the sorted set until we find a prefix * that matches the manufacturer description. Since the set is sorted this * will be the longest matching prefix. * * @author gregor */ class NaiveSwitchDriverRegistry implements ISwitchDriverRegistry { protected static final Logger log = LoggerFactory.getLogger(NaiveSwitchDriverRegistry.class); private final SortedSet<String> switchDescSorted; private final Map<String,IOFSwitchDriver> switchBindingMap; private final IOFSwitchManager switchManager; public NaiveSwitchDriverRegistry(@Nonnull IOFSwitchManager switchManager) { Preconditions.checkNotNull(switchManager, "switchManager must not be null"); this.switchManager = switchManager; switchBindingMap = new HashMap<String, IOFSwitchDriver>(); switchDescSorted = new TreeSet<String>(Collections.reverseOrder()); } @Override public synchronized void addSwitchDriver(String manufacturerDescPrefix, IOFSwitchDriver driver) { Preconditions.checkNotNull(manufacturerDescPrefix, "manufactererDescProfix"); Preconditions.checkNotNull(driver, "driver"); IOFSwitchDriver existingDriver = switchBindingMap.get(manufacturerDescPrefix); if (existingDriver != null ) { throw new IllegalStateException("Failed to add OFSwitch driver for " + manufacturerDescPrefix + "already registered"); } switchBindingMap.put(manufacturerDescPrefix, driver); switchDescSorted.add(manufacturerDescPrefix); } @Override // TODO: instead of synchronized we could actually use a r/w lock // but it's probably not worth it. public synchronized IOFSwitchBackend getOFSwitchInstance(IOFConnectionBackend connection, SwitchDescription description, OFFactory factory, DatapathId id) { Preconditions.checkNotNull(connection, "connection"); Preconditions.checkNotNull(description, "description"); Preconditions.checkNotNull(factory, "factory"); Preconditions.checkNotNull(id, "id"); Preconditions.checkNotNull(description.getHardwareDescription(), "hardware description"); Preconditions.checkNotNull(description.getManufacturerDescription(), "manufacturer description"); Preconditions.checkNotNull(description.getSerialNumber(), "serial number"); Preconditions.checkNotNull(description.getDatapathDescription(), "datapath description"); Preconditions.checkNotNull(description.getSoftwareDescription(), "software description"); // Find the appropriate driver for (String descPrefix: switchDescSorted) { if (description.getManufacturerDescription() .startsWith(descPrefix)) { IOFSwitchDriver driver = switchBindingMap.get(descPrefix); IOFSwitchBackend sw = driver.getOFSwitchImpl(description, factory); if (sw != null) { sw.setSwitchProperties(description); return sw; } } } // no switch found IOFSwitchBackend sw = new OFSwitch(connection, factory, switchManager, id); sw.setSwitchProperties(description); return sw; } }