mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 12:16:13 +02:00
ONOS-7077 Openflow 1.5 OXS and stat trigger support
Change-Id: I006bcd3d8eac451a780c7e5c69a12298ead14281
This commit is contained in:
parent
3ba06869ec
commit
3baff6785f
@ -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<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 @@ 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<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 @@ 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<Instruction> deferred = new ArrayList<>();
|
||||
|
||||
List<Instruction> 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<StatTriggerField, Long> statTriggerFieldMap,
|
||||
StatTriggerFlag statTriggerFlag) {
|
||||
return add(Instructions.statTrigger(statTriggerFieldMap, statTriggerFlag));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrafficTreatment.Builder addTreatment(TrafficTreatment treatment) {
|
||||
List<Instruction> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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<StatTriggerField, Long> statTriggerFieldMap,
|
||||
StatTriggerFlag statTriggerFlag);
|
||||
|
||||
/**
|
||||
* Add all instructions from another treatment.
|
||||
*
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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<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.
|
||||
*/
|
||||
@ -865,6 +883,68 @@ public final class Instructions {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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<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);
|
||||
|
||||
@ -112,6 +112,11 @@ public class IntentTestsMocks {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instructions.StatTriggerInstruction statTrigger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instructions.MeterInstruction metered() {
|
||||
return null;
|
||||
|
||||
@ -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<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 @@ 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");
|
||||
|
||||
@ -59,6 +59,11 @@ public final class InstructionCodec extends JsonCodec<Instruction> {
|
||||
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";
|
||||
|
||||
@ -663,6 +663,11 @@ public class FlowRuleManagerTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instructions.StatTriggerInstruction statTrigger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instructions.MeterInstruction metered() {
|
||||
return null;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<Dpid, OFFlowStatsEntry> fullFlowStats =
|
||||
ArrayListMultimap.create();
|
||||
|
||||
protected Multimap<Dpid, OFFlowLightweightStatsEntry> fullFlowLightweightStats =
|
||||
ArrayListMultimap.create();
|
||||
|
||||
protected Multimap<Dpid, OFTableStatsEntry> fullTableStats =
|
||||
ArrayListMultimap.create();
|
||||
|
||||
@ -422,7 +427,17 @@ public class OpenFlowControllerImpl implements OpenFlowController {
|
||||
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 @@ public class OpenFlowControllerImpl implements OpenFlowController {
|
||||
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
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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<Dpid, FlowStatsCollector> 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<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;
|
||||
|
||||
@ -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<OFInstruction> 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<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.
|
||||
*
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user