Jonathan Hart
Committed by Gerrit Code Review

Generic extensions to the treatment API to support protocol extensions like

OF experimenter actions.

Change-Id: I88cc5896d17fdbf89807f911f9c23e4f19f6a5ad
Showing 21 changed files with 842 additions and 43 deletions
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.behaviour;
import com.google.common.annotations.Beta;
import org.onosproject.net.driver.HandlerBehaviour;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.ExtensionType;
/**
* Provides access to the extension implemented by this driver.
*/
@Beta
public interface ExtensionResolver extends HandlerBehaviour {
/**
* Gets an extension instruction instance of the specified type, if supported
* by the driver.
*
* @param type type of extension to get
* @return extension instruction
* @throws UnsupportedOperationException if the extension type is not
* supported by this driver
*/
ExtensionInstruction getExtensionInstruction(ExtensionType type);
}
......@@ -27,8 +27,10 @@ import org.onlab.packet.MplsLabel;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.IndexedLambda;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.meter.MeterId;
......@@ -244,6 +246,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
case L2MODIFICATION:
case L3MODIFICATION:
case L4MODIFICATION:
case EXTENSION:
current.add(instruction);
break;
case TABLE:
......@@ -481,6 +484,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public TrafficTreatment.Builder extension(ExtensionInstruction extension,
DeviceId deviceId) {
return add(Instructions.extension(extension, deviceId));
}
@Override
public TrafficTreatment build() {
if (deferred.size() == 0 && immediate.size() == 0
&& table == null && !clear) {
......
......@@ -24,7 +24,9 @@ import org.onlab.packet.MplsLabel;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.meter.MeterId;
......@@ -413,6 +415,15 @@ public interface TrafficTreatment {
Builder setUdpDst(TpPort port);
/**
* Uses an extension treatment.
*
* @param extension extension treatment
* @param deviceId device ID
* @return a treatment builder
*/
Builder extension(ExtensionInstruction extension, DeviceId deviceId);
/**
* Builds an immutable traffic treatment descriptor.
* <p>
* If the treatment is empty when build() is called, it will add a default
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.instructions;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Abstract implementation of the set/get property methods of ExtensionInstruction.
*/
public abstract class AbstractExtensionInstruction implements ExtensionInstruction {
private static final String INVALID_KEY = "Invalid property key: ";
private static final String INVALID_TYPE = "Given type does not match field type: ";
@Override
public <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException {
Class<?> clazz = this.getClass();
try {
Field field = clazz.getDeclaredField(key);
field.setAccessible(true);
field.set(this, value);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExtensionPropertyException(INVALID_KEY + key);
}
}
@Override
public <T> T getPropertyValue(String key) throws ExtensionPropertyException {
Class<?> clazz = this.getClass();
try {
Field field = clazz.getDeclaredField(key);
field.setAccessible(true);
@SuppressWarnings("unchecked")
T result = (T) field.get(this);
return result;
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExtensionPropertyException(INVALID_KEY + key);
} catch (ClassCastException e) {
throw new ExtensionPropertyException(INVALID_TYPE + key);
}
}
@Override
public List<String> getProperties() {
Class<?> clazz = this.getClass();
List<String> fields = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
fields.add(field.getName());
}
return fields;
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.instructions;
import java.util.List;
/**
* An extensible instruction type.
*/
public interface ExtensionInstruction {
/**
* Gets the type of the extension instruction.
*
* @return type
*/
ExtensionType type();
/**
* Sets a property on the extension instruction.
*
* @param key property key
* @param value value to set for the given key
* @param <T> class of the value
* @throws ExtensionPropertyException if the given key is not a valid
* property on this extension instruction
*/
<T> void setPropertyValue(String key, T value) throws ExtensionPropertyException;
/**
* Gets a property value of an extension instruction.
*
* @param key property key
* @param <T> class of the value
* @return value of the property
* @throws ExtensionPropertyException if the given key is not a valid
* property on this extension instruction
*/
<T> T getPropertyValue(String key) throws ExtensionPropertyException;
/**
* Gets a list of all properties on the extension instruction.
*
* @return list of properties
*/
List<String> getProperties();
/**
* Serialize the extension instruction to a byte array.
*
* @return byte array
*/
byte[] serialize();
/**
* Deserialize the extension instruction from a byte array. The properties
* of this object will be overwritten with the data in the byte array.
*
* @param data input byte array
*/
void deserialize(byte[] data);
}
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.instructions;
/**
* Exception indicating there was an error while setting/getting an extension
* instruction property.
*/
public class ExtensionPropertyException extends Exception {
public ExtensionPropertyException(String message) {
super(message);
}
public ExtensionPropertyException(String message, Throwable cause) {
super(message, cause);
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.instructions;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import java.util.Objects;
/**
* Type of extension instructions.
*/
@Beta
public final class ExtensionType {
/**
* A list of well-known named extension instruction type codes.
*/
public enum ExtensionTypes {
// TODO fix type numbers to include experimenter id
NICIRA_SET_TUNNEL_DST(31);
private ExtensionType type;
/**
* Creates a new named extension instruction type.
*
* @param type type code
*/
ExtensionTypes(int type) {
this.type = new ExtensionType(type);
}
/**
* Gets the extension type object for this named type code.
*
* @return extension type object
*/
public ExtensionType type() {
return type;
}
}
private final int type;
/**
* Creates an extension type with the given int type code.
*
* @param type type code
*/
public ExtensionType(int type) {
this.type = type;
}
@Override
public int hashCode() {
return Objects.hash(type);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ExtensionType) {
final ExtensionType that = (ExtensionType) obj;
return this.type == that.type;
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(ExtensionType.class)
.add("type", type)
.toString();
}
}
......@@ -92,7 +92,12 @@ public interface Instruction {
/**
* Signifies that the traffic should be modified in L4 way.
*/
L4MODIFICATION
L4MODIFICATION,
/**
* Signifies that an extension instruction will be used.
*/
EXTENSION
}
/**
......
......@@ -22,6 +22,7 @@ import org.onlab.packet.MplsLabel;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.IndexedLambda;
import org.onosproject.net.Lambda;
import org.onosproject.net.OchSignal;
......@@ -480,6 +481,20 @@ public final class Instructions {
}
/**
* Creates an extension instruction.
*
* @param extension extension instruction
* @param deviceId device ID
* @return extension instruction
*/
public static ExtensionInstructionWrapper extension(ExtensionInstruction extension,
DeviceId deviceId) {
checkNotNull(extension, "Extension instruction cannot be null");
checkNotNull(deviceId, "Device ID cannot be null");
return new ExtensionInstructionWrapper(extension, deviceId);
}
/**
* Drop instruction.
*/
@Deprecated
......@@ -820,6 +835,59 @@ public final class Instructions {
}
}
/**
* Extension instruction.
*/
public static class ExtensionInstructionWrapper implements Instruction {
private final ExtensionInstruction extensionInstruction;
private final DeviceId deviceId;
ExtensionInstructionWrapper(ExtensionInstruction extension, DeviceId deviceId) {
extensionInstruction = extension;
this.deviceId = deviceId;
}
public ExtensionInstruction extensionInstruction() {
return extensionInstruction;
}
public DeviceId deviceId() {
return deviceId;
}
@Override
public Type type() {
return Type.EXTENSION;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("extension", extensionInstruction)
.add("deviceId", deviceId)
.toString();
}
@Override
public int hashCode() {
return Objects.hash(type().ordinal(), extensionInstruction, deviceId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ExtensionInstructionWrapper) {
ExtensionInstructionWrapper that = (ExtensionInstructionWrapper) obj;
return Objects.equals(extensionInstruction, that.extensionInstruction)
&& Objects.equals(deviceId, that.deviceId);
}
return false;
}
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.store.serializers;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.ExtensionResolver;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.ExtensionType;
import org.onosproject.net.flow.instructions.Instructions;
/**
* Created by jono on 10/29/15.
*/
public class ExtensionInstructionSerializer extends
Serializer<Instructions.ExtensionInstructionWrapper> {
public ExtensionInstructionSerializer() {
super(false, true);
}
@Override
public void write(Kryo kryo, Output output, Instructions.ExtensionInstructionWrapper object) {
kryo.writeClassAndObject(output, object.extensionInstruction().type());
kryo.writeClassAndObject(output, object.deviceId());
kryo.writeClassAndObject(output, object.extensionInstruction().serialize());
}
@Override
public Instructions.ExtensionInstructionWrapper read(Kryo kryo, Input input,
Class<Instructions.ExtensionInstructionWrapper> type) {
ExtensionType exType = (ExtensionType) kryo.readClassAndObject(input);
DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
DriverService driverService = DefaultServiceDirectory.getService(DriverService.class);
DriverHandler handler = new DefaultDriverHandler(
new DefaultDriverData(driverService.getDriver(deviceId), deviceId));
ExtensionResolver resolver = handler.behaviour(ExtensionResolver.class);
ExtensionInstruction instruction = resolver.getExtensionInstruction(exType);
byte[] bytes = (byte[]) kryo.readClassAndObject(input);
instruction.deserialize(bytes);
return Instructions.extension(instruction, deviceId);
}
}
......@@ -128,6 +128,7 @@ import org.onosproject.net.flow.criteria.TunnelIdCriterion;
import org.onosproject.net.flow.criteria.UdpPortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.criteria.VlanPcpCriterion;
import org.onosproject.net.flow.instructions.ExtensionType;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.L0ModificationInstruction;
import org.onosproject.net.flow.instructions.L1ModificationInstruction;
......@@ -450,6 +451,8 @@ public final class KryoNamespaces {
.register(new HostLocationSerializer(), HostLocation.class)
.register(new DefaultOutboundPacketSerializer(), DefaultOutboundPacket.class)
.register(new AnnotationsSerializer(), DefaultAnnotations.class)
.register(new ExtensionInstructionSerializer(), Instructions.ExtensionInstructionWrapper.class)
.register(ExtensionType.class)
.register(Versioned.class)
.register(MapEvent.class)
.register(MapEvent.Type.class)
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.driver.extensions;
import org.onlab.packet.Ip4Address;
import org.onosproject.net.behaviour.ExtensionResolver;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.ExtensionType;
import org.onosproject.openflow.controller.ExtensionInterpreter;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst;
import org.projectfloodlight.openflow.types.IPv4Address;
/**
* Interpreter for Nicira OpenFlow extensions.
*/
public class NiciraExtensionInterpreter extends AbstractHandlerBehaviour
implements ExtensionInterpreter, ExtensionResolver {
@Override
public boolean supported(ExtensionType extensionType) {
if (extensionType.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST)) {
return true;
}
return false;
}
@Override
public OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction) {
ExtensionType type = extensionInstruction.type();
if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) {
NiciraSetTunnelDst tunnelDst = (NiciraSetTunnelDst) extensionInstruction;
return factory.actions().setField(factory.oxms().tunnelIpv4Dst(
IPv4Address.of(tunnelDst.tunnelDst().toInt())));
}
return null;
}
@Override
public ExtensionInstruction mapAction(OFAction action) {
if (action.getType().equals(OFActionType.SET_FIELD)) {
OFActionSetField setFieldAction = (OFActionSetField) action;
OFOxm<?> oxm = setFieldAction.getField();
switch (oxm.getMatchField().id) {
case TUNNEL_IPV4_DST:
OFOxmTunnelIpv4Dst tunnelIpv4Dst = (OFOxmTunnelIpv4Dst) oxm;
return new NiciraSetTunnelDst(Ip4Address.valueOf(tunnelIpv4Dst.getValue().getInt()));
default:
throw new UnsupportedOperationException(
"Driver does not support extension type " + oxm.getMatchField().id);
}
}
return null;
}
@Override
public ExtensionInstruction getExtensionInstruction(ExtensionType type) {
if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) {
return new NiciraSetTunnelDst();
}
throw new UnsupportedOperationException(
"Driver does not support extension type " + type.toString());
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.driver.extensions;
import com.google.common.base.MoreObjects;
import org.onlab.packet.Ip4Address;
import org.onlab.util.KryoNamespace;
import org.onosproject.net.flow.instructions.AbstractExtensionInstruction;
import org.onosproject.net.flow.instructions.ExtensionType;
import org.onosproject.store.serializers.Ip4AddressSerializer;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Nicira set tunnel destination extension instruction.
*/
public class NiciraSetTunnelDst extends AbstractExtensionInstruction {
private Ip4Address tunnelDst;
private final KryoNamespace appKryo = new KryoNamespace.Builder()
.register(new Ip4AddressSerializer(), Ip4Address.class)
.register(byte[].class)
.build();
/**
* Creates a new set tunnel destination instruction.
*/
NiciraSetTunnelDst() {
tunnelDst = null;
}
/**
* Creates a new set tunnel destination instruction with a particular IPv4
* address.
*/
NiciraSetTunnelDst(Ip4Address tunnelDst) {
checkNotNull(tunnelDst);
this.tunnelDst = tunnelDst;
}
/**
* Gets the tunnel destination IPv4 address.
*
* @return tunnel destination IPv4 address
*/
public Ip4Address tunnelDst() {
return tunnelDst;
}
@Override
public ExtensionType type() {
return ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type();
}
@Override
public void deserialize(byte[] data) {
tunnelDst = appKryo.deserialize(data);
}
@Override
public byte[] serialize() {
return appKryo.serialize(tunnelDst);
}
@Override
public int hashCode() {
return Objects.hash(tunnelDst);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof NiciraSetTunnelDst) {
NiciraSetTunnelDst that = (NiciraSetTunnelDst) obj;
return Objects.equals(tunnelDst, that.tunnelDst);
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("tunnelDst", tunnelDst)
.toString();
}
}
......@@ -32,6 +32,10 @@
impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
<behaviour api="org.onosproject.net.behaviour.ControllerConfig"
impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/>
<behaviour api="org.onosproject.openflow.controller.ExtensionInterpreter"
impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
<behaviour api="org.onosproject.net.behaviour.ExtensionResolver"
impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
</driver>
<driver name="ovs-corsa" extends="ovs"
manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
......
/*
* Copyright 2015 Open Networking Laboratory
*
* 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.openflow.controller;
import com.google.common.annotations.Beta;
import org.onosproject.net.driver.HandlerBehaviour;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.ExtensionType;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.action.OFAction;
/**
* Interprets extension instructions and converts them to/from OpenFlow objects.
*/
@Beta
public interface ExtensionInterpreter extends HandlerBehaviour {
/**
* Returns true if the given extension instruction is supported by this
* driver.
*
* @param extensionType extension instruction type
* @return true if the instruction is supported, otherwise false
*/
boolean supported(ExtensionType extensionType);
/**
* Maps an extension instruction to an OpenFlow action.
*
* @param factory OpenFlow factory
* @param extensionInstruction extension instruction
* @return OpenFlow action
*/
OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction);
/**
* Maps an OpenFlow action to an extension instruction.
*
* @param action OpenFlow action
* @return extension instruction
*/
ExtensionInstruction mapAction(OFAction action);
}
......@@ -28,6 +28,11 @@ import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Lambda;
import org.onosproject.net.PortNumber;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
......@@ -39,6 +44,7 @@ import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.ExtensionInterpreter;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
......@@ -106,7 +112,9 @@ public class FlowEntryBuilder {
private final FlowType type;
public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) {
private final DriverService driverService;
public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry, DriverService driverService) {
this.stat = entry;
this.match = entry.getMatch();
this.instructions = getInstructions(entry);
......@@ -114,9 +122,10 @@ public class FlowEntryBuilder {
this.removed = null;
this.flowMod = null;
this.type = FlowType.STAT;
this.driverService = driverService;
}
public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) {
public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed, DriverService driverService) {
this.match = removed.getMatch();
this.removed = removed;
......@@ -125,10 +134,10 @@ public class FlowEntryBuilder {
this.stat = null;
this.flowMod = null;
this.type = FlowType.REMOVED;
this.driverService = driverService;
}
public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) {
public FlowEntryBuilder(Dpid dpid, OFFlowMod fm, DriverService driverService) {
this.match = fm.getMatch();
this.dpid = dpid;
this.instructions = getInstructions(fm);
......@@ -136,6 +145,7 @@ public class FlowEntryBuilder {
this.flowMod = fm;
this.stat = null;
this.removed = null;
this.driverService = driverService;
}
public FlowEntry build(FlowEntryState... state) {
......@@ -307,7 +317,7 @@ public class FlowEntryBuilder {
break;
case SET_FIELD:
OFActionSetField setField = (OFActionSetField) act;
handleSetField(builder, setField.getField());
handleSetField(builder, setField);
break;
case POP_MPLS:
OFActionPopMpls popMpls = (OFActionPopMpls) act;
......@@ -363,7 +373,8 @@ public class FlowEntryBuilder {
}
private void handleSetField(TrafficTreatment.Builder builder, OFOxm<?> oxm) {
private void handleSetField(TrafficTreatment.Builder builder, OFActionSetField action) {
OFOxm<?> oxm = action.getField();
switch (oxm.getMatchField().id) {
case VLAN_PCP:
@SuppressWarnings("unchecked")
......@@ -432,6 +443,13 @@ public class FlowEntryBuilder {
OFOxm<TransportPort> udpsrc = (OFOxm<TransportPort>) oxm;
builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort()));
break;
case TUNNEL_IPV4_DST:
DriverHandler driver = getDriver(dpid);
ExtensionInterpreter interpreter = driver.behaviour(ExtensionInterpreter.class);
if (interpreter != null) {
builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid)));
}
break;
case ARP_OP:
case ARP_SHA:
case ARP_SPA:
......@@ -697,4 +715,11 @@ public class FlowEntryBuilder {
}
return builder.build();
}
private DriverHandler getDriver(Dpid dpid) {
DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
Driver driver = driverService.getDriver(deviceId);
DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
return handler;
}
}
......
......@@ -15,16 +15,13 @@
*/
package org.onosproject.provider.of.flow.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Optional;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.Ip6Prefix;
import org.onlab.packet.VlanId;
import org.onosproject.net.OchSignal;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
......@@ -85,6 +82,10 @@ import org.projectfloodlight.openflow.types.VlanPcp;
import org.projectfloodlight.openflow.types.VlanVid;
import org.slf4j.Logger;
import java.util.Optional;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Builder for OpenFlow flow mods based on FlowRules.
*/
......@@ -96,6 +97,7 @@ public abstract class FlowModBuilder {
private final FlowRule flowRule;
private final TrafficSelector selector;
protected final Long xid;
protected final Optional<DriverService> driverService;
/**
* Creates a new flow mod builder.
......@@ -107,12 +109,13 @@ public abstract class FlowModBuilder {
*/
public static FlowModBuilder builder(FlowRule flowRule,
OFFactory factory,
Optional<Long> xid) {
Optional<Long> xid,
Optional<DriverService> driverService) {
switch (factory.getVersion()) {
case OF_10:
return new FlowModBuilderVer10(flowRule, factory, xid);
return new FlowModBuilderVer10(flowRule, factory, xid, driverService);
case OF_13:
return new FlowModBuilderVer13(flowRule, factory, xid);
return new FlowModBuilderVer13(flowRule, factory, xid, driverService);
default:
throw new UnsupportedOperationException(
"No flow mod builder for protocol version " + factory.getVersion());
......@@ -126,12 +129,13 @@ public abstract class FlowModBuilder {
* @param factory the OpenFlow factory to use to build the flow mod
* @param xid the transaction ID
*/
protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid,
Optional<DriverService> driverService) {
this.factory = factory;
this.flowRule = flowRule;
this.selector = flowRule.selector();
this.xid = xid.orElse(0L);
this.driverService = driverService;
}
/**
......
......@@ -17,6 +17,7 @@ package org.onosproject.provider.of.flow.impl;
import org.onlab.packet.Ip4Address;
import org.onosproject.net.PortNumber;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.Instruction;
......@@ -68,8 +69,9 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
* @param xid the transaction ID
*/
protected FlowModBuilderVer10(FlowRule flowRule,
OFFactory factory, Optional<Long> xid) {
super(flowRule, factory, xid);
OFFactory factory, Optional<Long> xid,
Optional<DriverService> driverService) {
super(flowRule, factory, xid, driverService);
this.treatment = flowRule.treatment();
}
......
......@@ -18,10 +18,16 @@ package org.onosproject.provider.of.flow.impl;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip6Address;
import org.onosproject.net.DeviceId;
import org.onosproject.net.OchSignal;
import org.onosproject.net.PortNumber;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.ExtensionInstruction;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
......@@ -34,15 +40,16 @@ import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
import org.onosproject.net.flow.instructions.L4ModificationInstruction;
import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
import org.onosproject.openflow.controller.ExtensionInterpreter;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFlowAdd;
import org.projectfloodlight.openflow.protocol.OFFlowDelete;
......@@ -88,6 +95,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
private static final int OFPCML_NO_BUFFER = 0xffff;
private final TrafficTreatment treatment;
private final DeviceId deviceId;
/**
* Constructor for a flow mod builder for OpenFlow 1.3.
......@@ -96,10 +104,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
* @param factory the OpenFlow factory to use to build the flow mod
* @param xid the transaction ID
*/
protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
super(flowRule, factory, xid);
protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid,
Optional<DriverService> driverService) {
super(flowRule, factory, xid, driverService);
this.treatment = flowRule.treatment();
this.deviceId = flowRule.deviceId();
}
@Override
......@@ -256,6 +266,10 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
//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());
}
......@@ -467,4 +481,20 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
return null;
}
private OFAction buildExtensionAction(ExtensionInstruction i) {
if (!driverService.isPresent()) {
log.error("No driver service present");
return null;
}
Driver driver = driverService.get().getDriver(deviceId);
if (driver.hasBehaviour(ExtensionInterpreter.class)) {
DefaultDriverHandler handler =
new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
ExtensionInterpreter interpreter = handler.behaviour(ExtensionInterpreter.class);
return interpreter.mapInstruction(factory(), i);
}
return null;
}
}
......
......@@ -16,21 +16,10 @@
package org.onosproject.provider.of.flow.impl;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.onosproject.net.flow.DefaultTypedFlowEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
......@@ -47,9 +36,19 @@ import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TableId;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.flow.TypedStoredFlowEntry.*;
import static org.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType;
import static org.slf4j.LoggerFactory.getLogger;
/**
......@@ -232,7 +231,8 @@ public class NewAdaptiveFlowStatsCollector {
// send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw
private void ofFlowStatsRequestFlowSend(FlowEntry fe) {
// set find match
Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty()).buildMatch();
Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(),
Optional.empty()).buildMatch();
// set find tableId
TableId tableId = TableId.of(fe.tableId());
// set output port
......
......@@ -21,7 +21,6 @@ import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -32,6 +31,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.DefaultTableStatisticsEntry;
import org.onosproject.net.flow.FlowEntry;
......@@ -61,12 +61,12 @@ import org.projectfloodlight.openflow.protocol.OFErrorType;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsType;
import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
import org.slf4j.Logger;
......@@ -106,6 +106,9 @@ public class OpenFlowRuleProvider extends AbstractProvider
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
private static final int DEFAULT_POLL_FREQUENCY = 5;
@Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
label = "Frequency (in seconds) for polling flow statistics")
......@@ -269,7 +272,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
return;
}
sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Optional.empty()).buildFlowAdd());
Optional.empty(), Optional.of(driverService)).buildFlowAdd());
if (adaptiveFlowSampling) {
// Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
......@@ -298,7 +301,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
return;
}
sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Optional.empty()).buildFlowDel());
Optional.empty(), Optional.of(driverService)).buildFlowDel());
if (adaptiveFlowSampling) {
// Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
......@@ -334,7 +337,8 @@ public class OpenFlowRuleProvider extends AbstractProvider
continue;
}
FlowModBuilder builder =
FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id()));
FlowModBuilder.builder(fbe.target(), sw.factory(),
Optional.of(batch.id()), Optional.of(driverService));
NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
switch (fbe.operator()) {
case ADD:
......@@ -423,7 +427,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
case FLOW_REMOVED:
OFFlowRemoved removed = (OFFlowRemoved) msg;
FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
FlowEntry fr = new FlowEntryBuilder(dpid, removed, driverService).build();
providerService.flowRemoved(fr);
if (adaptiveFlowSampling) {
......@@ -474,7 +478,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
InternalCacheEntry entry =
pendingBatches.getIfPresent(msg.getXid());
if (entry != null) {
entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
entry.appendFailure(new FlowEntryBuilder(dpid, fm, driverService).build());
} else {
log.error("No matching batch for this error: {}", error);
}
......@@ -501,7 +505,7 @@ public class OpenFlowRuleProvider extends AbstractProvider
DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
List<FlowEntry> flowEntries = replies.getEntries().stream()
.map(entry -> new FlowEntryBuilder(dpid, entry).build())
.map(entry -> new FlowEntryBuilder(dpid, entry, driverService).build())
.collect(Collectors.toList());
if (adaptiveFlowSampling) {
......