import org.opendaylight.controller.clustering.services.ICoordinatorChangeAware;
import org.opendaylight.controller.configuration.IConfigurationContainerAware;
import org.opendaylight.controller.connectionmanager.IConnectionManager;
+import org.opendaylight.controller.containermanager.IContainerManager;
import org.opendaylight.controller.forwardingrulesmanager.
IForwardingRulesManager;
import org.opendaylight.controller.hosttracker.IfHostListener;
list.add(IFlowProgrammerListener.class.getName());
if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
list.add(IContainerListener.class.getName());
+
+ c.add(createServiceDependency().
+ setService(IContainerManager.class).
+ setCallbacks("setContainerManager",
+ "unsetContainerManager").
+ setRequired(true));
}
// Export IVTNFlowDebugger only if "vtn.debug" system property
for (PortVlan pvlan: pvSet) {
portMaps.remove(pvlan);
}
+
+ if (vtnManagers.size() == 1) {
+ // The controller quits the container mode.
+ // Some FLOW_REMOVED notifications might be ignored when the
+ // controller entered the container mode.
+ // So we need to clean up them.
+ VTNManagerImpl mgr = vtnManagers.get(0);
+ mgr.cleanUpRemovedFlows();
+ }
}
// ICoordinatorChangeAware
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.internal;
+
+import java.util.HashSet;
+import java.util.List;
+
+import org.opendaylight.vtn.manager.internal.cluster.VTNFlow;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
+import org.opendaylight.controller.forwardingrulesmanager.
+ IForwardingRulesManager;
+
+/**
+ * {@link VTNFlowMatch} implementation which accepts VTN flows which are
+ * already removed.
+ */
+public class RemovedFlowMatch implements VTNFlowMatch {
+ /**
+ * Forwarding rules manager service.
+ */
+ private final IForwardingRulesManager fwRulesManager;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param frm Forwarding rules manager service.
+ */
+ public RemovedFlowMatch(IForwardingRulesManager frm) {
+ fwRulesManager = frm;
+ }
+
+ /**
+ * Test if the specified VTN flow should be accepted or not.
+ *
+ * @param vflow A {@link VTNFlow} instance to be tested.
+ * @return {@code true} if the specified flow is already removed.
+ * Otherwise {@code false}.
+ */
+ @Override
+ public boolean accept(VTNFlow vflow) {
+ HashSet<String> installed = new HashSet<String>();
+ String group = vflow.getGroupId().toString();
+ for (FlowEntry fent: fwRulesManager.getFlowEntriesForGroup(group)) {
+ installed.add(fent.getFlowName());
+ }
+
+ List<FlowEntry> entries = vflow.getFlowEntries();
+ if (entries.size() != installed.size()) {
+ return true;
+ }
+
+ for (FlowEntry fent: entries) {
+ if (!installed.contains(fent.getFlowName())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getDescription() {
+ return "removed";
+ }
+}
return collector.uninstall(mgr);
}
+ /**
+ * Remove all VTN flows accepted by the specified {@link VTNFlowMatch}
+ * instance.
+ *
+ * <p>
+ * Flow uninstallation will be executed in background.
+ * The caller can wait for completion of flow uninstallation by using
+ * returned {@link FlowRemoveTask} object.
+ * </p>
+ *
+ * @param mgr VTN Manager service.
+ * @param fmatch A {@link VTNFlowMatch} instance which determines VTN
+ * flows to be removed.
+ * Specifying {@code null} results in undefined behavior.
+ * @return A {@link FlowRemoveTask} object that will execute the actual
+ * work is returned. {@code null} is returned if there is no flow
+ * entry to be removed.
+ */
+ public synchronized FlowRemoveTask removeFlows(VTNManagerImpl mgr,
+ VTNFlowMatch fmatch) {
+ FlowCollector collector = new FlowCollector();
+ for (Iterator<VTNFlow> it = vtnFlows.values().iterator();
+ it.hasNext();) {
+ VTNFlow vflow = it.next();
+ if (fmatch.accept(vflow)) {
+ FlowGroupId gid = vflow.getGroupId();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("{}:{}: Remove VTN flow accepted by filter" +
+ "({}): group={}", mgr.getContainerName(),
+ tenantName, fmatch.getDescription(), gid);
+ }
+
+ // Remove this VTN flow from the database.
+ groupFlows.remove(gid.getEventId());
+ removeNodeIndex(vflow);
+ removePortIndex(vflow);
+ it.remove();
+
+ // Collect flow entries to be uninstalled.
+ collector.collect(mgr, vflow);
+ }
+ }
+
+ // Uninstall flow entries in background.
+ return collector.uninstall(mgr);
+ }
+
/**
* Create indices for the specified VTN flow.
*
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.internal;
+
+import org.opendaylight.vtn.manager.internal.cluster.VTNFlow;
+
+/**
+ * {@code VTNFlowMatch} provides interfaces to be implemented by classes which
+ * search for specific flow entries.
+ */
+public interface VTNFlowMatch {
+ /**
+ * Test if the specified VTN flow should be accepted or not.
+ *
+ * @param vflow A {@link VTNFlow} instance to be tested.
+ * @return {@code true} if the specified flow should be accepted.
+ * {@code false} if the specified flow should be filtered out.
+ */
+ boolean accept(VTNFlow vflow);
+
+ /**
+ * Return a brief description about this filter.
+ *
+ * @return A brief description about this filter.
+ */
+ String getDescription();
+}
import org.opendaylight.controller.sal.utils.NetUtils;
import org.opendaylight.controller.sal.utils.ObjectReader;
import org.opendaylight.controller.sal.utils.ObjectWriter;
-import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
import org.opendaylight.controller.switchmanager.IInventoryListener;
*/
private IConnectionManager connectionManager;
+ /**
+ * Container manager service instance.
+ *
+ * <p>
+ * Note that {@code null} is set unless this instance is associated with
+ * the default container.
+ * </p>
+ */
+ private IContainerManager containerManager;
+
/**
* Host listeners.
*/
String root = GlobalConstants.STARTUPHOME.toString();
vtnConfig = new VTNConfig(root, cname);
- if (cname.equals(GlobalConstants.DEFAULT.toString())) {
- IContainerManager ctMgr = (IContainerManager)ServiceHelper.
- getGlobalInstance(IContainerManager.class, this);
- inContainerMode =
- (ctMgr != null && ctMgr.hasNonDefaultContainer());
+ if (containerManager != null) {
+ assert containerName.equals(GlobalConstants.DEFAULT.toString());
+ inContainerMode = containerManager.inContainerMode();
} else {
inContainerMode = false;
}
return connectionManager;
}
+ /**
+ * Invoked when a container manager service is registered.
+ *
+ * @param service Container manager service.
+ */
+ void setContainerManager(IContainerManager service) {
+ LOG.trace("{}: Set container manager service: {}", containerName,
+ service);
+ containerManager = service;
+ }
+
+ /**
+ * Invoked when a container manager service is unregistered.
+ *
+ * @param service Container manager service.
+ */
+ void unsetContainerManager(IContainerManager service) {
+ if (containerManager == service) {
+ LOG.trace("{}: Unset container manager service: {}",
+ containerName, service);
+ containerManager = null;
+ }
+ }
+
+ /**
+ * Return container manager service instance.
+ *
+ * @return Container manager service.
+ * Note that {@code null} is always returned unless this instance
+ * is associated with the default container.
+ */
+ public IContainerManager getContainerManager() {
+ return containerManager;
+ }
+
/**
* Invoked when a host listener is registered.
*
}
}
+ /**
+ * Collect inactive flows and remove them in background.
+ */
+ public void cleanUpRemovedFlows() {
+ if (clusterService.amICoordinator()) {
+ RemovedFlowMatch fmatch = new RemovedFlowMatch(fwRuleManager);
+ for (VTNFlowDatabase fdb: vtnFlowMap.values()) {
+ fdb.removeFlows(this, fmatch);
+ }
+ }
+ }
+
/**
* Determine whether the given node connector is associated with the
* physical switch port at the edge of the SDN network.
}
} else if (arpHandler == null) {
// Inactivate VTN, and start ARP handler emulator.
- for (VTNFlowDatabase fdb: vtnFlowMap.values()) {
- VTNThreadData.removeFlows(this, fdb);
- }
arpHandler = new ArpHandler(this);
if (sync) {
notifyListeners(false);
*/
@Override
public void flowRemoved(Node node, Flow flow) {
+ if (containerManager != null && containerManager.inContainerMode()) {
+ // The given flow was removed by forwarding rule manager, and it
+ // will be restored when the controller exits the container mode.
+ // Note that we can not use inContainerMode variable here because
+ // containerModeUpdated() handler for FRM may be called before
+ // the VTN Manager. Although this code may miss FLOW_REMOVED
+ // notifications actually sent by OF switch, they will be fixed
+ // when the controller quits the container mode.
+ assert containerName.equals(GlobalConstants.DEFAULT.toString());
+ LOG.trace("{}: Ignore FLOW_REMOVED during container mode: " +
+ "node={}, flow={}", containerName, node, flow);
+ return;
+ }
+
LOG.trace("{}: flowRemoved() called: node={}, flow={}",
containerName, node, flow);
vtnMgr.setHostTracker(stubObj);
vtnMgr.setForwardingRuleManager(stubObj);
vtnMgr.setConnectionManager(cm);
+ vtnMgr.setContainerManager(stubObj);
startVTNManager(c);
}
import org.opendaylight.controller.clustering.services.IClusterServices.cacheMode;
import org.opendaylight.controller.connectionmanager.ConnectionMgmtScheme;
import org.opendaylight.controller.connectionmanager.IConnectionManager;
+import org.opendaylight.controller.containermanager.ContainerConfig;
+import org.opendaylight.controller.containermanager.ContainerFlowConfig;
+import org.opendaylight.controller.containermanager.IContainerManager;
import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.packet.RawPacket;
import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.NetUtils;
import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
import org.opendaylight.controller.sal.utils.NodeCreator;
* (other is not implemented yet.)
* </p>
*/
-public class TestStub implements IClusterGlobalServices, IClusterContainerServices,
- ISwitchManager, ITopologyManager, IDataPacketService, IRouting,
- IForwardingRulesManager, IfIptoHost, IConnectionManager {
-
+public class TestStub
+ implements IClusterGlobalServices, IClusterContainerServices,
+ ISwitchManager, ITopologyManager, IDataPacketService, IRouting,
+ IForwardingRulesManager, IfIptoHost, IConnectionManager,
+ IContainerManager {
/**
* Active cluster cache transactions per thread.
*/
return null;
}
+ // IContainerManager
+
+ @Override
+ public Status addContainer(ContainerConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeContainer(ContainerConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeContainer(String containerName) {
+ return null;
+ }
+
+ @Override
+ public Status addContainerEntry(String containerName,
+ List<String> portList) {
+ return null;
+ }
+
+ @Override
+ public Status removeContainerEntry(String containerName,
+ List<String> portList) {
+ return null;
+ }
+
+ @Override
+ public Status addContainerFlows(String containerName,
+ List<ContainerFlowConfig> configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeContainerFlows(String containerName,
+ List<ContainerFlowConfig> configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeContainerFlows(String containerName, Set<String> name) {
+ return null;
+ }
+
+ @Override
+ public List<ContainerConfig> getContainerConfigList() {
+ return null;
+ }
+
+ @Override
+ public ContainerConfig getContainerConfig(String containerName) {
+ return null;
+ }
+
+ @Override
+ public List<String> getContainerNameList() {
+ return null;
+ }
+
+ @Override
+ public boolean doesContainerExist(String ContainerId) {
+ return GlobalConstants.DEFAULT.toString().equals(ContainerId);
+ }
+
+ @Override
+ public Map<String, List<ContainerFlowConfig>> getContainerFlows() {
+ return null;
+ }
+
+ @Override
+ public List<ContainerFlowConfig> getContainerFlows(String containerName) {
+ return null;
+ }
+
+ @Override
+ public List<String> getContainerFlowNameList(String containerName) {
+ return null;
+ }
+
+ @Override
+ public boolean hasNonDefaultContainer() {
+ return false;
+ }
+
+ @Override
+ public List<String> getContainerNames() {
+ return null;
+ }
+
+ @Override
+ public boolean inContainerMode() {
+ return false;
+ }
+
// additional method for control stub
public void addEdge(Edge edge) {
Map<Node, List<Edge>> map = nodeEdges.get(edge.getTailNodeConnector().getNode());
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.Dictionary;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Hashtable;
import org.opendaylight.controller.clustering.services.CacheExistException;
import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.containermanager.IContainerManager;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
import org.opendaylight.controller.hosttracker.IfHostListener;
import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
vtnMgr.setHostTracker(stubObj);
vtnMgr.setForwardingRuleManager(stubObj);
vtnMgr.setConnectionManager(stubObj);
+ vtnMgr.setContainerManager(stubObj);
startVTNManager(c);
}
* startup VTNManager.
*/
protected void startVTNManager(ComponentImpl c) {
+ Dictionary<?, ?> props = c.getServiceProperties();
+ if (props != null) {
+ String name = (String)props.get("containerName");
+ IContainerManager ctmgr = vtnMgr.getContainerManager();
+ if (GlobalConstants.DEFAULT.toString().equals(name)) {
+ if (ctmgr == null) {
+ vtnMgr.setContainerManager(stubObj);
+ }
+ } else if (ctmgr != null) {
+ vtnMgr.unsetContainerManager(ctmgr);
+ }
+ }
vtnMgr.init(c);
vtnMgr.clearDisabledNode();
}
vtnMgr.setHostTracker(stub);
vtnMgr.setForwardingRuleManager(stub);
vtnMgr.setConnectionManager(stub);
+ vtnMgr.setContainerManager(stub);
startVTNManager(c);
}
vtnMgr.setHostTracker(stubObj);
vtnMgr.setForwardingRuleManager(stubObj);
vtnMgr.setConnectionManager(stubObj);
+ vtnMgr.setContainerManager(stubObj);
startVTNManager(c);
}
vtnMgr.setHostTracker(stubObj);
vtnMgr.setForwardingRuleManager(stubObj);
vtnMgr.setConnectionManager(stubObj);
+ vtnMgr.setContainerManager(stubObj);
startVTNManager(c);
}
vtnMgr.setHostTracker(stubObj);
vtnMgr.setForwardingRuleManager(stubObj);
vtnMgr.setConnectionManager(stubObj);
+ vtnMgr.setContainerManager(stubObj);
vtnMgr.init(c);
vtnMgr.clearDisabledNode();
}
import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.connectionmanager.IConnectionManager;
+import org.opendaylight.controller.containermanager.IContainerManager;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
import org.opendaylight.controller.hosttracker.IfHostListener;
assertSame(org, mgr.getConnectionManager());
}
+ /**
+ * Test method for
+ * {@link VTNManagerImpl#setContainerManager(IContainerManager)},
+ * {@link VTNManagerImpl#unsetContainerManager(IContainerManager)},
+ * {@link VTNManagerImpl#getContainerManager()}
+ * .
+ */
+ @Test
+ public void testSetUnsetContainerManager() {
+ VTNManagerImpl mgr = vtnMgr;
+ IContainerManager org = mgr.getContainerManager();
+ TestStub stub = new TestStub();
+ TestStub stub2 = new TestStub();
+
+ mgr.setContainerManager(stub);
+ assertSame(stub, mgr.getContainerManager());
+
+ mgr.unsetContainerManager(stub2);
+ assertSame(stub, mgr.getContainerManager());
+
+ mgr.unsetContainerManager(stub);
+ assertNull(mgr.getContainerManager());
+
+ mgr.setContainerManager(org);
+ assertSame(org, mgr.getContainerManager());
+ }
+
/**
* Test method for
* {@link VTNManagerImpl#setResourceManager(IVTNResourceManager)},