ONOS-7077 Openflow 1.5 OXS and stat trigger support

Change-Id: I006bcd3d8eac451a780c7e5c69a12298ead14281
This commit is contained in:
Cem Türker 2017-10-12 15:09:01 +03:00 committed by Yuta HIGUCHI
parent 3ba06869ec
commit 3baff6785f
23 changed files with 1051 additions and 121 deletions

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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.
*

View File

@ -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
}
/**

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -112,6 +112,11 @@ public class IntentTestsMocks {
return null;
}
@Override
public Instructions.StatTriggerInstruction statTrigger() {
return null;
}
@Override
public Instructions.MeterInstruction metered() {
return null;

View File

@ -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");

View File

@ -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";

View File

@ -663,6 +663,11 @@ public class FlowRuleManagerTest {
return null;
}
@Override
public Instructions.StatTriggerInstruction statTrigger() {
return null;
}
@Override
public Instructions.MeterInstruction metered() {
return null;

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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.
*

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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();
}
/**