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 6c720c859c..8bde2f61d4 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 @@ package org.onosproject.net.flow; 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 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { private final List all; private final Instructions.TableTypeTransition table; private final Instructions.MetadataInstruction meta; + private final Instructions.StatTriggerInstruction statTrigger; private final boolean hasClear; @@ -69,6 +71,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { this.table = null; this.meta = null; this.meter = null; + this.statTrigger = null; } /** @@ -80,11 +83,13 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { * @param clear instruction to clear the deferred actions list */ private DefaultTrafficTreatment(List deferred, - List immediate, - Instructions.TableTypeTransition table, - boolean clear, - Instructions.MetadataInstruction meta, - Instructions.MeterInstruction meter) { + List 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() @@ -95,6 +100,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { this.meta = meta; this.hasClear = clear; this.meter = meter; + this.statTrigger = statTrigger; } @Override @@ -127,6 +133,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { return meta; } + @Override + public Instructions.StatTriggerInstruction statTrigger() { + return statTrigger; + } + @Override public Instructions.MeterInstruction metered() { return meter; @@ -191,6 +202,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { .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 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { Instructions.MeterInstruction meter; + Instructions.StatTriggerInstruction statTrigger; + List deferred = new ArrayList<>(); List immediate = new ArrayList<>(); @@ -259,6 +273,9 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { case METER: meter = (Instructions.MeterInstruction) instruction; break; + case STAT_TRIGGER: + statTrigger = (Instructions.StatTriggerInstruction) instruction; + break; default: throw new IllegalArgumentException("Unknown instruction type: " + instruction.type()); @@ -492,6 +509,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { return add(Instructions.extension(extension, deviceId)); } + @Override + public TrafficTreatment.Builder statTrigger(Map statTriggerFieldMap, + StatTriggerFlag statTriggerFlag) { + return add(Instructions.statTrigger(statTriggerFieldMap, statTriggerFlag)); + } + @Override public TrafficTreatment.Builder addTreatment(TrafficTreatment treatment) { List previous = current; @@ -516,7 +539,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { 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 0000000000..f9465425fb --- /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 0000000000..7ed650c29b --- /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 9ddabe180d..057f0f88db 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; @@ -80,6 +81,12 @@ public interface TrafficTreatment { */ 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. * @@ -421,6 +428,16 @@ public interface TrafficTreatment { */ 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 statTriggerFieldMap, + StatTriggerFlag statTriggerFlag); + /** * Add all instructions from 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 c3c9b60f3f..66fbb1841f 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 @@ public interface Instruction { /** * 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 460976aaad..9bd7df5f9a 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.Lambda; 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.flow.instructions.L4ModificationInstruction.ModTransp 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; @@ -497,6 +501,20 @@ public final class Instructions { return new ExtensionInstructionWrapper(extension, deviceId); } + /** + * 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 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. */ @@ -865,6 +883,68 @@ public final class Instructions { } } + public static class StatTriggerInstruction implements Instruction { + private Map statTriggerFieldMap; + private StatTriggerFlag statTriggerFlag; + + + StatTriggerInstruction(Map statTriggerMap, + StatTriggerFlag flag) { + this.statTriggerFieldMap = ImmutableMap.copyOf(statTriggerMap); + this.statTriggerFlag = flag; + } + + public Map 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 9eada31ae9..ddf6500789 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.GridType; 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.PiActionParam; 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 @@ public class InstructionsTest { 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 statTriggerFieldMap1 = new EnumMap(StatTriggerField.class) { + { + put(StatTriggerField.BYTE_COUNT, packetCountValue1); + put(StatTriggerField.PACKET_COUNT, byteCountValue1); + } + }; + Map statTriggerFieldMap2 = new EnumMap(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 352e2f5384..a05745cae2 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 @@ -112,6 +112,11 @@ public class IntentTestsMocks { return null; } + @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 a9571f9714..ff55e49cf1 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 @@ package org.onosproject.codec.impl; 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.OchSignal; 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.flow.instructions.L4ModificationInstruction; 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 @@ public final class DecodeInstructionCodecHelper { + 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 statThresholdMap = getStatThreshold(statThresholdsNode); + if (statThresholdMap.isEmpty()) { + throw new IllegalArgumentException("statThreshold must have at least one property"); + } + return Instructions.statTrigger(statThresholdMap, flag); + } + + private Map getStatThreshold(JsonNode statThresholdNode) { + Map 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 @@ public final class DecodeInstructionCodecHelper { 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 1f741b5217..9762643445 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 @@ public final class InstructionCodec extends JsonCodec { 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 825ef1aa45..7785a38159 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 @@ -663,6 +663,11 @@ public class FlowRuleManagerTest { return null; } + @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 d5deae1923..6c4ad07e06 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.DefaultTrafficTreatment; 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 @@ public final class KryoNamespaces { .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 c44775544e..584401eb0c 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 @@ -464,6 +464,11 @@ public class VirtualNetworkFlowRuleManagerTest extends VirtualNetworkTestUtil { return null; } + @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 bf0af04966..9bd2146baa 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 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext 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 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext 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 b50bdbc802..05b68a4b11 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.OFCalientFlowStatsReply; 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.OFPacketIn; 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.onlab.util.Tools.groupedThreads; 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 @@ public class OpenFlowControllerImpl implements OpenFlowController { protected Multimap fullFlowStats = ArrayListMultimap.create(); + protected Multimap fullFlowLightweightStats = + ArrayListMultimap.create(); + protected Multimap fullTableStats = ArrayListMultimap.create(); @@ -422,7 +427,17 @@ public class OpenFlowControllerImpl implements OpenFlowController { executorMsgs.execute(new OFMessageHandler(dpid, rep.build())); } break; - + case FLOW_LIGHTWEIGHT: + Collection 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 tableStats = publishTableStats(dpid, (OFTableStatsReply) reply); if (tableStats != null) { @@ -529,6 +544,17 @@ public class OpenFlowControllerImpl implements OpenFlowController { return null; } + private synchronized Collection 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 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 4ec4a69352..a281927f1f 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 @@ public abstract class FlowModBuilder { 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 5381af71e3..ad601c98cc 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 @@ import java.util.Optional; */ 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 @@ public class FlowModBuilderVer13 extends FlowModBuilder { 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 @@ public class FlowModBuilderVer13 extends FlowModBuilder { 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 @@ public class FlowModBuilderVer13 extends FlowModBuilder { 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 @@ public class FlowModBuilderVer13 extends FlowModBuilder { return null; } - private OFAction buildL3Modification(Instruction i) { + protected OFAction buildL3Modification(Instruction i) { L3ModificationInstruction l3m = (L3ModificationInstruction) i; ModIPInstruction ip; Ip4Address ip4; @@ -493,7 +493,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder { 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 @@ public class FlowModBuilderVer13 extends FlowModBuilder { 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 0000000000..7ba893a0c2 --- /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 xid, + Optional driverService) { + super(flowRule, factory, xid, driverService); + } + + @Override + public OFFlowMod buildFlowAdd() { + Match match = buildMatch(); + List deferredActions = buildActions(treatment.deferred(), false); + List immediateActions = buildActions(treatment.immediate(), true); + List 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 deferredActions = buildActions(treatment.deferred(), false); + List immediateActions = buildActions(treatment.immediate(), true); + List 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 buildActions(List treatments, Boolean immediateActions) { + if (treatment == null) { + return Collections.emptyList(); + } + + boolean tableFound = false; + List 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 statTriggerMap) { + OFFactory factory = factory(); + List> ofOxsList = Lists.newArrayList(); + for (Map.Entry 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 getStatTriggerFlag(StatTriggerFlag flag) { + Set 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 9dc03cdc7e..7f472adfd4 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.osgi.service.component.ComponentContext; 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 @@ public class OpenFlowRuleProvider extends AbstractProvider private final Timer timer = new Timer("onos-openflow-collector"); + // Old simple collector set private final Map simpleCollectors = Maps.newConcurrentMap(); @@ -441,6 +443,8 @@ public class OpenFlowRuleProvider extends AbstractProvider 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 @@ public class OpenFlowRuleProvider extends AbstractProvider 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 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 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 083a74c0bb..c16c34f344 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.DefaultTrafficTreatment; 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.net.flow.instructions.Instructions; 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.action.OFActionSetVlanVid; 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.Logger; 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 @@ public class FlowEntryBuilder { private final OFFlowStatsEntry stat; private final OFFlowRemoved removed; private final OFFlowMod flowMod; + private final OFFlowLightweightStatsEntry lightWeightStat; private final Match match; @@ -120,7 +135,7 @@ public class FlowEntryBuilder { 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 @@ public class FlowEntryBuilder { 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 @@ public class FlowEntryBuilder { 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 @@ public class FlowEntryBuilder { this.removed = null; this.driverService = driverService; this.afsc = null; + this.lightWeightStat = null; } public FlowEntryBuilder withSetAfsc(NewAdaptiveFlowStatsCollector afsc) { @@ -172,83 +204,16 @@ public class FlowEntryBuilder { } 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 @@ public class FlowEntryBuilder { } + 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 getInstructions(OFFlowMod entry) { switch (entry.getVersion()) { case OF_10: @@ -321,6 +423,10 @@ public class FlowEntryBuilder { 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 @@ public class FlowEntryBuilder { return builder.build(); } + private TrafficTreatment.Builder buildStatTrigger(OFOxsList oxsList, + Set flagsSet, + TrafficTreatment.Builder builder) { + Map 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 0000000000..dfea3901db --- /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 3d0dacd535..bcacb294bd 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 @@ public class OpenFlowMeterProvider extends AbstractProvider implements MeterProv 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 0eb0c04b58..c5e2a87cbe 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.OpenFlowSwitch; 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 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr .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(); } /**