Initial Match Action Module implementation
This patch set implements the Match Action framework that
Brian and I have been working on. Still a work in progress,
not all implementations complete, and not all javadocs and
tests in place.
Unit tests are currently not working, so they are commented out.
Change-Id: I61d79555c6bbb2d5437b2433613ab47ab8cea4f6
diff --git a/src/main/java/net/onrc/onos/core/matchaction/MatchActionComponent.java b/src/main/java/net/onrc/onos/core/matchaction/MatchActionComponent.java
new file mode 100644
index 0000000..362038f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/matchaction/MatchActionComponent.java
@@ -0,0 +1,469 @@
+package net.onrc.onos.core.matchaction;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFMessageFuture;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.api.flowmanager.ConflictDetectionPolicy;
+import net.onrc.onos.core.datagrid.IDatagridService;
+import net.onrc.onos.core.datagrid.IEventChannel;
+import net.onrc.onos.core.datagrid.IEventChannelListener;
+import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
+import net.onrc.onos.core.intent.FlowEntry;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.IdGenerator;
+import net.onrc.onos.core.util.SwitchPort;
+import org.apache.commons.lang3.tuple.Pair;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+
+/**
+ * Manages Match-Action entries.
+ * <p>
+ * TODO: Make all methods thread-safe
+ */
+public class MatchActionComponent implements MatchActionService, IFloodlightService {
+
+ private static final Logger log = LoggerFactory.getLogger(MatchActionService.class);
+ IFlowPusherService pusher;
+ IFloodlightProviderService provider;
+
+ private ConcurrentMap<MatchActionId, MatchAction> matchActionMap = new ConcurrentHashMap<>();
+ private ConcurrentMap<MatchActionOperationsId, MatchActionOperations> matchSetMap =
+ new ConcurrentHashMap<>();
+ // TODO - want something better here for the resolved Queue
+ private BlockingQueue<MatchActionOperationsId> resolvedQueue = new ArrayBlockingQueue<>(100);
+ private BlockingQueue<MatchActionOperations> installationWorkQueue = new ArrayBlockingQueue<>(100);
+
+ private IEventChannel<String, MatchActionOperations> installSetChannel;
+ private IEventChannel<String, SwitchResultList> installSetReplyChannel;
+
+ // Convenience declarations to hide the name space collision on the Operator type
+ private static final net.onrc.onos.core.intent.IntentOperation.Operator INTENT_ADD_OP =
+ net.onrc.onos.core.intent.IntentOperation.Operator.ADD;
+ private static final net.onrc.onos.core.intent.IntentOperation.Operator INTENT_REMOVE_OP =
+ net.onrc.onos.core.intent.IntentOperation.Operator.REMOVE;
+
+ // TODO Single instance for now, should be a work queue of some sort eventually
+ private Thread coordinator;
+ private Thread installer;
+ private final IDatagridService datagrid;
+
+ public MatchActionComponent(final IDatagridService newDatagrid,
+ final IFlowPusherService newPusher,
+ final IFloodlightProviderService newProvider) {
+ datagrid = newDatagrid;
+ pusher = newPusher;
+ provider = newProvider;
+ }
+
+ public void start() {
+ installSetChannel = datagrid.createChannel("onos.matchaction.installSetChannel",
+ String.class,
+ MatchActionOperations.class);
+
+ installSetReplyChannel = datagrid.createChannel("onos.matchaction.installSetReplyChannel",
+ String.class,
+ SwitchResultList.class);
+
+ coordinator = new Coordinator();
+ coordinator.start();
+
+ installer = new InstallerWorker();
+ installer.start();
+ }
+
+ public MatchActionOperationsId installMatchActionOperations(MatchActionOperations matchSet) {
+ if (checkResolved(matchSet)) {
+ matchSet.setState(MatchActionOperationsState.RESOLVED);
+ } else {
+ matchSet.setState(MatchActionOperationsState.INIT);
+ }
+ matchSetMap.put(matchSet.getOperationsId(), matchSet);
+ if (matchSet.getState() == MatchActionOperationsState.RESOLVED) {
+ resolvedQueue.add(matchSet.getOperationsId());
+ }
+ return matchSet.getOperationsId();
+ }
+
+ public MatchActionOperationsState getMatchActionOperationsState(MatchActionOperationsId matchSetId) {
+ MatchActionOperations set = matchSetMap.get(matchSetId);
+ return (set == null) ? null : set.getState();
+ }
+
+ protected boolean checkResolved(MatchActionOperations matchSet) {
+ boolean resolved = true;
+ for (MatchActionOperationsId setId : matchSet.getDependencies()) {
+ MatchActionOperations set = matchSetMap.get(setId);
+ if (set == null || set.getState() != MatchActionOperationsState.RESOLVED) {
+ resolved = false;
+ break;
+ }
+ }
+ return resolved;
+ }
+
+ // TODO need operation too...
+ protected List<MatchAction> getMatchActions(final MatchActionOperations matchSet) {
+
+ final List<MatchAction> result = new ArrayList<>();
+ for (MatchActionOperationEntry op : matchSet.getOperations()) {
+ final MatchAction match = op.getTarget();
+
+ switch(op.getOperator()) {
+ case ADD:
+ matchActionMap.put(match.getId(), match);
+ break;
+
+ case REMOVE:
+ default:
+ throw new UnsupportedOperationException(
+ "Unsupported MatchAction operation" +
+ op.getOperator().toString());
+ }
+ result.add(match);
+ }
+ return result;
+ }
+
+ class Coordinator extends Thread
+ implements IEventChannelListener<String, SwitchResultList> {
+
+ private Map<MatchActionOperationsId, Map<Dpid, SwitchResult>> pendingMatchActionOperationss = new HashMap<>();
+
+ protected Coordinator() {
+ installSetReplyChannel.addListener(this);
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ // 1. Remove MatchActionOperations(s) from the Global Resolved Queue
+ try {
+ MatchActionOperationsId setId = resolvedQueue.take();
+ processSet(setId);
+ } catch (InterruptedException e) {
+ log.warn("Error taking from resolved queue: {}", e.getMessage());
+ }
+ }
+ }
+
+ private void processSet(MatchActionOperationsId setId) {
+ MatchActionOperations matchSet = matchSetMap.get(setId);
+ matchSet.setState(MatchActionOperationsState.PENDING);
+ matchSetMap.put(setId, matchSet);
+
+ // TODO apply updates to in-memory flow table and resolve conflicts
+ // TODO generate apply and undo sets, using MatchActionOperations for now...
+
+ // build pending switches set for coordinator tracking
+ Map<Dpid, SwitchResult> switches = new HashMap<>();
+ for (MatchAction match : getMatchActions(matchSet)) {
+ SwitchPort sw = match.getSwitchPort();
+ switches.put(sw.getDpid(), new SwitchResult(setId, sw.getDpid()));
+ }
+ pendingMatchActionOperationss.put(setId, switches);
+
+ // distribute apply/undo sets to cluster
+ //installSetChannel.addTransientEntry(setId.toString(), matchSet);
+ }
+
+ @Override
+ public void entryAdded(SwitchResultList value) {
+ updateSwitchResults(value);
+ }
+
+ @Override
+ public void entryRemoved(SwitchResultList value) {
+ // noop
+ }
+
+ @Override
+ public void entryUpdated(SwitchResultList value) {
+ updateSwitchResults(value);
+ }
+
+ private void updateSwitchResults(SwitchResultList results) {
+ if (results == null || results.size() == 0) {
+ return;
+ }
+ MatchActionOperationsId matchSetId = results.get(0).getMatchActionOperationsId();
+
+ // apply updates from results list
+ Map<Dpid, SwitchResult> resultMap = pendingMatchActionOperationss.get(matchSetId);
+ for (SwitchResult result : results) {
+ SwitchResult resultToUpdate = resultMap.get(result.getSwitch());
+ if (resultToUpdate != null) {
+ resultToUpdate.setStatus(result.getStatus());
+ }
+ // else {
+ // TODO error!
+ // }
+ }
+
+ // check to see the overall outcome of the install operation
+ SwitchResult.Status setResult = SwitchResult.Status.SUCCESS;
+ for (SwitchResult result : resultMap.values()) {
+ if (result.getStatus().equals(SwitchResult.Status.FAILURE)) {
+ setResult = SwitchResult.Status.FAILURE;
+ // if any switch fails, we fail the installation
+ break;
+ } else if (!setResult.equals(SwitchResult.Status.FAILURE)
+ && result.getStatus().equals(SwitchResult.Status.UNKNOWN)) {
+ setResult = SwitchResult.Status.UNKNOWN;
+ }
+ }
+ switch (setResult) {
+ case SUCCESS:
+ // mark MatchActionOperations as INSTALLED
+ MatchActionOperations matchSet = matchSetMap.get(matchSetId);
+ matchSet.setState(MatchActionOperationsState.INSTALLED);
+ matchSetMap.replace(matchSetId, matchSet);
+ pendingMatchActionOperationss.remove(matchSetId);
+
+ // TODO update dependent sets as needed
+ break;
+ case FAILURE:
+ // mark MatchActionOperations as FAILED
+ matchSet = matchSetMap.get(matchSetId);
+ matchSet.setState(MatchActionOperationsState.FAILED);
+ matchSetMap.replace(matchSetId, matchSet);
+
+ // TODO instruct installers to install Undo set
+ break;
+ case UNKNOWN:
+ default:
+ // noop, still waiting for results
+ // TODO: check to see if installers are dead after timeout
+ }
+ }
+ }
+
+
+ class InstallerWorker extends Thread {
+
+ // Note: we should consider using an alternative representation for
+ // apply sets
+ protected void install(MatchActionOperations matchSet) {
+ Map<Long, IOFSwitch> switches = provider.getSwitches();
+
+ Set<Pair<Dpid, FlowEntry>> entries = new HashSet<>();
+ Set<IOFSwitch> modifiedSwitches = new HashSet<>();
+
+ // convert flow entries and create pairs
+ for (MatchAction entry : getMatchActions(matchSet)) {
+ Dpid swDpid = entry.getSwitchPort().getDpid();
+ IOFSwitch sw = switches.get(swDpid.value());
+ if (sw == null) {
+ // no active switch, skip this flow entry
+ log.debug("Skipping flow entry: {}", entry);
+ continue;
+ }
+ final List<FlowEntry> flowEntries = getFlowEntry(entry);
+ for (final FlowEntry flowEntry : flowEntries) {
+ entries.add(Pair.of(swDpid, flowEntry));
+ }
+ modifiedSwitches.add(sw);
+ }
+
+ // push flow entries to switches
+ pusher.pushFlowEntries(entries);
+
+ // insert a barrier after each phase on each modifiedSwitch
+ // wait for confirmation messages before proceeding
+ List<Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>>> barriers = new ArrayList<>();
+ for (IOFSwitch sw : modifiedSwitches) {
+ barriers.add(Pair.of(sw, pusher.barrierAsync(new Dpid(sw.getId()))));
+ }
+ List<SwitchResult> switchResults = new ArrayList<>();
+ for (Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>> pair : barriers) {
+ IOFSwitch sw = pair.getLeft();
+ OFMessageFuture<OFBarrierReply> future = pair.getRight();
+ SwitchResult switchResult = new SwitchResult(matchSet.getOperationsId(), new Dpid(
+ sw.getId()));
+ try {
+ future.get();
+ switchResult.setStatus(SwitchResult.Status.SUCCESS);
+ } catch (InterruptedException | ExecutionException e) {
+ log.error("Barrier message not received for sw: {}", sw);
+ switchResult.setStatus(SwitchResult.Status.FAILURE);
+ }
+ switchResults.add(switchResult);
+ }
+
+ // send update message to coordinator
+ // TODO: we might want to use another ID here, i.e. GUID, to avoid
+ // overlap
+ final SwitchResultList switchResultList = new SwitchResultList();
+ switchResultList.addAll(switchResults);
+ installSetReplyChannel.addTransientEntry(matchSet.getOperationsId().toString(),
+ switchResultList);
+ }
+
+ // TODO this should be removed when FlowPusher supports MatchAction
+ private List<FlowEntry> getFlowEntry(MatchAction matchAction) {
+ final Match match = matchAction.getMatch();
+ // Currently we only support Packet based matching
+ checkArgument(match instanceof PacketMatch);
+
+ final PacketMatch packetMatch = (PacketMatch) match;
+ final SwitchPort srcPort = matchAction.getSwitchPort();
+
+ final long switchId = srcPort.getDpid().value();
+ final long srcPortNumber = srcPort.getPortNumber().value();
+ final int srcIp = packetMatch.getSrcIpAddress().address().value();
+ final MACAddress srcMacAddress = packetMatch.getSrcMacAddress();
+ final int dstIp = packetMatch.getDstIpAddress().address().value();
+ final MACAddress dstMacAddress = packetMatch.getDstMacAddress();
+
+ final List<FlowEntry> result = new ArrayList<>();
+
+ for (final Action action : matchAction.getActions()) {
+ if (action instanceof OutputAction) {
+ final OutputAction outputAction = (OutputAction) action;
+ final long dstPortNumber =
+ outputAction.getPortNumber().value();
+
+
+ final FlowEntry entry = new FlowEntry(
+ switchId,
+ srcPortNumber,
+ dstPortNumber,
+ srcMacAddress,
+ dstMacAddress,
+ srcIp,
+ dstIp,
+ INTENT_ADD_OP
+ );
+ result.add(entry);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ // 1. Remove MatchActionOperations(s) from the Global Resolved Queue
+ try {
+ MatchActionOperations operations = installationWorkQueue.take();
+ install(operations);
+ } catch (InterruptedException e) {
+ log.warn("Error taking from installation queue: {}", e.getMessage());
+ }
+ }
+ }
+ }
+
+ class Installer
+ implements IEventChannelListener<String, MatchActionOperations> {
+
+ protected Installer() {
+ installSetChannel.addListener(this);
+ }
+
+
+ @Override
+ public void entryAdded(MatchActionOperations value) {
+ installationWorkQueue.add(value);
+ }
+
+ @Override
+ public void entryRemoved(MatchActionOperations value) {
+ // noop
+ }
+
+ @Override
+ public void entryUpdated(MatchActionOperations value) {
+ installationWorkQueue.add(value);
+ }
+ }
+
+ private final HashSet<MatchAction> currentOperations = new HashSet<>();
+
+ private boolean processMatchActionEntries(
+ final List<MatchActionOperationEntry> entries) {
+ int successfulOperations = 0;
+ for (final MatchActionOperationEntry entry : entries) {
+ if (currentOperations.add(entry.getTarget())) {
+ successfulOperations++;
+ }
+ }
+ return entries.size() == successfulOperations;
+ }
+
+ @Override
+ public boolean addMatchAction(MatchAction matchAction) {
+ return false;
+ }
+
+ @Override
+ public Set<MatchAction> getMatchActions() {
+ return Collections.unmodifiableSet(currentOperations);
+ }
+
+ @Override
+ public boolean executeOperations(final MatchActionOperations operations) {
+ installMatchActionOperations(operations);
+ return processMatchActionEntries(operations.getOperations());
+ }
+
+ @Override
+ public void setConflictDetectionPolicy(ConflictDetectionPolicy policy) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public ConflictDetectionPolicy getConflictDetectionPolicy() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void addEventListener(EventListener listener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void removeEventListener(EventListener listener) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public IdGenerator<MatchActionId> getMatchActionIdGenerator() {
+ return null;
+ }
+
+ @Override
+ public IdGenerator<MatchActionOperationsId> getMatchActionOperationsIdGenerator() {
+ return null;
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/matchaction/MatchActionModule.java b/src/main/java/net/onrc/onos/core/matchaction/MatchActionModule.java
index 6ae5d5e..eaf7a39 100644
--- a/src/main/java/net/onrc/onos/core/matchaction/MatchActionModule.java
+++ b/src/main/java/net/onrc/onos/core/matchaction/MatchActionModule.java
@@ -1,58 +1,104 @@
package net.onrc.onos.core.matchaction;
-import java.util.Collections;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+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.onrc.onos.api.flowmanager.ConflictDetectionPolicy;
+import net.onrc.onos.core.datagrid.IDatagridService;
+import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
+import net.onrc.onos.core.util.IdGenerator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.EventListener;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import net.onrc.onos.api.flowmanager.ConflictDetectionPolicy;
-import net.onrc.onos.core.util.IdGenerator;
-
/**
- * Manages Match-Action entries.
- * <p>
- * TODO: Make all methods thread-safe
+ * Floodlight module for Match Action service.
*/
-public class MatchActionModule implements MatchActionFloodlightService {
+
+public class MatchActionModule implements MatchActionFloodlightService, IFloodlightModule {
private final HashSet<MatchAction> currentOperations = new HashSet<>();
+ private static final Logger log = LoggerFactory
+ .getLogger(MatchActionModule.class);
+ private MatchActionComponent matchActionComponent;
- private boolean processMatchActionEntries(
- final List<MatchActionOperationEntry> entries) {
- int successfulOperations = 0;
- for (final MatchActionOperationEntry entry : entries) {
- if (currentOperations.add(entry.getTarget())) {
- successfulOperations++;
- }
- }
- return entries.size() == successfulOperations;
+
+
+
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+ List<Class<? extends IFloodlightService>> services = new ArrayList<>();
+ log.info("get module services");
+ services.add(MatchActionFloodlightService.class);
+ return services;
+ }
+
+ @Override
+ public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+ Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
+ new HashMap<>();
+ impls.put(MatchActionFloodlightService.class, this);
+ return impls;
+ }
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+ List<Class<? extends IFloodlightService>> dependencies = new ArrayList<>();
+ dependencies.add(IDatagridService.class);
+ dependencies.add(IFlowPusherService.class);
+ dependencies.add(IFloodlightProviderService.class);
+ return dependencies;
+ }
+
+ @Override
+ public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+
+ }
+
+ @Override
+ public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
+ final IDatagridService datagrid = context.getServiceImpl(IDatagridService.class);
+ final IFlowPusherService pusher = context.getServiceImpl(IFlowPusherService.class);
+ final IFloodlightProviderService provider = context.getServiceImpl(IFloodlightProviderService.class);
+
+ matchActionComponent = new MatchActionComponent(datagrid, pusher, provider);
+ log.info("match action component created");
+ matchActionComponent.start();
}
@Override
public boolean addMatchAction(MatchAction matchAction) {
- return false;
+ return matchActionComponent.addMatchAction(matchAction);
}
@Override
public Set<MatchAction> getMatchActions() {
- return Collections.unmodifiableSet(currentOperations);
+ return null;
}
@Override
- public boolean executeOperations(final MatchActionOperations operations) {
- return processMatchActionEntries(operations.getOperations());
+ public boolean executeOperations(MatchActionOperations operations) {
+ return false;
}
@Override
public void setConflictDetectionPolicy(ConflictDetectionPolicy policy) {
- // TODO Auto-generated method stub
}
@Override
public ConflictDetectionPolicy getConflictDetectionPolicy() {
- // TODO Auto-generated method stub
return null;
}
@@ -72,13 +118,11 @@
@Override
public void addEventListener(EventListener listener) {
- // TODO Auto-generated method stub
}
@Override
public void removeEventListener(EventListener listener) {
- // TODO Auto-generated method stub
}
}
diff --git a/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperations.java b/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperations.java
index c865203..e87fcda 100644
--- a/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperations.java
+++ b/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperations.java
@@ -2,18 +2,22 @@
import net.onrc.onos.api.batchoperation.BatchOperation;
+import java.util.HashSet;
+import java.util.Set;
+
import static com.google.common.base.Preconditions.checkNotNull;
/**
* The MatchActionOperations class holds a list of MatchActionOperationEntry
* objects to be executed together as one set.
- * <p/>
- * Objects of this class are immutable.
*/
-public final class MatchActionOperations
+public class MatchActionOperations
extends BatchOperation<MatchActionOperationEntry> {
private final MatchActionOperationsId id;
+ private MatchActionOperationsState state;
+ private final Set<MatchActionOperationsId> dependencies;
+
/**
* The MatchAction operators.
*/
@@ -30,6 +34,8 @@
*/
public MatchActionOperations(final MatchActionOperationsId newId) {
id = checkNotNull(newId);
+ state = MatchActionOperationsState.INIT;
+ dependencies = new HashSet<>();
}
/**
@@ -41,6 +47,38 @@
return id;
}
+ /**
+ * Gets the state of the Match Action Operations.
+ *
+ * @return state of the operations
+ */
+ public MatchActionOperationsState getState() {
+ return state;
+ }
+
+ /**
+ * Sets the state of the Match Action Operations.
+ *
+ * @param newState new state of the operations
+ */
+ public void setState(final MatchActionOperationsState newState) {
+ state = newState;
+ }
+
+ /**
+ * Gets the set of IDs of operations that are dependent on this
+ * operation.
+ *
+ * @return set of operations IDs of dependent operations
+ */
+ public Set<MatchActionOperationsId> getDependencies() {
+ return dependencies;
+ }
+
+ public void addDependency(MatchActionOperationsId dependentOperationId) {
+ dependencies.add(dependentOperationId);
+ }
+
@Override
public int hashCode() {
return id.hashCode();
diff --git a/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperationsState.java b/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperationsState.java
index 4239027..4ccf668 100644
--- a/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperationsState.java
+++ b/src/main/java/net/onrc/onos/core/matchaction/MatchActionOperationsState.java
@@ -1,5 +1,11 @@
package net.onrc.onos.core.matchaction;
-public interface MatchActionOperationsState {
- // TODO waiting on MatchActionOperations
+
+public enum MatchActionOperationsState {
+ INIT,
+ RESOLVED,
+ PENDING,
+ INSTALLED,
+ FAILED
}
+
diff --git a/src/main/java/net/onrc/onos/core/matchaction/MatchActionService.java b/src/main/java/net/onrc/onos/core/matchaction/MatchActionService.java
index fa6b34f..ce5a60c 100644
--- a/src/main/java/net/onrc/onos/core/matchaction/MatchActionService.java
+++ b/src/main/java/net/onrc/onos/core/matchaction/MatchActionService.java
@@ -1,11 +1,11 @@
package net.onrc.onos.core.matchaction;
-import java.util.EventListener;
-import java.util.Set;
-
import net.onrc.onos.api.flowmanager.ConflictDetectionPolicy;
import net.onrc.onos.core.util.IdGenerator;
+import java.util.EventListener;
+import java.util.Set;
+
/**
* An interface for the match-action service.
*/
diff --git a/src/main/java/net/onrc/onos/core/matchaction/SwitchResult.java b/src/main/java/net/onrc/onos/core/matchaction/SwitchResult.java
new file mode 100644
index 0000000..6faaa0d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/matchaction/SwitchResult.java
@@ -0,0 +1,37 @@
+package net.onrc.onos.core.matchaction;
+
+import net.onrc.onos.core.util.Dpid;
+
+public class SwitchResult {
+ private Dpid sw;
+ private Status status;
+ private MatchActionOperationsId matchSetId;
+
+ protected enum Status {
+ SUCCESS,
+ FAILURE,
+ UNKNOWN
+ }
+
+ protected SwitchResult(MatchActionOperationsId match, Dpid sw) {
+ this.sw = sw;
+ this.status = Status.UNKNOWN;
+ this.matchSetId = match;
+ }
+
+ protected void setStatus(Status newStatus) {
+ this.status = newStatus;
+ }
+
+ protected Status getStatus() {
+ return this.status;
+ }
+
+ protected MatchActionOperationsId getMatchActionOperationsId() {
+ return this.matchSetId;
+ }
+
+ protected Dpid getSwitch() {
+ return this.sw;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/matchaction/SwitchResultList.java b/src/main/java/net/onrc/onos/core/matchaction/SwitchResultList.java
new file mode 100644
index 0000000..2523556
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/matchaction/SwitchResultList.java
@@ -0,0 +1,21 @@
+package net.onrc.onos.core.matchaction;
+import java.util.LinkedList;
+
+/**
+ * This class wraps a list of SwitchResults. It is required to be able to pass
+ * SwitchResults via a Hazelcast channel.
+ */
+public class SwitchResultList extends LinkedList<SwitchResult> {
+
+ static final long serialVersionUID = -4966789015808022563L;
+
+ /**
+ * Add a switch result to the list.
+ *
+ * @param result switch result to add to the list
+ * @return true
+ */
+ public boolean add(SwitchResult result) {
+ return super.add(result);
+ }
+}