-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Collections;
-import java.util.Date;
import java.util.Dictionary;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.felix.dm.Component;
import org.opendaylight.controller.clustering.services.CacheConfigException;
import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.clustering.services.IClusterServices;
import org.opendaylight.controller.configuration.IConfigurationContainerAware;
import org.opendaylight.controller.forwarding.staticrouting.IStaticRoutingAware;
import org.opendaylight.controller.forwarding.staticrouting.StaticRoute;
import org.opendaylight.controller.forwarding.staticrouting.StaticRouteConfig;
+import org.opendaylight.controller.hosttracker.HostIdFactory;
+import org.opendaylight.controller.hosttracker.IHostId;
import org.opendaylight.controller.hosttracker.IfIptoHost;
import org.opendaylight.controller.hosttracker.IfNewHostNotify;
import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
-import org.opendaylight.controller.sal.utils.StatusCode;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.IObjectReader;
import org.opendaylight.controller.sal.utils.ObjectReader;
import org.opendaylight.controller.sal.utils.ObjectWriter;
import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Static Routing feature provides the bridge between SDN and Non-SDN networks.
- *
- *
- *
*/
-public class StaticRoutingImplementation implements IfNewHostNotify,
- IForwardingStaticRouting, IObjectReader, IConfigurationContainerAware,
- ICacheUpdateAware<Long, String> {
- private static Logger log = LoggerFactory
- .getLogger(StaticRoutingImplementation.class);
+public class StaticRoutingImplementation implements IfNewHostNotify, IForwardingStaticRouting, IObjectReader,
+ IConfigurationContainerAware {
+ private static Logger log = LoggerFactory.getLogger(StaticRoutingImplementation.class);
private static String ROOT = GlobalConstants.STARTUPHOME.toString();
- private static final String SAVE = "Save";
ConcurrentMap<String, StaticRoute> staticRoutes;
ConcurrentMap<String, StaticRouteConfig> staticRouteConfigs;
private IfIptoHost hostTracker;
private Timer gatewayProbeTimer;
private String staticRoutesFileName = null;
- private Map<Long, String> configSaveEvent;
private IClusterContainerServices clusterContainerService = null;
private Set<IStaticRoutingAware> staticRoutingAware = Collections
.synchronizedSet(new HashSet<IStaticRoutingAware>());
+ private ExecutorService executor;
void setStaticRoutingAware(IStaticRoutingAware s) {
if (this.staticRoutingAware != null) {
}
}
+ @Override
public ConcurrentMap<String, StaticRouteConfig> getStaticRouteConfigs() {
return staticRouteConfigs;
}
- public void setStaticRouteConfigs(
- ConcurrentMap<String, StaticRouteConfig> staticRouteConfigs) {
- this.staticRouteConfigs = staticRouteConfigs;
- }
-
@Override
- public Object readObject(ObjectInputStream ois)
- throws FileNotFoundException, IOException, ClassNotFoundException {
+ public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
// Perform the class deserialization locally, from inside the package
// where the class is defined
return ois.readObject();
@SuppressWarnings("unchecked")
private void loadConfiguration() {
ObjectReader objReader = new ObjectReader();
- ConcurrentMap<String, StaticRouteConfig> confList = (ConcurrentMap<String, StaticRouteConfig>) objReader
- .read(this, staticRoutesFileName);
+ ConcurrentMap<String, StaticRouteConfig> confList = (ConcurrentMap<String, StaticRouteConfig>) objReader.read(
+ this, staticRoutesFileName);
if (confList == null) {
return;
}
}
-
private Status saveConfig() {
- // Publish the save config event to the cluster nodes
- configSaveEvent.put(new Date().getTime(), SAVE);
return saveConfigInternal();
}
Status status;
ObjectWriter objWriter = new ObjectWriter();
- status = objWriter.write(
- new ConcurrentHashMap<String, StaticRouteConfig>(
- staticRouteConfigs), staticRoutesFileName);
+ status = objWriter.write(new ConcurrentHashMap<String, StaticRouteConfig>(staticRouteConfigs),
+ staticRoutesFileName);
if (status.isSuccess()) {
return status;
}
@SuppressWarnings("deprecation")
- private void allocateCaches() {
+ private void allocateCaches() {
if (this.clusterContainerService == null) {
- log
- .info("un-initialized clusterContainerService, can't create cache");
+ log.info("un-initialized clusterContainerService, can't create cache");
return;
}
try {
- clusterContainerService.createCache(
- "forwarding.staticrouting.routes", EnumSet
- .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
- clusterContainerService.createCache(
- "forwarding.staticrouting.configs", EnumSet
- .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
- clusterContainerService.createCache(
- "forwarding.staticrouting.configSaveEvent", EnumSet
- .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
-
+ clusterContainerService.createCache("forwarding.staticrouting.routes",
+ EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ clusterContainerService.createCache("forwarding.staticrouting.configs",
+ EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
} catch (CacheExistException cee) {
- log
- .error("\nCache already exists - destroy and recreate if needed");
+ log.error("\nCache already exists - destroy and recreate if needed");
} catch (CacheConfigException cce) {
log.error("\nCache configuration invalid - check cache mode");
}
@SuppressWarnings({ "unchecked", "deprecation" })
private void retrieveCaches() {
if (this.clusterContainerService == null) {
- log
- .info("un-initialized clusterContainerService, can't retrieve cache");
+ log.info("un-initialized clusterContainerService, can't retrieve cache");
return;
}
if (staticRouteConfigs == null) {
log.error("\nFailed to get rulesDB handle");
}
- configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
- .getCache("forwarding.staticrouting.configSaveEvent");
- if (configSaveEvent == null) {
- log.error("\nFailed to get cache for configSaveEvent");
- }
- }
-
- @SuppressWarnings("deprecation")
- private void destroyCaches() {
- if (this.clusterContainerService == null) {
- log
- .info("un-initialized clusterContainerService, can't destroy cache");
- return;
- }
-
- clusterContainerService.destroyCache("forwarding.staticrouting.routes");
- clusterContainerService
- .destroyCache("forwarding.staticrouting.configs");
- clusterContainerService
- .destroyCache("forwarding.staticrouting.configSaveEvent");
-
- }
-
- @Override
- public void entryCreated(Long key, String cacheName, boolean local) {
- }
-
- @Override
- public void entryUpdated(Long key, String new_value, String cacheName,
- boolean originLocal) {
- saveConfigInternal();
- }
-
- @Override
- public void entryDeleted(Long key, String cacheName, boolean originLocal) {
}
private void notifyStaticRouteUpdate(StaticRoute s, boolean update) {
try {
ra.staticRouteUpdate(s, update);
} catch (Exception e) {
- log.error("",e);
+ log.error("", e);
}
}
}
}
}
- private class NotifyStaticRouteThread extends Thread {
+ private class NotifyStaticRouteWorker implements Callable<Object> {
+
+ private String name;
private StaticRoute staticRoute;
private boolean added;
- public NotifyStaticRouteThread(StaticRoute s, boolean update) {
+ public NotifyStaticRouteWorker(String name, StaticRoute s, boolean update) {
+ this.name = name;
this.staticRoute = s;
this.added = update;
}
- public void run() {
- if (!added
- || (staticRoute.getType() == StaticRoute.NextHopType.SWITCHPORT)) {
+ @Override
+ public Object call() throws Exception {
+ if (!added || (staticRoute.getType() == StaticRoute.NextHopType.SWITCHPORT)) {
notifyStaticRouteUpdate(staticRoute, added);
} else {
- HostNodeConnector host = hostTracker.hostQuery(staticRoute
- .getNextHopAddress());
+ InetAddress nh = staticRoute.getNextHopAddress();
+ // HostTracker hosts db key scheme implementation
+ IHostId id = HostIdFactory.create(nh, null);
+ HostNodeConnector host = hostTracker.hostQuery(id);
if (host == null) {
- Future<HostNodeConnector> future = hostTracker
- .discoverHost(staticRoute.getNextHopAddress());
+ log.debug("Next hop {} is not present, try to discover it", nh.getHostAddress());
+ Future<HostNodeConnector> future = hostTracker.discoverHost(id);
if (future != null) {
try {
host = future.get();
+ } catch (InterruptedException ioe) {
+ log.trace("Thread interrupted {}", ioe);
} catch (Exception e) {
- log.error("",e);
+ log.error("", e);
}
}
}
if (host != null) {
+ log.debug("Next hop {} is found", nh.getHostAddress());
staticRoute.setHost(host);
+ // static route object has changed
+ // put the changed object back in the cache
+ // for it to sync
+ staticRoutes.put(name, staticRoute);
notifyStaticRouteUpdate(staticRoute, added);
+ } else {
+ log.debug("Next hop {} is still not present, try again later", nh.getHostAddress());
}
}
+ return null;
}
}
- private void checkAndUpdateListeners(StaticRoute staticRoute, boolean added) {
- new NotifyStaticRouteThread(staticRoute, added).start();
+ private void checkAndUpdateListeners(String name, StaticRoute staticRoute, boolean added) {
+ NotifyStaticRouteWorker worker = new NotifyStaticRouteWorker(name, staticRoute, added);
+ try {
+ executor.submit(worker);
+ } catch (Exception e) {
+ log.error("got Exception ", e);
+ }
}
private void notifyHostUpdate(HostNodeConnector host, boolean added) {
- if (host == null)
+ if (host == null) {
return;
- for (StaticRoute s : staticRoutes.values()) {
- if (s.getType() == StaticRoute.NextHopType.SWITCHPORT)
+ }
+ for (Map.Entry<String, StaticRoute> s : staticRoutes.entrySet()) {
+ StaticRoute route = s.getValue();
+ if (route.getType() == StaticRoute.NextHopType.SWITCHPORT) {
continue;
- if (s.getNextHopAddress().equals(host.getNetworkAddress())) {
+ }
+ if (route.getNextHopAddress().equals(host.getNetworkAddress())) {
if (added) {
- s.setHost(host);
+ route.setHost(host);
} else {
- s.setHost(null);
+ route.setHost(null);
}
- notifyStaticRouteUpdate(s, added);
+ // static route object has changed
+ // put the changed object back in the cache
+ // for it to sync
+ staticRoutes.put(s.getKey(), route);
+ notifyStaticRouteUpdate(route, added);
}
}
}
}
public boolean isIPv4AddressValid(String cidr) {
- if (cidr == null)
+ if (cidr == null) {
return false;
+ }
String values[] = cidr.split("/");
Pattern ipv4Pattern = Pattern
return 0;
}
+ @Override
public StaticRoute getBestMatchStaticRoute(InetAddress ipAddress) {
ByteBuffer bblongestPrefix = null;
try {
- bblongestPrefix = ByteBuffer.wrap(InetAddress.getByName("0.0.0.0")
- .getAddress());
+ bblongestPrefix = ByteBuffer.wrap(InetAddress.getByName("0.0.0.0").getAddress());
} catch (Exception e) {
return null;
}
return longestPrefixRoute;
}
+ @Override
public Status addStaticRoute(StaticRouteConfig config) {
- Status status;
-
- status = config.isValid();
+ Status status = config.isValid();
if (!status.isSuccess()) {
return status;
}
if (staticRouteConfigs.get(config.getName()) != null) {
- return new Status(StatusCode.CONFLICT,
- "A valid Static Route configuration with this name " +
- "already exists. Please use a different name");
+ return new Status(StatusCode.CONFLICT, "A valid Static Route configuration with this name "
+ + "already exists. Please use a different name");
}
- for (StaticRouteConfig s : staticRouteConfigs.values()) {
- if (s.equals(config)) {
- return new Status(StatusCode.CONFLICT,
- "This conflicts with an existing Static Route " +
- "Configuration. Please check the configuration " +
- "and try again");
+
+ // Update database
+ StaticRoute sRoute = new StaticRoute(config);
+
+ for (Map.Entry<String, StaticRoute> entry : staticRoutes.entrySet()) {
+ if (entry.getValue().compareTo(sRoute) == 0) {
+ return new Status(StatusCode.CONFLICT, "This conflicts with an existing Static Route "
+ + "Configuration. Please check the configuration " + "and try again");
}
}
+ staticRoutes.put(config.getName(), sRoute);
+ // Update config databse
staticRouteConfigs.put(config.getName(), config);
- StaticRoute sRoute = new StaticRoute(config);
- staticRoutes.put(config.getName(), sRoute);
- checkAndUpdateListeners(sRoute, true);
+
+ // Notify
+ checkAndUpdateListeners(config.getName(), sRoute, true);
return status;
}
+ @Override
public Status removeStaticRoute(String name) {
staticRouteConfigs.remove(name);
StaticRoute sRoute = staticRoutes.remove(name);
if (sRoute != null) {
- checkAndUpdateListeners(sRoute, false);
+ checkAndUpdateListeners(name, sRoute, false);
return new Status(StatusCode.SUCCESS, null);
}
- return new Status(StatusCode.NOTFOUND,
- "Static Route with name " + name + " is not found");
+ return new Status(StatusCode.NOTFOUND, "Static Route with name " + name + " is not found");
}
void setClusterContainerService(IClusterContainerServices s) {
containerName = "";
}
- staticRoutesFileName = ROOT + "staticRouting_" + containerName
- + ".conf";
+ staticRoutesFileName = ROOT + "staticRouting_" + containerName + ".conf";
- log.debug("forwarding.staticrouting starting on container {}",
- containerName);
- //staticRoutes = new ConcurrentHashMap<String, StaticRoute>();
+ log.debug("forwarding.staticrouting starting on container {}", containerName);
allocateCaches();
retrieveCaches();
-
- if (staticRouteConfigs.isEmpty())
+ this.executor = Executors.newFixedThreadPool(1);
+ if (staticRouteConfigs.isEmpty()) {
loadConfiguration();
+ }
/*
- * Slow probe to identify any gateway that might have silently appeared
- * after the Static Routing Configuration.
+ * Slow probe to identify any gateway that might have silently appeared
+ * after the Static Routing Configuration.
*/
gatewayProbeTimer = new Timer();
gatewayProbeTimer.schedule(new TimerTask() {
@Override
public void run() {
- for (StaticRoute s : staticRoutes.values()) {
- if ((s.getType() == StaticRoute.NextHopType.IPADDRESS)
- && s.getHost() == null) {
- checkAndUpdateListeners(s, true);
+ for (Map.Entry<String, StaticRoute> s : staticRoutes.entrySet()) {
+ StaticRoute route = s.getValue();
+ if ((route.getType() == StaticRoute.NextHopType.IPADDRESS) && route.getHost() == null) {
+ checkAndUpdateListeners(s.getKey(), route, true);
}
}
}
}, 60 * 1000, 60 * 1000);
+
}
/**
- * Function called by the dependency manager when at least one
- * dependency become unsatisfied or when the component is shutting
- * down because for example bundle is being stopped.
+ * Function called by the dependency manager when at least one dependency
+ * become unsatisfied or when the component is shutting down because for
+ * example bundle is being stopped.
*
*/
void destroy() {
- log.debug("Destroy all the Static Routing Rules given we are "
- + "shutting down");
+ log.debug("Destroy all the Static Routing Rules given we are " + "shutting down");
- destroyCaches();
gatewayProbeTimer.cancel();
// Clear the listener so to be ready in next life
}
/**
- * Function called by dependency manager after "init ()" is called
- * and after the services provided by the class are registered in
- * the service registry
+ * Function called by dependency manager after "init ()" is called and after
+ * the services provided by the class are registered in the service registry
*
*/
void start() {
}
/**
- * Function called by the dependency manager before the services
- * exported by the component are unregistered, this will be
- * followed by a "destroy ()" calls
+ * Function called by the dependency manager before the services exported by
+ * the component are unregistered, this will be followed by a "destroy ()"
+ * calls
*
*/
void stop() {
+ executor.shutdown();
}
@Override
public Status saveConfiguration() {
return this.saveConfig();
}
+
}