ONOS-7077 Openflow 1.5 OXS and stat trigger support
Change-Id: I006bcd3d8eac451a780c7e5c69a12298ead14281
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index 6c720c8..8bde2f6 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -17,6 +17,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import org.onlab.packet.EthType;
@@ -49,6 +50,7 @@
private final List<Instruction> all;
private final Instructions.TableTypeTransition table;
private final Instructions.MetadataInstruction meta;
+ private final Instructions.StatTriggerInstruction statTrigger;
private final boolean hasClear;
@@ -69,6 +71,7 @@
this.table = null;
this.meta = null;
this.meter = null;
+ this.statTrigger = null;
}
/**
@@ -80,11 +83,13 @@
* @param clear instruction to clear the deferred actions list
*/
private DefaultTrafficTreatment(List<Instruction> deferred,
- List<Instruction> immediate,
- Instructions.TableTypeTransition table,
- boolean clear,
- Instructions.MetadataInstruction meta,
- Instructions.MeterInstruction meter) {
+ List<Instruction> immediate,
+ Instructions.TableTypeTransition table,
+ boolean clear,
+ Instructions.MetadataInstruction meta,
+ Instructions.MeterInstruction meter,
+ Instructions.StatTriggerInstruction statTrigger
+ ) {
this.immediate = ImmutableList.copyOf(checkNotNull(immediate));
this.deferred = ImmutableList.copyOf(checkNotNull(deferred));
this.all = new ImmutableList.Builder<Instruction>()
@@ -95,6 +100,7 @@
this.meta = meta;
this.hasClear = clear;
this.meter = meter;
+ this.statTrigger = statTrigger;
}
@Override
@@ -128,6 +134,11 @@
}
@Override
+ public Instructions.StatTriggerInstruction statTrigger() {
+ return statTrigger;
+ }
+
+ @Override
public Instructions.MeterInstruction metered() {
return meter;
}
@@ -191,6 +202,7 @@
.add("transition", table == null ? "None" : table.toString())
.add("meter", meter == null ? "None" : meter.toString())
.add("cleared", hasClear)
+ .add("StatTrigger", statTrigger)
.add("metadata", meta)
.toString();
}
@@ -209,6 +221,8 @@
Instructions.MeterInstruction meter;
+ Instructions.StatTriggerInstruction statTrigger;
+
List<Instruction> deferred = new ArrayList<>();
List<Instruction> immediate = new ArrayList<>();
@@ -259,6 +273,9 @@
case METER:
meter = (Instructions.MeterInstruction) instruction;
break;
+ case STAT_TRIGGER:
+ statTrigger = (Instructions.StatTriggerInstruction) instruction;
+ break;
default:
throw new IllegalArgumentException("Unknown instruction type: " +
instruction.type());
@@ -493,6 +510,12 @@
}
@Override
+ public TrafficTreatment.Builder statTrigger(Map<StatTriggerField, Long> statTriggerFieldMap,
+ StatTriggerFlag statTriggerFlag) {
+ return add(Instructions.statTrigger(statTriggerFieldMap, statTriggerFlag));
+ }
+
+ @Override
public TrafficTreatment.Builder addTreatment(TrafficTreatment treatment) {
List<Instruction> previous = current;
deferred();
@@ -516,7 +539,7 @@
immediate();
noAction();
}
- return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter);
+ return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter, statTrigger);
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/StatTriggerField.java b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerField.java
new file mode 100644
index 0000000..f946542
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerField.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.flow;
+
+/**
+ * Stat fields are supported default by OXS.
+ */
+public enum StatTriggerField {
+ /** Time flow entry has been alive. Unit indicates nanoseconds. */
+ DURATION,
+ /** Time flow entry has been idle. Unit indicates nanoseconds. */
+ IDLE_TIME,
+ /** Number of aggregated flow entries. */
+ FLOW_COUNT,
+ /** Number of packets in flow entry. */
+ PACKET_COUNT,
+ /** Number of bytes in flow entry. */
+ BYTE_COUNT
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/flow/StatTriggerFlag.java b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerFlag.java
new file mode 100644
index 0000000..7ed650c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerFlag.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.flow;
+
+/**
+ * Stat Trigger Flags.
+ */
+public enum StatTriggerFlag {
+ /** Trigger for all multiples of thresholds. */
+ PERIODIC,
+ /** Trigger on only first reach threshold. */
+ ONLY_FIRST
+}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index 9ddabe1..057f0f8 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -16,6 +16,7 @@
package org.onosproject.net.flow;
import java.util.List;
+import java.util.Map;
import com.google.common.annotations.Beta;
import org.onlab.packet.EthType;
@@ -81,6 +82,12 @@
Instructions.MetadataInstruction writeMetadata();
/**
+ * Returns the stat trigger instruction if there is one.
+ * @return a stat trigger instruction; may be null.
+ */
+ Instructions.StatTriggerInstruction statTrigger();
+
+ /**
* Returns the meter instruction if there is one.
*
* @return a meter instruction that may be null
@@ -422,6 +429,16 @@
Builder extension(ExtensionTreatment extension, DeviceId deviceId);
/**
+ * Add stat trigger instruction.
+ *
+ * @param statTriggerFieldMap defines stat trigger constraints
+ * @param statTriggerFlag describes which circumstances that start will be triggered
+ * @return a treatment builder
+ */
+ Builder statTrigger(Map<StatTriggerField, Long> statTriggerFieldMap,
+ StatTriggerFlag statTriggerFlag);
+
+ /**
* Add all instructions from another treatment.
*
* @param treatment another treatment
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
index c3c9b60..66fbb18 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
@@ -96,7 +96,12 @@
/**
* Signifies that an extension instruction will be used.
*/
- EXTENSION
+ EXTENSION,
+
+ /**
+ * Signifies that statistics will be triggered.
+ */
+ STAT_TRIGGER
}
/**
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index 460976a..9bd7df5 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -16,6 +16,7 @@
package org.onosproject.net.flow.instructions;
import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
import org.onlab.packet.EthType;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
@@ -28,6 +29,8 @@
import org.onosproject.net.OchSignal;
import org.onosproject.net.OduSignalId;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction;
import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType;
@@ -42,6 +45,7 @@
import org.onosproject.net.meter.MeterId;
import org.onosproject.net.pi.runtime.PiTableAction;
+import java.util.Map;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
@@ -498,6 +502,20 @@
}
/**
+ * Creates a stat trigger instruction.
+ *
+ * @param statTriggerMap map keeps stat trigger threshold
+ * @param flag stat trigger flag
+ * @return stat trigger instruction
+ */
+ public static StatTriggerInstruction statTrigger(Map<StatTriggerField, Long> statTriggerMap,
+ StatTriggerFlag flag) {
+ checkNotNull(statTriggerMap, "Stat trigger map cannot be null");
+ checkNotNull(flag, "Stat trigger flag cannot be null");
+ return new StatTriggerInstruction(statTriggerMap, flag);
+ }
+
+ /**
* No Action instruction.
*/
public static final class NoActionInstruction implements Instruction {
@@ -865,6 +883,68 @@
}
}
+ public static class StatTriggerInstruction implements Instruction {
+ private Map<StatTriggerField, Long> statTriggerFieldMap;
+ private StatTriggerFlag statTriggerFlag;
+
+
+ StatTriggerInstruction(Map<StatTriggerField, Long> statTriggerMap,
+ StatTriggerFlag flag) {
+ this.statTriggerFieldMap = ImmutableMap.copyOf(statTriggerMap);
+ this.statTriggerFlag = flag;
+ }
+
+ public Map<StatTriggerField, Long> getStatTriggerFieldMap() {
+ return statTriggerFieldMap;
+ }
+
+ public StatTriggerFlag getStatTriggerFlag() {
+ return statTriggerFlag;
+ }
+
+ public Long getStatValue(StatTriggerField field) {
+ return statTriggerFieldMap.get(field);
+ }
+
+ @Override
+ public Type type() {
+ return Type.STAT_TRIGGER;
+ }
+
+ @Override
+ public String toString() {
+ return "StatTriggerInstruction{" +
+ "statTriggerFieldMap=" + statTriggerFieldMap +
+ ", statTriggerFlag=" + statTriggerFlag +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ StatTriggerInstruction that = (StatTriggerInstruction) o;
+
+ if (!Objects.equals(statTriggerFieldMap, that.statTriggerFieldMap)) {
+ return false;
+ }
+
+ return statTriggerFlag == that.statTriggerFlag;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = statTriggerFieldMap != null ? statTriggerFieldMap.hashCode() : 0;
+ result = 31 * result + (statTriggerFlag != null ? statTriggerFlag.hashCode() : 0);
+ return result;
+ }
+ }
+
}
diff --git a/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java b/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
index 9eada31..ddf6500 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
@@ -31,6 +31,8 @@
import org.onosproject.net.Lambda;
import org.onosproject.net.OduSignalId;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
import org.onosproject.net.meter.MeterId;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionId;
@@ -38,7 +40,9 @@
import org.onosproject.net.pi.runtime.PiActionParamId;
import org.onosproject.net.pi.runtime.PiTableAction;
+import java.util.EnumMap;
import java.util.List;
+import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@@ -829,6 +833,49 @@
meterInstruction2);
}
+ private long packetCountValue1 = 5L;
+ private long byteCountValue1 = 10L;
+ private long packetCountValue2 = 10L;
+ private long byteCountValue2 = 5L;
+ private StatTriggerFlag flag1 = StatTriggerFlag.ONLY_FIRST;
+ private StatTriggerFlag flag2 = StatTriggerFlag.PERIODIC;
+ Map<StatTriggerField, Long> statTriggerFieldMap1 = new EnumMap<StatTriggerField, Long>(StatTriggerField.class) {
+ {
+ put(StatTriggerField.BYTE_COUNT, packetCountValue1);
+ put(StatTriggerField.PACKET_COUNT, byteCountValue1);
+ }
+ };
+ Map<StatTriggerField, Long> statTriggerFieldMap2 = new EnumMap<StatTriggerField, Long>(StatTriggerField.class) {
+ {
+ put(StatTriggerField.BYTE_COUNT, packetCountValue2);
+ put(StatTriggerField.PACKET_COUNT, byteCountValue2);
+ }
+ };
+
+ final Instruction statInstruction1 = Instructions.statTrigger(statTriggerFieldMap1, flag1);
+ final Instruction statInstruction1Same = Instructions.statTrigger(statTriggerFieldMap1, flag1);
+ final Instruction statInstruction2 = Instructions.statTrigger(statTriggerFieldMap2, flag2);
+
+ @Test
+ public void testStatTriggerTrafficMethod() {
+ final Instruction instruction = Instructions.statTrigger(statTriggerFieldMap1, flag1);
+ final Instructions.StatTriggerInstruction statTriggerInstruction =
+ checkAndConvert(instruction,
+ Instruction.Type.STAT_TRIGGER,
+ Instructions.StatTriggerInstruction.class);
+ assertThat(statTriggerInstruction.getStatTriggerFieldMap(), is(equalTo(statTriggerFieldMap1)));
+ assertThat(statTriggerInstruction.getStatTriggerFlag(), is(equalTo(flag1)));
+ assertThat(statTriggerInstruction.getStatTriggerFieldMap(), is(not(equalTo(statTriggerFieldMap2))));
+ assertThat(statTriggerInstruction.getStatTriggerFlag(), is(not(equalTo(flag2))));
+ }
+
+ @Test
+ public void testStatTriggerTrafficInstructionEquals() {
+ checkEqualsAndToString(statInstruction1,
+ statInstruction1Same,
+ statInstruction2);
+ }
+
// TableTypeTransition
private final Instruction transitionInstruction1 = Instructions.transition(1);
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index 352e2f5..a05745c 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -113,6 +113,11 @@
}
@Override
+ public Instructions.StatTriggerInstruction statTrigger() {
+ return null;
+ }
+
+ @Override
public Instructions.MeterInstruction metered() {
return null;
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index a9571f9..ff55e49 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -17,6 +17,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.EthType;
@@ -37,6 +38,8 @@
import org.onosproject.net.OduSignalId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
@@ -48,10 +51,12 @@
import org.onosproject.net.meter.MeterId;
import org.slf4j.Logger;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.onlab.util.Tools.nullIsIllegal;
+import static org.onosproject.codec.impl.InstructionCodec.STAT_PACKET_COUNT;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -262,6 +267,58 @@
+ subType + " is not supported");
}
+ private Instruction decodeStatTrigger() {
+ String statTriggerFlag = nullIsIllegal(json.get(InstructionCodec.STAT_TRIGGER_FLAG),
+ InstructionCodec.STAT_TRIGGER_FLAG + InstructionCodec.ERROR_MESSAGE).asText();
+
+ StatTriggerFlag flag = null;
+
+ if (statTriggerFlag.equals(StatTriggerFlag.ONLY_FIRST.name())) {
+ flag = StatTriggerFlag.ONLY_FIRST;
+ } else if (statTriggerFlag.equals(StatTriggerFlag.PERIODIC.name())) {
+ flag = StatTriggerFlag.PERIODIC;
+ } else {
+ throw new IllegalArgumentException("statTriggerFlag "
+ + statTriggerFlag + " is not supported");
+ }
+ if (!json.has(InstructionCodec.STAT_THRESHOLDS)) {
+ throw new IllegalArgumentException("statThreshold is not added");
+ }
+ JsonNode statThresholdsNode = nullIsIllegal(json.get(InstructionCodec.STAT_THRESHOLDS),
+ InstructionCodec.STAT_THRESHOLDS + InstructionCodec.ERROR_MESSAGE);
+ Map<StatTriggerField, Long> statThresholdMap = getStatThreshold(statThresholdsNode);
+ if (statThresholdMap.isEmpty()) {
+ throw new IllegalArgumentException("statThreshold must have at least one property");
+ }
+ return Instructions.statTrigger(statThresholdMap, flag);
+ }
+
+ private Map<StatTriggerField, Long> getStatThreshold(JsonNode statThresholdNode) {
+ Map<StatTriggerField, Long> statThresholdMap = Maps.newEnumMap(StatTriggerField.class);
+ for (JsonNode jsonNode : statThresholdNode) {
+ if (jsonNode.hasNonNull(InstructionCodec.STAT_BYTE_COUNT)) {
+ JsonNode byteCountNode = jsonNode.get(InstructionCodec.STAT_BYTE_COUNT);
+ if (!byteCountNode.isNull() && byteCountNode.isNumber()) {
+ statThresholdMap.put(StatTriggerField.BYTE_COUNT, byteCountNode.asLong());
+ }
+ } else if (jsonNode.hasNonNull(STAT_PACKET_COUNT)) {
+ JsonNode packetCount = jsonNode.get(STAT_PACKET_COUNT);
+ if (!packetCount.isNull() && packetCount.isNumber()) {
+ statThresholdMap.put(StatTriggerField.PACKET_COUNT, packetCount.asLong());
+ }
+ } else if (jsonNode.hasNonNull(InstructionCodec.STAT_DURATION)) {
+ JsonNode duration = jsonNode.get(InstructionCodec.STAT_DURATION);
+ if (!duration.isNull() && duration.isNumber()) {
+ statThresholdMap.put(StatTriggerField.DURATION, duration.asLong());
+ }
+ } else {
+ log.error("Unsupported stat {}", jsonNode.toString());
+ }
+ }
+
+ return statThresholdMap;
+ }
+
/**
* Decodes a extension instruction.
*
@@ -391,6 +448,8 @@
return decodeL4();
} else if (type.equals(Instruction.Type.EXTENSION.name())) {
return decodeExtension();
+ } else if (type.equals(Instruction.Type.STAT_TRIGGER.name())) {
+ return decodeStatTrigger();
}
throw new IllegalArgumentException("Instruction type "
+ type + " is not supported");
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
index 1f741b5..9762643 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
@@ -59,6 +59,11 @@
protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap";
protected static final String EXTENSION = "extension";
protected static final String DEVICE_ID = "deviceId";
+ protected static final String STAT_TRIGGER_FLAG = "statTriggerFlag";
+ protected static final String STAT_THRESHOLDS = "statThreshold";
+ protected static final String STAT_BYTE_COUNT = "byteCount";
+ protected static final String STAT_PACKET_COUNT = "packetCount";
+ protected static final String STAT_DURATION = "duration";
protected static final String MISSING_MEMBER_MESSAGE =
" member is required in Instruction";
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 825ef1a..7785a38 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -664,6 +664,11 @@
}
@Override
+ public Instructions.StatTriggerInstruction statTrigger() {
+ return null;
+ }
+
+ @Override
public Instructions.MeterInstruction metered() {
return null;
}
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index d5deae1..6c4ad07 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -100,16 +100,18 @@
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleExtPayLoad;
+import org.onosproject.net.flow.IndexTableId;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
+import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TableId;
+import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
import org.onosproject.net.flow.oldbatch.FlowRuleBatchEvent;
import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
import org.onosproject.net.flow.oldbatch.FlowRuleBatchRequest;
-import org.onosproject.net.flow.FlowRuleEvent;
-import org.onosproject.net.flow.FlowRuleExtPayLoad;
-import org.onosproject.net.flow.IndexTableId;
-import org.onosproject.net.flow.StoredFlowEntry;
-import org.onosproject.net.flow.TableId;
-import org.onosproject.net.flow.TableStatisticsEntry;
import org.onosproject.net.flow.criteria.ArpHaCriterion;
import org.onosproject.net.flow.criteria.ArpOpCriterion;
import org.onosproject.net.flow.criteria.ArpPaCriterion;
@@ -355,6 +357,9 @@
.nextId(KryoNamespace.INITIAL_ID + BASIC_MAX_SIZE + MISC_MAX_SIZE)
.register(
Instructions.MeterInstruction.class,
+ Instructions.StatTriggerInstruction.class,
+ StatTriggerFlag.class,
+ StatTriggerField.class,
MeterId.class,
Version.class,
ControllerNode.State.class,
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java
index c447755..584401e 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java
@@ -465,6 +465,11 @@
}
@Override
+ public Instructions.StatTriggerInstruction statTrigger() {
+ return null;
+ }
+
+ @Override
public Instructions.MeterInstruction metered() {
return null;
}
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java
index bf0af04..9bd2146 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/DefaultOpenFlowPacketContext.java
@@ -70,14 +70,24 @@
if (isBuilt.getAndSet(true)) {
return;
}
- OFPacketOut.Builder builder = sw.factory().buildPacketOut();
OFAction act = buildOutput(outPort.getPortNumber());
- pktout = builder.setXid(pktin.getXid())
- .setInPort(pktinInPort())
- .setBufferId(OFBufferId.NO_BUFFER)
- .setData(pktin.getData())
+ pktout = createOFPacketOut(pktin.getData(), act, pktin.getXid());
+ }
+
+ private OFPacketOut createOFPacketOut(byte[] data, OFAction act, long xid) {
+ OFPacketOut.Builder builder = sw.factory().buildPacketOut();
+ if (sw.factory().getVersion().getWireVersion() <= OFVersion.OF_14.getWireVersion()) {
+ return builder.setXid(xid)
+ .setInPort(pktinInPort())
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setData(data)
// .setBufferId(pktin.getBufferId())
+ .setActions(Collections.singletonList(act)).build();
+ }
+ return builder.setXid(xid)
+ .setBufferId(OFBufferId.NO_BUFFER)
.setActions(Collections.singletonList(act))
+ .setData(data)
.build();
}
@@ -86,14 +96,8 @@
if (isBuilt.getAndSet(true)) {
return;
}
- OFPacketOut.Builder builder = sw.factory().buildPacketOut();
OFAction act = buildOutput(outPort.getPortNumber());
- pktout = builder.setXid(pktin.getXid())
- .setBufferId(OFBufferId.NO_BUFFER)
- .setInPort(pktinInPort())
- .setActions(Collections.singletonList(act))
- .setData(ethFrame.serialize())
- .build();
+ pktout = createOFPacketOut(ethFrame.serialize(), act, pktin.getXid());
}
@Override
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
index b50bdbc..05b68a4 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -49,6 +49,8 @@
import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
import org.projectfloodlight.openflow.protocol.OFExperimenter;
import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
@@ -60,6 +62,8 @@
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFQueueStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFQueueStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
@@ -88,8 +92,6 @@
import static org.onosproject.net.Device.Type.CONTROLLER;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
import static org.onosproject.openflow.controller.Dpid.dpid;
-import org.projectfloodlight.openflow.protocol.OFQueueStatsEntry;
-import org.projectfloodlight.openflow.protocol.OFQueueStatsReply;
@Component(immediate = true)
@@ -161,6 +163,9 @@
protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
ArrayListMultimap.create();
+ protected Multimap<Dpid, OFFlowLightweightStatsEntry> fullFlowLightweightStats =
+ ArrayListMultimap.create();
+
protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
ArrayListMultimap.create();
@@ -422,7 +427,17 @@
executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
}
break;
-
+ case FLOW_LIGHTWEIGHT:
+ Collection<OFFlowLightweightStatsEntry> flowLightweightStats =
+ publishFlowStatsLightweight(dpid, (OFFlowLightweightStatsReply) reply);
+ if (flowLightweightStats != null) {
+ OFFlowLightweightStatsReply.Builder rep =
+ OFFactories.getFactory(reply.getVersion()).buildFlowLightweightStatsReply();
+ rep.setEntries(ImmutableList.copyOf(flowLightweightStats));
+ rep.setXid(reply.getXid());
+ executorMsgs.execute(new OFMessageHandler(dpid, rep.build()));
+ }
+ break;
case TABLE:
Collection<OFTableStatsEntry> tableStats = publishTableStats(dpid, (OFTableStatsReply) reply);
if (tableStats != null) {
@@ -529,6 +544,17 @@
return null;
}
+ private synchronized Collection<OFFlowLightweightStatsEntry> publishFlowStatsLightweight(
+ Dpid dpid,
+ OFFlowLightweightStatsReply reply) {
+ //TODO: Get rid of synchronized
+ fullFlowLightweightStats.putAll(dpid, reply.getEntries());
+ if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+ return fullFlowLightweightStats.removeAll(dpid);
+ }
+ return null;
+ }
+
private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid,
OFTableStatsReply reply) {
//TODO: Get rid of synchronized
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
index 4ec4a69..a281927 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
@@ -134,8 +134,9 @@
return new FlowModBuilderVer10(flowRule, factory, xid, driverService);
case OF_13:
case OF_14:
- case OF_15:
return new FlowModBuilderVer13(flowRule, factory, xid, driverService);
+ case OF_15:
+ return new FlowModBuilderVer15(flowRule, factory, xid, driverService);
default:
throw new UnsupportedOperationException(
"No flow mod builder for protocol version " + factory.getVersion());
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index 5381af7..ad601c9 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -100,10 +100,10 @@
*/
public class FlowModBuilderVer13 extends FlowModBuilder {
- private final Logger log = LoggerFactory.getLogger(getClass());
- private static final int OFPCML_NO_BUFFER = 0xffff;
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected static final int OFPCML_NO_BUFFER = 0xffff;
- private final TrafficTreatment treatment;
+ protected final TrafficTreatment treatment;
/**
* Constructor for a flow mod builder for OpenFlow 1.3.
@@ -295,24 +295,24 @@
return actions;
}
- private OFInstruction buildTableGoto(Instructions.TableTypeTransition i) {
+ protected OFInstruction buildTableGoto(Instructions.TableTypeTransition i) {
OFInstruction instruction = factory().instructions().gotoTable(
TableId.of(i.tableId()));
return instruction;
}
- private OFInstruction buildMetadata(Instructions.MetadataInstruction m) {
+ protected OFInstruction buildMetadata(Instructions.MetadataInstruction m) {
OFInstruction instruction = factory().instructions().writeMetadata(
U64.of(m.metadata()), U64.of(m.metadataMask()));
return instruction;
}
- private OFInstruction buildMeter(Instructions.MeterInstruction metered) {
+ protected OFInstruction buildMeter(Instructions.MeterInstruction metered) {
return factory().instructions().meter(metered.meterId().id());
}
- private OFAction buildL0Modification(Instruction i) {
+ protected OFAction buildL0Modification(Instruction i) {
L0ModificationInstruction l0m = (L0ModificationInstruction) i;
OFOxm<?> oxm = null;
switch (l0m.subtype()) {
@@ -340,7 +340,7 @@
return null;
}
- private OFAction buildL1Modification(Instruction i) {
+ protected OFAction buildL1Modification(Instruction i) {
L1ModificationInstruction l1m = (L1ModificationInstruction) i;
OFOxm<?> oxm = null;
switch (l1m.subtype()) {
@@ -365,7 +365,7 @@
return null;
}
- private OFAction buildL2Modification(Instruction i) {
+ protected OFAction buildL2Modification(Instruction i) {
L2ModificationInstruction l2m = (L2ModificationInstruction) i;
ModEtherInstruction eth;
OFOxm<?> oxm = null;
@@ -430,7 +430,7 @@
return null;
}
- private OFAction buildL3Modification(Instruction i) {
+ protected OFAction buildL3Modification(Instruction i) {
L3ModificationInstruction l3m = (L3ModificationInstruction) i;
ModIPInstruction ip;
Ip4Address ip4;
@@ -493,7 +493,7 @@
return null;
}
- private OFAction buildL4Modification(Instruction i) {
+ protected OFAction buildL4Modification(Instruction i) {
L4ModificationInstruction l4m = (L4ModificationInstruction) i;
ModTransportPortInstruction tp;
OFOxm<?> oxm = null;
@@ -525,7 +525,7 @@
return null;
}
- private OFAction buildExtensionAction(ExtensionTreatment i) {
+ protected OFAction buildExtensionAction(ExtensionTreatment i) {
if (!driverService.isPresent()) {
log.error("No driver service present");
return null;
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer15.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer15.java
new file mode 100644
index 0000000..7ba893a
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer15.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.provider.of.flow.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.OFOxsList;
+import org.projectfloodlight.openflow.protocol.OFStatTriggerFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
+import org.projectfloodlight.openflow.protocol.action.OFActionMeter;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetQueue;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.oxs.OFOxs;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFGroup;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.projectfloodlight.openflow.protocol.OFStatTriggerFlags.ONLY_FIRST;
+import static org.projectfloodlight.openflow.protocol.OFStatTriggerFlags.PERIODIC;
+
+/**
+ * Flow mod builder for OpenFlow 1.5+.
+ */
+public class FlowModBuilderVer15 extends FlowModBuilderVer13 {
+
+ /**
+ * Constructor for a flow mod builder for OpenFlow 1.5.
+ *
+ * @param flowRule the flow rule to transform into a flow mod
+ * @param factory the OpenFlow factory to use to build the flow mod
+ * @param xid the transaction ID
+ * @param driverService the device driver service
+ */
+ protected FlowModBuilderVer15(FlowRule flowRule, OFFactory factory,
+ Optional<Long> xid,
+ Optional<DriverService> driverService) {
+ super(flowRule, factory, xid, driverService);
+ }
+
+ @Override
+ public OFFlowMod buildFlowAdd() {
+ Match match = buildMatch();
+ List<OFAction> deferredActions = buildActions(treatment.deferred(), false);
+ List<OFAction> immediateActions = buildActions(treatment.immediate(), true);
+ List<OFInstruction> instructions = Lists.newLinkedList();
+
+ if (treatment.clearedDeferred()) {
+ instructions.add(factory().instructions().clearActions());
+ }
+ if (!immediateActions.isEmpty()) {
+ instructions.add(factory().instructions().applyActions(immediateActions));
+ }
+ if (!deferredActions.isEmpty()) {
+ instructions.add(factory().instructions().writeActions(deferredActions));
+ }
+ if (treatment.tableTransition() != null) {
+ instructions.add(buildTableGoto(treatment.tableTransition()));
+ }
+ if (treatment.writeMetadata() != null) {
+ instructions.add(buildMetadata(treatment.writeMetadata()));
+ }
+ if (treatment.statTrigger() != null) {
+ instructions.add(buildStatTrigger(treatment.statTrigger()));
+ }
+
+
+
+ long cookie = flowRule().id().value();
+
+ OFFlowAdd fm = factory().buildFlowAdd()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(instructions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .setTableId(TableId.of(flowRule().tableId()))
+ .setHardTimeout(flowRule().hardTimeout())
+ .build();
+
+ return fm;
+ }
+
+ @Override
+ public OFFlowMod buildFlowMod() {
+ Match match = buildMatch();
+ List<OFAction> deferredActions = buildActions(treatment.deferred(), false);
+ List<OFAction> immediateActions = buildActions(treatment.immediate(), true);
+ List<OFInstruction> instructions = Lists.newLinkedList();
+
+
+ if (!immediateActions.isEmpty()) {
+ instructions.add(factory().instructions().applyActions(immediateActions));
+ }
+ if (treatment.clearedDeferred()) {
+ instructions.add(factory().instructions().clearActions());
+ }
+ if (!deferredActions.isEmpty()) {
+ instructions.add(factory().instructions().writeActions(deferredActions));
+ }
+ if (treatment.tableTransition() != null) {
+ instructions.add(buildTableGoto(treatment.tableTransition()));
+ }
+ if (treatment.writeMetadata() != null) {
+ instructions.add(buildMetadata(treatment.writeMetadata()));
+ }
+ if (treatment.statTrigger() != null) {
+ instructions.add(buildStatTrigger(treatment.statTrigger()));
+ }
+
+ long cookie = flowRule().id().value();
+
+ OFFlowMod fm = factory().buildFlowModify()
+ .setXid(xid)
+ .setCookie(U64.of(cookie))
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setInstructions(instructions)
+ .setMatch(match)
+ .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+ .setPriority(flowRule().priority())
+ .setTableId(TableId.of(flowRule().tableId()))
+ .setHardTimeout(flowRule().hardTimeout())
+ .build();
+
+ return fm;
+ }
+
+ private List<OFAction> buildActions(List<Instruction> treatments, Boolean immediateActions) {
+ if (treatment == null) {
+ return Collections.emptyList();
+ }
+
+ boolean tableFound = false;
+ List<OFAction> actions = new LinkedList<>();
+
+ //Meter action handling
+ if (null != treatment.metered() && immediateActions) {
+ OFAction meterAction = buildMultipleMeterAction(treatment.metered());
+ actions.add(meterAction);
+ }
+
+ for (Instruction i : treatments) {
+ switch (i.type()) {
+ case NOACTION:
+ return Collections.emptyList();
+ case L0MODIFICATION:
+ actions.add(buildL0Modification(i));
+ break;
+ case L1MODIFICATION:
+ actions.add(buildL1Modification(i));
+ break;
+ case L2MODIFICATION:
+ actions.add(buildL2Modification(i));
+ break;
+ case L3MODIFICATION:
+ actions.add(buildL3Modification(i));
+ break;
+ case L4MODIFICATION:
+ actions.add(buildL4Modification(i));
+ break;
+ case OUTPUT:
+ Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
+ OFActionOutput.Builder action = factory().actions().buildOutput()
+ .setPort(OFPort.of((int) out.port().toLong()));
+ if (out.port().equals(PortNumber.CONTROLLER)) {
+ action.setMaxLen(OFPCML_NO_BUFFER);
+ }
+ actions.add(action.build());
+ break;
+ case GROUP:
+ Instructions.GroupInstruction group = (Instructions.GroupInstruction) i;
+ OFActionGroup.Builder groupBuilder = factory().actions().buildGroup()
+ .setGroup(OFGroup.of(group.groupId().id()));
+ actions.add(groupBuilder.build());
+ break;
+ case QUEUE:
+ Instructions.SetQueueInstruction queue = (Instructions.SetQueueInstruction) i;
+ OFActionSetQueue.Builder queueBuilder = factory().actions().buildSetQueue()
+ .setQueueId(queue.queueId());
+ actions.add(queueBuilder.build());
+ break;
+ case TABLE:
+ //FIXME: should not occur here.
+ tableFound = true;
+ break;
+ case EXTENSION:
+ actions.add(buildExtensionAction(((Instructions.ExtensionInstructionWrapper) i)
+ .extensionInstruction()));
+ break;
+ default:
+ log.warn("Instruction type {} not yet implemented.", i.type());
+ }
+ }
+
+ if (tableFound && actions.isEmpty()) {
+ // handles the case where there are no actions, but there is
+ // a goto instruction for the next table
+ return Collections.emptyList();
+ }
+ return actions;
+ }
+
+ private OFOxsList getOFOxsList(Map<StatTriggerField, Long> statTriggerMap) {
+ OFFactory factory = factory();
+ List<OFOxs<?>> ofOxsList = Lists.newArrayList();
+ for (Map.Entry<StatTriggerField, Long> entry : statTriggerMap.entrySet()) {
+ switch (entry.getKey()) {
+ case DURATION:
+ ofOxsList.add(factory.oxss().buildDuration().setValue(U64.of(entry.getValue())).build());
+ break;
+ case IDLE_TIME:
+ ofOxsList.add(factory.oxss().buildIdleTime().setValue(U64.of(entry.getValue())).build());
+ break;
+ case BYTE_COUNT:
+ ofOxsList.add(factory.oxss().buildByteCount().setValue(U64.of(entry.getValue())).build());
+ break;
+ case FLOW_COUNT:
+ ofOxsList.add(factory.oxss().buildFlowCount().setValue(U32.of(entry.getValue())).build());
+ break;
+ case PACKET_COUNT:
+ ofOxsList.add(factory.oxss().buildPacketCount().setValue(U64.of(entry.getValue())).build());
+ break;
+ default:
+ log.warn("Unsupported Stat Trigger field");
+ break;
+ }
+ }
+ return OFOxsList.ofList(ofOxsList);
+ }
+
+ private Set<OFStatTriggerFlags> getStatTriggerFlag(StatTriggerFlag flag) {
+ Set<OFStatTriggerFlags> statTriggerFlagsSet = Sets.newHashSet();
+ switch (flag) {
+ case PERIODIC:
+ statTriggerFlagsSet.add(PERIODIC);
+ break;
+ case ONLY_FIRST:
+ statTriggerFlagsSet.add(ONLY_FIRST);
+ break;
+ default:
+ break;
+ }
+ return statTriggerFlagsSet;
+ }
+
+ /**
+ * Meter action builder.
+ *
+ * @param meterInstruction meter instruction
+ * @return meter action
+ */
+ protected OFAction buildMultipleMeterAction(Instructions.MeterInstruction meterInstruction) {
+ OFActionMeter.Builder meterBuilder = factory().actions().buildMeter()
+ .setMeterId(meterInstruction.meterId().id());
+ return meterBuilder.build();
+ }
+
+ protected OFInstruction buildStatTrigger(Instructions.StatTriggerInstruction s) {
+ OFInstruction instruction = factory().instructions().statTrigger(getStatTriggerFlag(s.getStatTriggerFlag()),
+ getOFOxsList(s.getStatTriggerFieldMap()));
+ return instruction;
+ }
+}
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index 9dc03cd..7f472ad 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -63,6 +63,7 @@
import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
@@ -142,6 +143,7 @@
private final Timer timer = new Timer("onos-openflow-collector");
+
// Old simple collector set
private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newConcurrentMap();
@@ -441,6 +443,8 @@
pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
} else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
pushTableStatistics(dpid, (OFTableStatsReply) msg);
+ } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
+ pushFlowLightWeightMetrics(dpid, (OFFlowLightweightStatsReply) msg);
}
break;
case BARRIER_REPLY:
@@ -653,6 +657,40 @@
providerService.pushTableStatistics(did, tableStatsEntries);
}
+ private void pushFlowLightWeightMetrics(Dpid dpid, OFFlowLightweightStatsReply replies) {
+
+ DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
+ NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
+ if (adaptiveFlowSampling && afsc != null) {
+ List<FlowEntry> flowEntries = replies.getEntries().stream()
+ .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
+ .collect(Collectors.toList());
+
+ // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
+ if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
+ log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
+ + "OFFlowStatsReply Xid={}, for {}",
+ afsc.getFlowMissingXid(), replies.getXid(), dpid);
+ if (afsc.getFlowMissingXid() == replies.getXid()) {
+ // call entire flow stats update with flowMissing synchronization.
+ // used existing pushFlowMetrics
+ providerService.pushFlowMetrics(did, flowEntries);
+ }
+ // reset flowMissingXid to NO_FLOW_MISSING_XID
+ afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
+ } else {
+ // call individual flow stats update
+ providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
+ }
+ } else {
+ List<FlowEntry> flowEntries = replies.getEntries().stream()
+ .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
+ .collect(Collectors.toList());
+ // call existing entire flow stats update with flowMissing synchronization
+ providerService.pushFlowMetrics(did, flowEntries);
+ }
+ }
+
private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
OFTableStatsEntry ofEntry) {
TableStatisticsEntry entry = null;
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
index 083a74c..c16c34f 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
@@ -16,6 +16,7 @@
package org.onosproject.provider.of.flow.util;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import org.onlab.packet.EthType;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
@@ -42,6 +43,8 @@
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowEntry.FlowEntryState;
import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.ExtensionSelectorType.ExtensionSelectorTypes;
@@ -49,11 +52,14 @@
import org.onosproject.openflow.controller.ExtensionSelectorInterpreter;
import org.onosproject.openflow.controller.ExtensionTreatmentInterpreter;
import org.onosproject.provider.of.flow.impl.NewAdaptiveFlowStatsCollector;
+import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsEntry;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFMatchV3;
import org.projectfloodlight.openflow.protocol.OFObject;
+import org.projectfloodlight.openflow.protocol.OFOxsList;
+import org.projectfloodlight.openflow.protocol.OFStatTriggerFlags;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
@@ -74,12 +80,14 @@
import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionStatTrigger;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteMetadata;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigid;
+import org.projectfloodlight.openflow.protocol.oxs.OFOxs;
import org.projectfloodlight.openflow.protocol.ver13.OFFactoryVer13;
import org.projectfloodlight.openflow.types.CircuitSignalID;
import org.projectfloodlight.openflow.types.IPv4Address;
@@ -97,9 +105,15 @@
import org.slf4j.LoggerFactory;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.onosproject.net.flow.StatTriggerField.*;
+import static org.onosproject.net.flow.StatTriggerField.IDLE_TIME;
+import static org.onosproject.net.flow.StatTriggerFlag.ONLY_FIRST;
+import static org.onosproject.net.flow.StatTriggerFlag.PERIODIC;
import static org.onosproject.net.flow.criteria.Criteria.*;
import static org.onosproject.net.flow.instructions.Instructions.modL0Lambda;
import static org.onosproject.net.flow.instructions.Instructions.modL1OduSignalId;
@@ -111,6 +125,7 @@
private final OFFlowStatsEntry stat;
private final OFFlowRemoved removed;
private final OFFlowMod flowMod;
+ private final OFFlowLightweightStatsEntry lightWeightStat;
private final Match match;
@@ -120,7 +135,7 @@
private final DeviceId deviceId;
- public enum FlowType { STAT, REMOVED, MOD }
+ public enum FlowType { STAT, LIGHTWEIGHT_STAT, REMOVED, MOD }
private final FlowType type;
@@ -140,6 +155,21 @@
this.type = FlowType.STAT;
this.driverService = driverService;
this.afsc = null;
+ this.lightWeightStat = null;
+ }
+
+ public FlowEntryBuilder(DeviceId deviceId, OFFlowLightweightStatsEntry lightWeightStat,
+ DriverService driverService) {
+ this.stat = null;
+ this.match = lightWeightStat.getMatch();
+ this.instructions = null;
+ this.deviceId = deviceId;
+ this.removed = null;
+ this.flowMod = null;
+ this.type = FlowType.LIGHTWEIGHT_STAT;
+ this.driverService = driverService;
+ this.afsc = null;
+ this.lightWeightStat = lightWeightStat;
}
public FlowEntryBuilder(DeviceId deviceId, OFFlowRemoved removed, DriverService driverService) {
@@ -152,6 +182,7 @@
this.type = FlowType.REMOVED;
this.driverService = driverService;
this.afsc = null;
+ this.lightWeightStat = null;
}
public FlowEntryBuilder(DeviceId deviceId, OFFlowMod fm, DriverService driverService) {
@@ -164,6 +195,7 @@
this.removed = null;
this.driverService = driverService;
this.afsc = null;
+ this.lightWeightStat = null;
}
public FlowEntryBuilder withSetAfsc(NewAdaptiveFlowStatsCollector afsc) {
@@ -172,83 +204,16 @@
}
public FlowEntry build(FlowEntryState... state) {
- FlowRule.Builder builder;
try {
switch (this.type) {
case STAT:
- builder = DefaultFlowRule.builder()
- .forDevice(deviceId)
- .withSelector(buildSelector())
- .withTreatment(buildTreatment())
- .withPriority(stat.getPriority())
- .withIdleTimeout(stat.getIdleTimeout())
- .withCookie(stat.getCookie().getValue());
- if (stat.getVersion() != OFVersion.OF_10) {
- builder.forTable(stat.getTableId().getValue());
- }
-
- if (afsc != null) {
- FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(stat.getDurationSec());
- return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
- SECONDS.toNanos(stat.getDurationSec())
- + stat.getDurationNsec(), NANOSECONDS,
- liveType,
- stat.getPacketCount().getValue(),
- stat.getByteCount().getValue());
- } else {
- return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
- stat.getDurationSec(),
- stat.getPacketCount().getValue(),
- stat.getByteCount().getValue());
- }
-
+ return createFlowEntryFromStat();
+ case LIGHTWEIGHT_STAT:
+ return createFlowEntryFromLightweightStat();
case REMOVED:
- builder = DefaultFlowRule.builder()
- .forDevice(deviceId)
- .withSelector(buildSelector())
- .withPriority(removed.getPriority())
- .withIdleTimeout(removed.getIdleTimeout())
- .withCookie(removed.getCookie().getValue())
- .withReason(FlowRule.FlowRemoveReason.parseShort((short) removed.getReason().ordinal()));
-
- if (removed.getVersion() != OFVersion.OF_10) {
- builder.forTable(removed.getTableId().getValue());
- }
-
- if (afsc != null) {
- FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(removed.getDurationSec());
- return new DefaultFlowEntry(builder.build(), FlowEntryState.REMOVED,
- SECONDS.toNanos(removed.getDurationSec())
- + removed.getDurationNsec(), NANOSECONDS,
- liveType,
- removed.getPacketCount().getValue(),
- removed.getByteCount().getValue());
- } else {
- return new DefaultFlowEntry(builder.build(), FlowEntryState.REMOVED,
- removed.getDurationSec(),
- removed.getPacketCount().getValue(),
- removed.getByteCount().getValue());
- }
-
+ return createFlowEntryForFlowRemoved();
case MOD:
- FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED;
- builder = DefaultFlowRule.builder()
- .forDevice(deviceId)
- .withSelector(buildSelector())
- .withTreatment(buildTreatment())
- .withPriority(flowMod.getPriority())
- .withIdleTimeout(flowMod.getIdleTimeout())
- .withCookie(flowMod.getCookie().getValue());
- if (flowMod.getVersion() != OFVersion.OF_10) {
- builder.forTable(flowMod.getTableId().getValue());
- }
-
- if (afsc != null) {
- FlowEntry.FlowLiveType liveType = FlowEntry.FlowLiveType.IMMEDIATE;
- return new DefaultFlowEntry(builder.build(), flowState, 0, liveType, 0, 0);
- } else {
- return new DefaultFlowEntry(builder.build(), flowState, 0, 0, 0);
- }
+ return createFlowEntryForFlowMod(state);
default:
log.error("Unknown flow type : {}", this.type);
return null;
@@ -260,6 +225,143 @@
}
+ private FlowEntry createFlowEntryFromStat() {
+
+ FlowRule.Builder builder = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(buildSelector())
+ .withTreatment(buildTreatment())
+ .withPriority(stat.getPriority())
+ .withIdleTimeout(stat.getIdleTimeout())
+ .withCookie(stat.getCookie().getValue());
+ if (stat.getVersion() != OFVersion.OF_10) {
+ builder.forTable(stat.getTableId().getValue());
+ }
+ if (stat.getVersion().getWireVersion() < OFVersion.OF_15.getWireVersion()) {
+ if (afsc != null) {
+ FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(stat.getDurationSec());
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
+ SECONDS.toNanos(stat.getDurationSec())
+ + stat.getDurationNsec(), NANOSECONDS,
+ liveType,
+ stat.getPacketCount().getValue(),
+ stat.getByteCount().getValue());
+ } else {
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
+ stat.getDurationSec(),
+ stat.getPacketCount().getValue(),
+ stat.getByteCount().getValue());
+ }
+ }
+ FlowStatParser statParser = new FlowStatParser(stat.getStats());
+ if (afsc != null && statParser.isDurationReceived()) {
+ FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(statParser.getDuration());
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
+ SECONDS.toNanos(statParser.getDuration())
+ + SECONDS.toNanos(statParser.getDuration()), NANOSECONDS,
+ liveType,
+ statParser.getPacketCount(),
+ statParser.getByteCount());
+ } else {
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
+ statParser.getDuration(),
+ statParser.getPacketCount(),
+ statParser.getByteCount());
+ }
+
+ }
+
+ private FlowEntry createFlowEntryForFlowMod(FlowEntryState ...state) {
+ FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED;
+ FlowRule.Builder builder = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(buildSelector())
+ .withTreatment(buildTreatment())
+ .withPriority(flowMod.getPriority())
+ .withIdleTimeout(flowMod.getIdleTimeout())
+ .withCookie(flowMod.getCookie().getValue());
+ if (flowMod.getVersion() != OFVersion.OF_10) {
+ builder.forTable(flowMod.getTableId().getValue());
+ }
+
+ if (afsc != null) {
+ FlowEntry.FlowLiveType liveType = FlowEntry.FlowLiveType.IMMEDIATE;
+ return new DefaultFlowEntry(builder.build(), flowState, 0, liveType, 0, 0);
+ } else {
+ return new DefaultFlowEntry(builder.build(), flowState, 0, 0, 0);
+ }
+ }
+
+ private FlowEntry createFlowEntryForFlowRemoved() {
+ FlowRule.Builder builder = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(buildSelector())
+ .withPriority(removed.getPriority())
+ .withIdleTimeout(removed.getIdleTimeout())
+ .withCookie(removed.getCookie().getValue())
+ .withReason(FlowRule.FlowRemoveReason.parseShort((short) removed.getReason().ordinal()));
+
+ if (removed.getVersion() != OFVersion.OF_10) {
+ builder.forTable(removed.getTableId().getValue());
+ }
+ if (removed.getVersion().getWireVersion() < OFVersion.OF_15.getWireVersion()) {
+ if (afsc != null) {
+ FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(removed.getDurationSec());
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.REMOVED,
+ SECONDS.toNanos(removed.getDurationSec())
+ + removed.getDurationNsec(), NANOSECONDS,
+ liveType,
+ removed.getPacketCount().getValue(),
+ removed.getByteCount().getValue());
+ } else {
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.REMOVED,
+ removed.getDurationSec(),
+ removed.getPacketCount().getValue(),
+ removed.getByteCount().getValue());
+ }
+ }
+ FlowStatParser statParser = new FlowStatParser(removed.getStats());
+ if (afsc != null && statParser.isDurationReceived()) {
+ FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(statParser.getDuration());
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.REMOVED,
+ SECONDS.toNanos(statParser.getDuration())
+ + SECONDS.toNanos(statParser.getDuration()), NANOSECONDS,
+ liveType,
+ statParser.getPacketCount(),
+ statParser.getByteCount());
+ } else {
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.REMOVED,
+ statParser.getDuration(),
+ statParser.getPacketCount(),
+ statParser.getByteCount());
+ }
+ }
+
+ private FlowEntry createFlowEntryFromLightweightStat() {
+ FlowRule.Builder builder = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(buildSelector())
+ .withPriority(lightWeightStat.getPriority())
+ .withIdleTimeout(0)
+ .withCookie(0);
+ FlowStatParser flowLightweightStatParser = new FlowStatParser(lightWeightStat.getStats());
+ builder.forTable(lightWeightStat.getTableId().getValue());
+ if (afsc != null && flowLightweightStatParser.isDurationReceived()) {
+ FlowEntry.FlowLiveType liveType = afsc.calFlowLiveType(flowLightweightStatParser.getDuration());
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
+ SECONDS.toNanos(flowLightweightStatParser.getDuration())
+ + flowLightweightStatParser.getDuration(), NANOSECONDS,
+ liveType,
+ flowLightweightStatParser.getPacketCount(),
+ flowLightweightStatParser.getByteCount());
+ } else {
+ return new DefaultFlowEntry(builder.build(), FlowEntryState.ADDED,
+ flowLightweightStatParser.getDuration(),
+ flowLightweightStatParser.getPacketCount(),
+ flowLightweightStatParser.getByteCount());
+ }
+ }
+
private List<OFInstruction> getInstructions(OFFlowMod entry) {
switch (entry.getVersion()) {
case OF_10:
@@ -321,6 +423,10 @@
case CLEAR_ACTIONS:
builder.wipeDeferred();
break;
+ case STAT_TRIGGER:
+ OFInstructionStatTrigger statTrigger = (OFInstructionStatTrigger) in;
+ buildStatTrigger(statTrigger.getThresholds(), statTrigger.getFlags(), builder);
+ break;
case EXPERIMENTER:
break;
case METER:
@@ -333,6 +439,57 @@
return builder.build();
}
+ private TrafficTreatment.Builder buildStatTrigger(OFOxsList oxsList,
+ Set<OFStatTriggerFlags> flagsSet,
+ TrafficTreatment.Builder builder) {
+ Map<StatTriggerField, Long> statTriggerMap = Maps.newEnumMap(StatTriggerField.class);
+ for (OFOxs<?> ofOxs : oxsList) {
+ switch (ofOxs.getStatField().id) {
+ case DURATION:
+ U64 durationType = (U64) ofOxs.getValue();
+ statTriggerMap.put(DURATION, durationType.getValue());
+ break;
+ case FLOW_COUNT:
+ U32 flowCount = (U32) ofOxs.getValue();
+ statTriggerMap.put(FLOW_COUNT, flowCount.getValue());
+ break;
+ case PACKET_COUNT:
+ U64 packetCount = (U64) ofOxs.getValue();
+ statTriggerMap.put(PACKET_COUNT, packetCount.getValue());
+ break;
+ case BYTE_COUNT:
+ U64 byteCount = (U64) ofOxs.getValue();
+ statTriggerMap.put(BYTE_COUNT, byteCount.getValue());
+ break;
+ case IDLE_TIME:
+ U64 idleTime = (U64) ofOxs.getValue();
+ statTriggerMap.put(IDLE_TIME, idleTime.getValue());
+ break;
+ default:
+ log.warn("getStatField not supported {}", ofOxs.getStatField().id);
+ break;
+ }
+ }
+ StatTriggerFlag flag = null;
+ for (OFStatTriggerFlags flags : flagsSet) {
+ switch (flags) {
+ case PERIODIC:
+ flag = PERIODIC;
+ break;
+ case ONLY_FIRST:
+ flag = ONLY_FIRST;
+ break;
+ default:
+ log.warn("flag not supported {}", flags);
+ break;
+ }
+ }
+ if (!statTriggerMap.isEmpty() && flag != null) {
+ builder.add(Instructions.statTrigger(statTriggerMap, flag));
+ }
+ return builder;
+ }
+
/**
* Configures traffic treatment builder with a given collection of actions.
*
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowStatParser.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowStatParser.java
new file mode 100644
index 0000000..dfea390
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowStatParser.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.provider.of.flow.util;
+
+import org.projectfloodlight.openflow.protocol.stat.Stat;
+import org.projectfloodlight.openflow.protocol.stat.StatField;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+
+/**
+ * FlowStatParser helps to parse OXS which is added in OPF 1.5.
+ */
+public final class FlowStatParser {
+ private final Stat stat;
+
+
+ private long duration;
+ private long idleTime;
+ private long flowCount;
+ private long packetCount;
+ private long byteCount;
+ private boolean isDurationReceived;
+
+ public FlowStatParser(Stat stat) {
+ this.stat = stat;
+ parseStats();
+ }
+
+ public Stat getStat() {
+ return stat;
+ }
+
+ private void parseStats() {
+ U64 durationOfValue = this.stat.get(StatField.DURATION);
+ U64 byteCountOfValue = this.stat.get(StatField.BYTE_COUNT);
+ U32 flowCountOfValue = this.stat.get(StatField.FLOW_COUNT);
+ U64 idleTimeOfValue = this.stat.get(StatField.IDLE_TIME);
+ U64 packetCountOfValue = this.stat.get(StatField.PACKET_COUNT);
+
+ isDurationReceived = durationOfValue != null;
+ duration = durationOfValue != null ? durationOfValue.getValue() : 0;
+ byteCount = byteCountOfValue != null ? byteCountOfValue.getValue() : 0;
+ idleTime = idleTimeOfValue != null ? idleTimeOfValue.getValue() : 0;
+ flowCount = flowCountOfValue != null ? flowCountOfValue.getValue() : 0;
+ packetCount = packetCountOfValue != null ? packetCountOfValue.getValue() : 0;
+ }
+
+
+ public long getByteCount() {
+ return byteCount;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public long getFlowCount() {
+ return flowCount;
+ }
+
+ public long getPacketCount() {
+ return packetCount;
+ }
+
+ public long getIdleTime() {
+ return idleTime;
+ }
+
+ public boolean isDurationReceived() {
+ return isDurationReceived;
+ }
+}
diff --git a/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java b/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java
index 3d0dacd..bcacb29 100644
--- a/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java
+++ b/providers/openflow/meter/src/main/java/org/onosproject/provider/of/meter/impl/OpenFlowMeterProvider.java
@@ -339,8 +339,9 @@
meter.setLife(stat.getDurationSec());
meter.setProcessedBytes(stat.getByteInCount().getValue());
meter.setProcessedPackets(stat.getPacketInCount().getValue());
- meter.setReferenceCount(stat.getFlowCount());
-
+ if (stat.getVersion().getWireVersion() < OFVersion.OF_15.getWireVersion()) {
+ meter.setReferenceCount(stat.getFlowCount());
+ }
// marks the meter as seen on the dataplane
pendingOperations.invalidate(stat.getMeterId());
return meter;
diff --git a/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java b/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java
index 0eb0c04..c5e2a87 100644
--- a/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java
+++ b/providers/openflow/packet/src/main/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProvider.java
@@ -40,6 +40,7 @@
import org.onosproject.openflow.controller.PacketListener;
import org.projectfloodlight.openflow.protocol.OFPacketOut;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.ver10.OFFactoryVer10;
import org.projectfloodlight.openflow.types.OFBufferId;
@@ -136,12 +137,14 @@
.buildOutput()
.setPort(out)
.build();
- return builder
- .setBufferId(OFBufferId.NO_BUFFER)
- .setInPort(OFPort.CONTROLLER)
+ builder.setBufferId(OFBufferId.NO_BUFFER)
.setActions(Collections.singletonList(act))
- .setData(eth)
- .build();
+ .setData(eth);
+ if (sw.factory().getVersion().getWireVersion() <= OFVersion.OF_14.getWireVersion()) {
+ builder.setInPort(OFPort.CONTROLLER);
+ }
+
+ return builder.build();
}
/**