Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/FlowsListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/FlowsListCommand.java
new file mode 100644
index 0000000..07d15e2
--- /dev/null
+++ b/cli/src/main/java/org/onlab/onos/cli/net/FlowsListCommand.java
@@ -0,0 +1,78 @@
+package org.onlab.onos.cli.net;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.onos.cli.AbstractShellCommand;
+import org.onlab.onos.net.Device;
+import org.onlab.onos.net.device.DeviceService;
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.FlowRuleService;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Lists all currently-known hosts.
+ */
+@Command(scope = "onos", name = "flows",
+description = "Lists all currently-known flows.")
+public class FlowsListCommand extends AbstractShellCommand {
+
+ private static final String FMT =
+ " id=%s, selector=%s, treatment=%s, state=%s";
+
+ protected static final Comparator<FlowRule> ID_COMPARATOR = new Comparator<FlowRule>() {
+ @Override
+ public int compare(FlowRule f1, FlowRule f2) {
+ return Long.valueOf(f1.id().value()).compareTo(f2.id().value());
+ }
+ };
+
+ @Override
+ protected Object doExecute() throws Exception {
+ DeviceService deviceService = getService(DeviceService.class);
+ FlowRuleService service = getService(FlowRuleService.class);
+ Map<Device, List<FlowRule>> flows = getSortedFlows(deviceService, service);
+ for (Device d : deviceService.getDevices()) {
+ printFlows(d, flows.get(d));
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns the list of devices sorted using the device ID URIs.
+ *
+ * @param service device service
+ * @return sorted device list
+ */
+ protected Map<Device, List<FlowRule>> getSortedFlows(DeviceService deviceService, FlowRuleService service) {
+ Map<Device, List<FlowRule>> flows = Maps.newHashMap();
+ List<FlowRule> rules;
+ for (Device d : deviceService.getDevices()) {
+ rules = newArrayList(service.getFlowEntries(d.id()));
+ Collections.sort(rules, ID_COMPARATOR);
+ flows.put(d, rules);
+ }
+ return flows;
+ }
+
+ /**
+ * Prints flows.
+ * @param d the device
+ * @param flows the set of flows for that device.
+ */
+ protected void printFlows(Device d, List<FlowRule> flows) {
+ print("Device: " + d.id());
+ for (FlowRule f : flows) {
+ print(FMT, f.id().value(), f.selector(), f.treatment(), f.state());
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 4494709..9d8259e 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -2,6 +2,9 @@
<command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
<command>
+ <action class="org.onlab.onos.cli.net.FlowsListCommand"/>
+ </command>
+ <command>
<action class="org.onlab.onos.cli.net.DevicesListCommand"/>
</command>
<command>
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
index fae1fe3..de59896 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
@@ -1,53 +1,83 @@
package org.onlab.onos.net.flow;
import static com.google.common.base.MoreObjects.toStringHelper;
+import static org.slf4j.LoggerFactory.getLogger;
import java.util.Objects;
import org.onlab.onos.net.DeviceId;
+import org.slf4j.Logger;
public class DefaultFlowRule implements FlowRule {
+ private final Logger log = getLogger(getClass());
+
private final DeviceId deviceId;
private final int priority;
private final TrafficSelector selector;
private final TrafficTreatment treatment;
- private final FlowId id;
private final long created;
private final long life;
- private final long idle;
private final long packets;
private final long bytes;
+ private final FlowRuleState state;
+ private final FlowId id;
- public DefaultFlowRule(DeviceId deviceId,
- TrafficSelector selector, TrafficTreatment treatment, int priority) {
+ public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
+ TrafficTreatment treatment, int priority, FlowRuleState state,
+ long life, long packets, long bytes, long flowId) {
this.deviceId = deviceId;
this.priority = priority;
this.selector = selector;
this.treatment = treatment;
+ this.state = state;
+
+ this.id = FlowId.valueOf(flowId);
+
+ this.life = life;
+ this.packets = packets;
+ this.bytes = bytes;
+ this.created = System.currentTimeMillis();
+ }
+
+ public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
+ TrafficTreatment treatement, int priority) {
+ this(deviceId, selector, treatement, priority, FlowRuleState.CREATED);
+ }
+
+ public DefaultFlowRule(FlowRule rule, FlowRuleState state) {
+ this(rule.deviceId(), rule.selector(), rule.treatment(),
+ rule.priority(), state, rule.id());
+ }
+
+ private DefaultFlowRule(DeviceId deviceId,
+ TrafficSelector selector, TrafficTreatment treatment,
+ int priority, FlowRuleState state) {
+ this.deviceId = deviceId;
+ this.priority = priority;
+ this.selector = selector;
+ this.treatment = treatment;
+ this.state = state;
this.life = 0;
- this.idle = 0;
this.packets = 0;
this.bytes = 0;
this.id = FlowId.valueOf(this.hashCode());
this.created = System.currentTimeMillis();
}
- public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
- TrafficTreatment treatment, int priority,
- long life, long idle, long packets, long bytes, Integer flowId) {
+ private DefaultFlowRule(DeviceId deviceId,
+ TrafficSelector selector, TrafficTreatment treatment,
+ int priority, FlowRuleState state, FlowId flowId) {
this.deviceId = deviceId;
this.priority = priority;
this.selector = selector;
this.treatment = treatment;
-
- this.id = FlowId.valueOf(flowId);
-
- this.life = life;
- this.idle = idle;
- this.packets = packets;
- this.bytes = bytes;
+ this.state = state;
+ this.life = 0;
+ this.packets = 0;
+ this.bytes = 0;
+ this.id = flowId;
this.created = System.currentTimeMillis();
}
@@ -83,11 +113,6 @@
}
@Override
- public long idleMillis() {
- return idle;
- }
-
- @Override
public long packets() {
return packets;
}
@@ -98,6 +123,12 @@
}
@Override
+ public FlowRuleState state() {
+ return this.state;
+ }
+
+
+ @Override
/*
* The priority and statistics can change on a given treatment and selector
*
@@ -116,18 +147,14 @@
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
+
+ if (this == obj) {
+ return true;
+ }
if (obj instanceof FlowRule) {
DefaultFlowRule that = (DefaultFlowRule) obj;
- if (!this.deviceId().equals(that.deviceId())) {
- return false;
- }
- if (!this.treatment().equals(that.treatment())) {
- return false;
- }
- if (!this.selector().equals(that.selector())) {
- return false;
- }
- return true;
+ return Objects.equals(deviceId, that.deviceId) &&
+ Objects.equals(id, that.id);
}
return false;
}
@@ -144,5 +171,4 @@
.toString();
}
-
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java
index 03140f7..6bcf1db 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java
@@ -1,21 +1,40 @@
package org.onlab.onos.net.flow;
+import com.google.common.base.Objects;
+
/**
* Representation of a Flow ID.
*/
public final class FlowId {
- private final int flowid;
+ private final long flowid;
- private FlowId(int id) {
+ private FlowId(long id) {
this.flowid = id;
}
- public static FlowId valueOf(int id) {
+ public static FlowId valueOf(long id) {
return new FlowId(id);
}
- public int value() {
+ public long value() {
return flowid;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj.getClass() == this.getClass()) {
+ FlowId that = (FlowId) obj;
+ return Objects.equal(this.flowid, that.flowid);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.flowid);
+ }
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java
index f2bc1a0..e72beed 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java
@@ -8,6 +8,42 @@
*/
public interface FlowRule {
+
+ public enum FlowRuleState {
+ /**
+ * Indicates that this rule has been created.
+ */
+ CREATED,
+
+ /**
+ * Indicates that this rule has been submitted for addition.
+ * Not necessarily in the flow table.
+ */
+ PENDING_ADD,
+
+ /**
+ * Rule has been added which means it is in the flow table.
+ */
+ ADDED,
+
+ /**
+ * Flow has been marked for removal, might still be in flow table.
+ */
+ PENDING_REMOVE,
+
+ /**
+ * Flow has been removed from flow table and can be purged.
+ */
+ REMOVED
+ }
+
+ /**
+ * Returns the flow rule state.
+ *
+ * @return flow rule state
+ */
+ FlowRuleState state();
+
//TODO: build cookie value
/**
* Returns the ID of this flow.
@@ -54,13 +90,6 @@
long lifeMillis();
/**
- * Returns the number of milliseconds this flow rule has been idle.
- *
- * @return number of millis
- */
- long idleMillis();
-
- /**
* Returns the number of packets this flow rule has matched.
*
* @return number of packets
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java
index ce8e700..b17449d 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java
@@ -19,7 +19,12 @@
/**
* Signifies that a flow rule has been removed.
*/
- RULE_REMOVED
+ RULE_REMOVED,
+
+ /**
+ * Signifies that a rule has been updated.
+ */
+ RULE_UPDATED
}
/**
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java
index 737ac28..01e4372 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java
@@ -1,5 +1,6 @@
package org.onlab.onos.net.flow;
+import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.provider.ProviderService;
/**
@@ -23,6 +24,13 @@
void flowMissing(FlowRule flowRule);
/**
+ * Signals that a flow rule is on the switch but not in the store.
+ *
+ * @param flowRule the extra flow rule
+ */
+ void extraneousFlow(FlowRule flowRule);
+
+ /**
* Signals that a flow rule was indeed added.
*
* @param flowRule the added flow rule
@@ -35,6 +43,8 @@
*
* @param flowRules collection of flow rules
*/
- void pushFlowMetrics(Iterable<FlowRule> flowRules);
+ void pushFlowMetrics(DeviceId deviceId, Iterable<FlowRule> flowRules);
+
+
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
index d2b9432..9db035a 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
@@ -1,7 +1,5 @@
package org.onlab.onos.net.flow;
-import java.util.List;
-
import org.onlab.onos.net.DeviceId;
/**
@@ -31,10 +29,8 @@
* device reconnects to the controller.
*
* @param flowRules one or more flow rules
- * throws SomeKindOfException that indicates which ones were applied and
- * which ones failed
*/
- List<FlowRule> applyFlowRules(FlowRule... flowRules);
+ void applyFlowRules(FlowRule... flowRules);
/**
* Removes the specified flow rules from their respective devices. If the
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
index 6fdc993..0698721 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
@@ -16,12 +16,18 @@
Iterable<FlowRule> getFlowEntries(DeviceId deviceId);
/**
- * Stores a new flow rule, and generates a FlowRule for it.
+ * Stores a new flow rule without generating events.
*
* @param rule the flow rule to add
- * @return a flow entry
*/
- FlowRule storeFlowRule(FlowRule rule);
+ void storeFlowRule(FlowRule rule);
+
+ /**
+ * Deletes a flow rule without generating events.
+ *
+ * @param rule the flow rule to delete
+ */
+ void deleteFlowRule(FlowRule rule);
/**
* Stores a new flow rule, or updates an existing entry.
diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
index 41f7303..1cee01a 100644
--- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
@@ -3,7 +3,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
-import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import org.apache.felix.scr.annotations.Activate;
@@ -17,7 +17,9 @@
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.device.DeviceService;
+import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
import org.onlab.onos.net.flow.FlowRuleEvent;
import org.onlab.onos.net.flow.FlowRuleListener;
import org.onlab.onos.net.flow.FlowRuleProvider;
@@ -29,17 +31,19 @@
import org.onlab.onos.net.provider.AbstractProviderService;
import org.slf4j.Logger;
+import com.google.common.collect.Lists;
+
@Component(immediate = true)
@Service
public class FlowRuleManager
- extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
- implements FlowRuleService, FlowRuleProviderRegistry {
+extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
+implements FlowRuleService, FlowRuleProviderRegistry {
public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
private final Logger log = getLogger(getClass());
private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
- listenerRegistry = new AbstractListenerRegistry<>();
+ listenerRegistry = new AbstractListenerRegistry<>();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleStore store;
@@ -68,27 +72,23 @@
}
@Override
- public List<FlowRule> applyFlowRules(FlowRule... flowRules) {
- List<FlowRule> entries = new ArrayList<FlowRule>();
-
+ public void applyFlowRules(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
- FlowRule f = flowRules[i];
+ FlowRule f = new DefaultFlowRule(flowRules[i], FlowRuleState.PENDING_ADD);
final Device device = deviceService.getDevice(f.deviceId());
final FlowRuleProvider frp = getProvider(device.providerId());
- entries.add(store.storeFlowRule(f));
+ store.storeFlowRule(f);
frp.applyFlowRule(f);
}
-
- return entries;
}
@Override
public void removeFlowRules(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
- FlowRule f = flowRules[i];
+ FlowRule f = new DefaultFlowRule(flowRules[i], FlowRuleState.PENDING_REMOVE);
final Device device = deviceService.getDevice(f.deviceId());
final FlowRuleProvider frp = getProvider(device.providerId());
- store.removeFlowRule(f);
+ store.deleteFlowRule(f);
frp.removeFlowRule(f);
}
@@ -111,8 +111,8 @@
}
private class InternalFlowRuleProviderService
- extends AbstractProviderService<FlowRuleProvider>
- implements FlowRuleProviderService {
+ extends AbstractProviderService<FlowRuleProvider>
+ implements FlowRuleProviderService {
protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
super(provider);
@@ -134,22 +134,30 @@
public void flowMissing(FlowRule flowRule) {
checkNotNull(flowRule, FLOW_RULE_NULL);
checkValidity();
- // TODO Auto-generated method stub
+ log.info("Flow {} has not been installed.");
}
@Override
+ public void extraneousFlow(FlowRule flowRule) {
+ checkNotNull(flowRule, FLOW_RULE_NULL);
+ checkValidity();
+ log.info("Flow {} is on switch but not in store.");
+ }
+
+ @Override
public void flowAdded(FlowRule flowRule) {
checkNotNull(flowRule, FLOW_RULE_NULL);
checkValidity();
FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule);
if (event == null) {
- log.debug("Flow {} updated", flowRule);
+ log.debug("No flow store event generated.");
} else {
- log.debug("Flow {} added", flowRule);
+ log.debug("Flow {} {}", flowRule, event.type());
post(event);
}
+
}
// Posts the specified event to the local event dispatcher.
@@ -160,9 +168,25 @@
}
@Override
- public void pushFlowMetrics(Iterable<FlowRule> flowEntries) {
- // TODO Auto-generated method stub
+ public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowRule> flowEntries) {
+ List<FlowRule> storedRules = Lists.newLinkedList(store.getFlowEntries(deviceId));
+ //List<FlowRule> switchRules = Lists.newLinkedList(flowEntries);
+ Iterator<FlowRule> switchRulesIterator = flowEntries.iterator(); //switchRules.iterator();
+ while (switchRulesIterator.hasNext()) {
+ FlowRule rule = switchRulesIterator.next();
+ if (storedRules.remove(rule)) {
+ // we both have the rule, let's update some info then.
+ flowAdded(rule);
+ } else {
+ // the device has a rule the store does not have
+ extraneousFlow(rule);
+ }
+ }
+ for (FlowRule rule : storedRules) {
+ // there are rules in the store that aren't on the switch
+ flowMissing(rule);
+ }
}
}
diff --git a/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
index b164015..564bea2 100644
--- a/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertTrue;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
+import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
import java.util.ArrayList;
import java.util.List;
@@ -37,10 +38,10 @@
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore;
/**
* Test codifying the flow rule service & flow rule provider service contracts.
@@ -131,7 +132,7 @@
addFlowRule(1);
assertEquals("should still be 2 rules", 2, flowCount());
- validateEvents();
+ validateEvents(RULE_UPDATED);
}
@Test
@@ -149,9 +150,9 @@
assertTrue("store should be empty",
Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
- List<FlowRule> ret = mgr.applyFlowRules(r1, r2, r3);
+ mgr.applyFlowRules(r1, r2, r3);
assertEquals("3 rules should exist", 3, flowCount());
- assertTrue("3 entries should result", fel.containsAll(ret));
+ assertTrue("3 entries should result", fel.containsAll(Lists.newArrayList(r1, r2, r3)));
}
@Test
@@ -167,10 +168,10 @@
mgr.removeFlowRules(rem1, rem2);
//removing from north, so no events generated
validateEvents();
- assertEquals("1 rule should exist", 1, flowCount());
+ assertEquals("3 rule should exist", 3, flowCount());
mgr.removeFlowRules(rem1);
- assertEquals("1 rule should still exist", 1, flowCount());
+ assertEquals("3 rule should still exist", 3, flowCount());
}
@Test
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
index d41b58b..2f0de26 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
@@ -1,22 +1,23 @@
package org.onlab.onos.net.trivial.impl;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
+import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
+import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
+import static org.slf4j.LoggerFactory.getLogger;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleEvent;
+import org.onlab.onos.net.flow.FlowRuleEvent.Type;
import org.onlab.onos.net.flow.FlowRuleStore;
import org.slf4j.Logger;
-import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
-import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
/**
* Manages inventory of flow rules using trivial in-memory implementation.
@@ -28,7 +29,7 @@
private final Logger log = getLogger(getClass());
// store entries as a pile of rules, no info about device tables
- private final Multimap<DeviceId, FlowRule> flowEntries = HashMultimap.create();
+ private final Multimap<DeviceId, FlowRule> flowEntries = ArrayListMultimap.create();
@Activate
public void activate() {
@@ -46,12 +47,26 @@
}
@Override
- public FlowRule storeFlowRule(FlowRule rule) {
+ public void storeFlowRule(FlowRule rule) {
DeviceId did = rule.deviceId();
- FlowRule entry = new DefaultFlowRule(did,
- rule.selector(), rule.treatment(), rule.priority());
- flowEntries.put(did, entry);
- return entry;
+ flowEntries.put(did, rule);
+ }
+
+ @Override
+ public void deleteFlowRule(FlowRule rule) {
+ DeviceId did = rule.deviceId();
+
+ /*
+ * find the rule and mark it for deletion.
+ * Ultimately a flow removed will come remove it.
+ */
+ if (flowEntries.containsEntry(did, rule)) {
+ synchronized (flowEntries) {
+
+ flowEntries.remove(did, rule);
+ flowEntries.put(did, rule);
+ }
+ }
}
@Override
@@ -59,12 +74,17 @@
DeviceId did = rule.deviceId();
// check if this new rule is an update to an existing entry
- for (FlowRule fe : flowEntries.get(did)) {
- if (rule.equals(fe)) {
- // TODO update the stats on this FlowRule?
- return null;
+ if (flowEntries.containsEntry(did, rule)) {
+ synchronized (flowEntries) {
+ // Multimaps support duplicates so we have to remove our rule
+ // and replace it with the current version.
+
+ flowEntries.remove(did, rule);
+ flowEntries.put(did, rule);
}
+ return new FlowRuleEvent(Type.RULE_UPDATED, rule);
}
+
flowEntries.put(did, rule);
return new FlowRuleEvent(RULE_ADDED, rule);
}
@@ -80,4 +100,6 @@
}
}
+
+
}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
index b2e7cf4..8c009a7 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
@@ -88,6 +88,24 @@
}
+ public OFFlowMod buildFlowDel() {
+ Match match = buildMatch();
+ List<OFAction> actions = buildActions();
+
+ OFFlowMod fm = factory.buildFlowDelete()
+ .setCookie(U64.of(cookie.value()))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setActions(actions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setIdleTimeout(10)
+ .setHardTimeout(10)
+ .setPriority(priority)
+ .build();
+
+ return fm;
+ }
+
private List<OFAction> buildActions() {
List<OFAction> acts = new LinkedList<>();
for (Instruction i : treatment.instructions()) {
@@ -246,4 +264,6 @@
return mBuilder.build();
}
+
+
}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowRuleBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowRuleBuilder.java
index ab01ab7..d6c3c2d 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowRuleBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowRuleBuilder.java
@@ -10,6 +10,7 @@
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.flow.criteria.Criteria;
@@ -52,7 +53,7 @@
this.match = entry.getMatch();
this.actions = entry.getActions();
this.dpid = dpid;
- removed = null;
+ this.removed = null;
}
public FlowRuleBuilder(Dpid dpid, OFFlowRemoved removed) {
@@ -69,16 +70,16 @@
if (stat != null) {
return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), buildTreatment(), stat.getPriority(),
- stat.getDurationNsec() / 1000000, stat.getIdleTimeout(),
+ FlowRuleState.ADDED, stat.getDurationNsec() / 1000000,
stat.getPacketCount().getValue(), stat.getByteCount().getValue(),
- (int) (stat.getCookie().getValue() & 0xFFFFFFFF));
+ stat.getCookie().getValue());
} else {
// TODO: revisit potentially.
return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), null, removed.getPriority(),
- removed.getDurationNsec() / 1000000, removed.getIdleTimeout(),
+ FlowRuleState.REMOVED, removed.getDurationNsec() / 1000000,
removed.getPacketCount().getValue(), removed.getByteCount().getValue(),
- (int) (removed.getCookie().getValue() & 0xFFFFFFFF));
+ removed.getCookie().getValue());
}
}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index b11eb0c..7ddc65d 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -10,6 +10,7 @@
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleProvider;
import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
@@ -94,11 +95,19 @@
@Override
public void removeFlowRule(FlowRule... flowRules) {
- // TODO Auto-generated method stub
+ for (int i = 0; i < flowRules.length; i++) {
+ removeRule(flowRules[i]);
+ }
}
+ private void removeRule(FlowRule flowRule) {
+ OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
+ sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
+ }
+
+
//TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
// possibly barriers as well. May not be internal at all...
private class InternalFlowProvider
@@ -108,7 +117,7 @@
@Override
public void switchAdded(Dpid dpid) {
- FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), 1);
+ FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), 5);
fsc.start();
collectors.put(dpid, fsc);
}
@@ -154,7 +163,7 @@
entries.add(new FlowRuleBuilder(dpid, reply).build());
}
log.debug("sending flowstats to core {}", entries);
- providerService.pushFlowMetrics(entries);
+ providerService.pushFlowMetrics(DeviceId.deviceId(Dpid.uri(dpid)), entries);
}
}