From 13d05bc8458758ee39cb829098241e89616717ee Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Wed, 9 Sep 2015 22:15:21 -0700 Subject: ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60 Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd --- framework/src/onos/providers/openflow/flow/pom.xml | 40 ++ .../provider/of/flow/impl/FlowEntryBuilder.java | 707 +++++++++++++++++++++ .../provider/of/flow/impl/FlowModBuilder.java | 444 +++++++++++++ .../provider/of/flow/impl/FlowModBuilderVer10.java | 230 +++++++ .../provider/of/flow/impl/FlowModBuilderVer13.java | 458 +++++++++++++ .../provider/of/flow/impl/FlowStatsCollector.java | 100 +++ .../of/flow/impl/NoMappingFoundException.java | 31 + .../of/flow/impl/OpenFlowRuleProvider.java | 453 +++++++++++++ .../provider/of/flow/impl/OpenFlowValueMapper.java | 152 +++++ .../provider/of/flow/impl/package-info.java | 20 + 10 files changed, 2635 insertions(+) create mode 100644 framework/src/onos/providers/openflow/flow/pom.xml create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java create mode 100644 framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java (limited to 'framework/src/onos/providers/openflow/flow') diff --git a/framework/src/onos/providers/openflow/flow/pom.xml b/framework/src/onos/providers/openflow/flow/pom.xml new file mode 100644 index 00000000..24c430e3 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/pom.xml @@ -0,0 +1,40 @@ + + + + 4.0.0 + + + org.onosproject + onos-of-providers + 1.3.0-SNAPSHOT + ../pom.xml + + + onos-of-provider-flow + bundle + + ONOS OpenFlow protocol flow provider + + + + org.osgi + org.osgi.compendium + + + diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java new file mode 100644 index 00000000..f238bdb1 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java @@ -0,0 +1,707 @@ +/* + * Copyright 2014-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.provider.of.flow.impl; + +import static org.onosproject.net.flow.criteria.Criteria.matchLambda; +import static org.onosproject.net.flow.criteria.Criteria.matchOchSignalType; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupChannelSpacing; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupGridType; +import static org.onosproject.provider.of.flow.impl.OpenFlowValueMapper.lookupOchSignalType; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.List; + +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.Ip6Prefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Lambda; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultFlowEntry; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +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.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.openflow.controller.Dpid; +import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.OFFlowRemoved; +import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionCircuit; +import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter; +import org.projectfloodlight.openflow.protocol.action.OFActionGroup; +import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls; +import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst; +import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc; +import org.projectfloodlight.openflow.protocol.action.OFActionSetField; +import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst; +import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc; +import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp; +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.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.OFOxmOchSigidBasic; +import org.projectfloodlight.openflow.protocol.ver13.OFFactoryVer13; +import org.projectfloodlight.openflow.types.CircuitSignalID; +import org.projectfloodlight.openflow.types.EthType; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; +import org.projectfloodlight.openflow.types.Masked; +import org.projectfloodlight.openflow.types.OFVlanVidMatch; +import org.projectfloodlight.openflow.types.TransportPort; +import org.projectfloodlight.openflow.types.U32; +import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.U8; +import org.projectfloodlight.openflow.types.VlanPcp; +import org.slf4j.Logger; + +import com.google.common.collect.Lists; + +public class FlowEntryBuilder { + private final Logger log = getLogger(getClass()); + + private final OFFlowStatsEntry stat; + private final OFFlowRemoved removed; + private final OFFlowMod flowMod; + + private final Match match; + + // All actions are contained in an OFInstruction. For OF1.0 + // the instruction type is apply instruction (immediate set in ONOS speak) + private final List instructions; + + private final Dpid dpid; + + public enum FlowType { STAT, REMOVED, MOD } + + private final FlowType type; + + public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) { + this.stat = entry; + this.match = entry.getMatch(); + this.instructions = getInstructions(entry); + this.dpid = dpid; + this.removed = null; + this.flowMod = null; + this.type = FlowType.STAT; + } + + public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) { + this.match = removed.getMatch(); + this.removed = removed; + + this.dpid = dpid; + this.instructions = null; + this.stat = null; + this.flowMod = null; + this.type = FlowType.REMOVED; + + } + + public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) { + this.match = fm.getMatch(); + this.dpid = dpid; + this.instructions = getInstructions(fm); + this.type = FlowType.MOD; + this.flowMod = fm; + this.stat = null; + this.removed = null; + } + + public FlowEntry build(FlowEntryState... state) { + FlowRule rule; + switch (this.type) { + case STAT: + rule = DefaultFlowRule.builder() + .forDevice(DeviceId.deviceId(Dpid.uri(dpid))) + .withSelector(buildSelector()) + .withTreatment(buildTreatment()) + .withPriority(stat.getPriority()) + .makeTemporary(stat.getIdleTimeout()) + .withCookie(stat.getCookie().getValue()) + .forTable(stat.getTableId().getValue()) + .build(); + + return new DefaultFlowEntry(rule, FlowEntryState.ADDED, + stat.getDurationSec(), stat.getPacketCount().getValue(), + stat.getByteCount().getValue()); + case REMOVED: + rule = DefaultFlowRule.builder() + .forDevice(DeviceId.deviceId(Dpid.uri(dpid))) + .withSelector(buildSelector()) + .withPriority(removed.getPriority()) + .makeTemporary(removed.getIdleTimeout()) + .withCookie(removed.getCookie().getValue()) + .forTable(removed.getTableId().getValue()) + .build(); + + return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(), + removed.getPacketCount().getValue(), removed.getByteCount().getValue()); + case MOD: + FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED; + rule = DefaultFlowRule.builder() + .forDevice(DeviceId.deviceId(Dpid.uri(dpid))) + .withSelector(buildSelector()) + .withTreatment(buildTreatment()) + .withPriority(flowMod.getPriority()) + .makeTemporary(flowMod.getIdleTimeout()) + .withCookie(flowMod.getCookie().getValue()) + .forTable(flowMod.getTableId().getValue()) + .build(); + + return new DefaultFlowEntry(rule, flowState, 0, 0, 0); + default: + log.error("Unknown flow type : {}", this.type); + return null; + } + + } + + private List getInstructions(OFFlowMod entry) { + switch (entry.getVersion()) { + case OF_10: + return Lists.newArrayList(OFFactoryVer13.INSTANCE.instructions() + .applyActions( + entry.getActions())); + case OF_11: + case OF_12: + case OF_13: + return entry.getInstructions(); + default: + log.warn("Unknown OF version {}", entry.getVersion()); + } + return Lists.newLinkedList(); + } + + private List getInstructions(OFFlowStatsEntry entry) { + switch (entry.getVersion()) { + case OF_10: + return Lists.newArrayList( + OFFactoryVer13.INSTANCE.instructions().applyActions(entry.getActions())); + case OF_11: + case OF_12: + case OF_13: + return entry.getInstructions(); + default: + log.warn("Unknown OF version {}", entry.getVersion()); + } + return Lists.newLinkedList(); + } + + private TrafficTreatment buildTreatment() { + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); + // If this is a drop rule + if (instructions.size() == 0) { + builder.drop(); + return builder.build(); + } + for (OFInstruction in : instructions) { + switch (in.getType()) { + case GOTO_TABLE: + builder.transition(((int) ((OFInstructionGotoTable) in) + .getTableId().getValue())); + break; + case WRITE_METADATA: + OFInstructionWriteMetadata m = (OFInstructionWriteMetadata) in; + builder.writeMetadata(m.getMetadata().getValue(), + m.getMetadataMask().getValue()); + break; + case WRITE_ACTIONS: + builder.deferred(); + buildActions(((OFInstructionWriteActions) in).getActions(), + builder); + break; + case APPLY_ACTIONS: + builder.immediate(); + buildActions(((OFInstructionApplyActions) in).getActions(), + builder); + break; + case CLEAR_ACTIONS: + builder.wipeDeferred(); + break; + case EXPERIMENTER: + break; + case METER: + break; + default: + log.warn("Unknown instructions type {}", in.getType()); + } + } + + return builder.build(); + } + + private TrafficTreatment.Builder buildActions(List actions, + TrafficTreatment.Builder builder) { + for (OFAction act : actions) { + switch (act.getType()) { + case OUTPUT: + OFActionOutput out = (OFActionOutput) act; + builder.setOutput( + PortNumber.portNumber(out.getPort().getPortNumber())); + break; + case SET_VLAN_VID: + OFActionSetVlanVid vlan = (OFActionSetVlanVid) act; + builder.setVlanId(VlanId.vlanId(vlan.getVlanVid().getVlan())); + break; + case SET_VLAN_PCP: + OFActionSetVlanPcp pcp = (OFActionSetVlanPcp) act; + builder.setVlanPcp(pcp.getVlanPcp().getValue()); + break; + case SET_DL_DST: + OFActionSetDlDst dldst = (OFActionSetDlDst) act; + builder.setEthDst( + MacAddress.valueOf(dldst.getDlAddr().getLong())); + break; + case SET_DL_SRC: + OFActionSetDlSrc dlsrc = (OFActionSetDlSrc) act; + builder.setEthSrc( + MacAddress.valueOf(dlsrc.getDlAddr().getLong())); + + break; + case SET_NW_DST: + OFActionSetNwDst nwdst = (OFActionSetNwDst) act; + IPv4Address di = nwdst.getNwAddr(); + builder.setIpDst(Ip4Address.valueOf(di.getInt())); + break; + case SET_NW_SRC: + OFActionSetNwSrc nwsrc = (OFActionSetNwSrc) act; + IPv4Address si = nwsrc.getNwAddr(); + builder.setIpSrc(Ip4Address.valueOf(si.getInt())); + break; + case EXPERIMENTER: + OFActionExperimenter exp = (OFActionExperimenter) act; + if (exp.getExperimenter() == 0x80005A06 || + exp.getExperimenter() == 0x748771) { + OFActionCircuit ct = (OFActionCircuit) exp; + short lambda = ((OFOxmOchSigidBasic) ct.getField()).getValue().getChannelNumber(); + builder.add(Instructions.modL0Lambda(Lambda.indexedLambda(lambda))); + } else { + log.warn("Unsupported OFActionExperimenter {}", exp.getExperimenter()); + } + break; + case SET_FIELD: + OFActionSetField setField = (OFActionSetField) act; + handleSetField(builder, setField.getField()); + break; + case POP_MPLS: + OFActionPopMpls popMpls = (OFActionPopMpls) act; + builder.popMpls((short) popMpls.getEthertype().getValue()); + break; + case PUSH_MPLS: + builder.pushMpls(); + break; + case COPY_TTL_IN: + builder.copyTtlIn(); + break; + case COPY_TTL_OUT: + builder.copyTtlOut(); + break; + case DEC_MPLS_TTL: + builder.decMplsTtl(); + break; + case DEC_NW_TTL: + builder.decNwTtl(); + break; + case GROUP: + OFActionGroup group = (OFActionGroup) act; + builder.group(new DefaultGroupId(group.getGroup().getGroupNumber())); + break; + case STRIP_VLAN: + case POP_VLAN: + builder.popVlan(); + break; + case PUSH_VLAN: + builder.pushVlan(); + break; + case SET_TP_DST: + case SET_TP_SRC: + case POP_PBB: + case PUSH_PBB: + case SET_MPLS_LABEL: + case SET_MPLS_TC: + case SET_MPLS_TTL: + case SET_NW_ECN: + case SET_NW_TOS: + case SET_NW_TTL: + case SET_QUEUE: + + case ENQUEUE: + default: + log.warn("Action type {} not yet implemented.", act.getType()); + } + } + return builder; + } + + + private void handleSetField(TrafficTreatment.Builder builder, OFOxm oxm) { + switch (oxm.getMatchField().id) { + case VLAN_PCP: + @SuppressWarnings("unchecked") + OFOxm vlanpcp = (OFOxm) oxm; + builder.setVlanPcp(vlanpcp.getValue().getValue()); + break; + case VLAN_VID: + @SuppressWarnings("unchecked") + OFOxm vlanvid = (OFOxm) oxm; + builder.setVlanId(VlanId.vlanId(vlanvid.getValue().getVlan())); + break; + case ETH_DST: + @SuppressWarnings("unchecked") + OFOxm ethdst = + (OFOxm) oxm; + builder.setEthDst(MacAddress.valueOf(ethdst.getValue().getLong())); + break; + case ETH_SRC: + @SuppressWarnings("unchecked") + OFOxm ethsrc = + (OFOxm) oxm; + builder.setEthSrc(MacAddress.valueOf(ethsrc.getValue().getLong())); + break; + case IPV4_DST: + @SuppressWarnings("unchecked") + OFOxm ip4dst = (OFOxm) oxm; + builder.setIpDst(Ip4Address.valueOf(ip4dst.getValue().getInt())); + break; + case IPV4_SRC: + @SuppressWarnings("unchecked") + OFOxm ip4src = (OFOxm) oxm; + builder.setIpSrc(Ip4Address.valueOf(ip4src.getValue().getInt())); + break; + case MPLS_LABEL: + @SuppressWarnings("unchecked") + OFOxm labelId = (OFOxm) oxm; + builder.setMpls(MplsLabel.mplsLabel((int) labelId.getValue().getValue())); + break; + case MPLS_BOS: + @SuppressWarnings("unchecked") + OFOxm mplsBos = (OFOxm) oxm; + builder.setMplsBos(mplsBos.getValue() == U8.ZERO ? false : true); + break; + case TUNNEL_ID: + @SuppressWarnings("unchecked") + OFOxm tunnelId = (OFOxm) oxm; + builder.setTunnelId(tunnelId.getValue().getValue()); + break; + case TCP_DST: + @SuppressWarnings("unchecked") + OFOxm tcpdst = (OFOxm) oxm; + builder.setTcpDst(TpPort.tpPort(tcpdst.getValue().getPort())); + break; + case TCP_SRC: + @SuppressWarnings("unchecked") + OFOxm tcpsrc = (OFOxm) oxm; + builder.setTcpSrc(TpPort.tpPort(tcpsrc.getValue().getPort())); + break; + case UDP_DST: + @SuppressWarnings("unchecked") + OFOxm udpdst = (OFOxm) oxm; + builder.setUdpDst(TpPort.tpPort(udpdst.getValue().getPort())); + break; + case UDP_SRC: + @SuppressWarnings("unchecked") + OFOxm udpsrc = (OFOxm) oxm; + builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort())); + break; + case ARP_OP: + case ARP_SHA: + case ARP_SPA: + case ARP_THA: + case ARP_TPA: + case BSN_EGR_PORT_GROUP_ID: + case BSN_GLOBAL_VRF_ALLOWED: + case BSN_IN_PORTS_128: + case BSN_L3_DST_CLASS_ID: + case BSN_L3_INTERFACE_CLASS_ID: + case BSN_L3_SRC_CLASS_ID: + case BSN_LAG_ID: + case BSN_TCP_FLAGS: + case BSN_UDF0: + case BSN_UDF1: + case BSN_UDF2: + case BSN_UDF3: + case BSN_UDF4: + case BSN_UDF5: + case BSN_UDF6: + case BSN_UDF7: + case BSN_VLAN_XLATE_PORT_GROUP_ID: + case BSN_VRF: + case ETH_TYPE: + case ICMPV4_CODE: + case ICMPV4_TYPE: + case ICMPV6_CODE: + case ICMPV6_TYPE: + case IN_PHY_PORT: + case IN_PORT: + case IPV6_DST: + case IPV6_FLABEL: + case IPV6_ND_SLL: + case IPV6_ND_TARGET: + case IPV6_ND_TLL: + case IPV6_SRC: + case IP_DSCP: + case IP_ECN: + case IP_PROTO: + case METADATA: + case MPLS_TC: + case OCH_SIGID: + case OCH_SIGID_BASIC: + case OCH_SIGTYPE: + case OCH_SIGTYPE_BASIC: + case SCTP_DST: + case SCTP_SRC: + default: + log.warn("Set field type {} not yet implemented.", oxm.getMatchField().id); + break; + } + } + + // CHECKSTYLE IGNORE MethodLength FOR NEXT 1 LINES + private TrafficSelector buildSelector() { + MacAddress mac; + Ip4Prefix ip4Prefix; + Ip6Address ip6Address; + Ip6Prefix ip6Prefix; + + TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); + for (MatchField field : match.getMatchFields()) { + switch (field.id) { + case IN_PORT: + builder.matchInPort(PortNumber + .portNumber(match.get(MatchField.IN_PORT).getPortNumber())); + break; + case IN_PHY_PORT: + builder.matchInPhyPort(PortNumber + .portNumber(match.get(MatchField.IN_PHY_PORT).getPortNumber())); + break; + case METADATA: + long metadata = + match.get(MatchField.METADATA).getValue().getValue(); + builder.matchMetadata(metadata); + break; + case ETH_DST: + mac = MacAddress.valueOf(match.get(MatchField.ETH_DST).getLong()); + builder.matchEthDst(mac); + break; + case ETH_SRC: + mac = MacAddress.valueOf(match.get(MatchField.ETH_SRC).getLong()); + builder.matchEthSrc(mac); + break; + case ETH_TYPE: + int ethType = match.get(MatchField.ETH_TYPE).getValue(); + if (ethType == EthType.VLAN_FRAME.getValue()) { + builder.matchVlanId(VlanId.ANY); + } else { + builder.matchEthType((short) ethType); + } + break; + case VLAN_VID: + VlanId vlanId = null; + if (match.isPartiallyMasked(MatchField.VLAN_VID)) { + Masked masked = match.getMasked(MatchField.VLAN_VID); + if (masked.getValue().equals(OFVlanVidMatch.PRESENT) + && masked.getMask().equals(OFVlanVidMatch.PRESENT)) { + vlanId = VlanId.ANY; + } + } else { + if (!match.get(MatchField.VLAN_VID).isPresentBitSet()) { + vlanId = VlanId.NONE; + } else { + vlanId = VlanId.vlanId(match.get(MatchField.VLAN_VID).getVlan()); + } + } + if (vlanId != null) { + builder.matchVlanId(vlanId); + } + break; + case VLAN_PCP: + byte vlanPcp = match.get(MatchField.VLAN_PCP).getValue(); + builder.matchVlanPcp(vlanPcp); + break; + case IP_DSCP: + byte ipDscp = match.get(MatchField.IP_DSCP).getDscpValue(); + builder.matchIPDscp(ipDscp); + break; + case IP_ECN: + byte ipEcn = match.get(MatchField.IP_ECN).getEcnValue(); + builder.matchIPEcn(ipEcn); + break; + case IP_PROTO: + short proto = match.get(MatchField.IP_PROTO).getIpProtocolNumber(); + builder.matchIPProtocol((byte) proto); + break; + case IPV4_SRC: + if (match.isPartiallyMasked(MatchField.IPV4_SRC)) { + Masked maskedIp = match.getMasked(MatchField.IPV4_SRC); + ip4Prefix = Ip4Prefix.valueOf( + maskedIp.getValue().getInt(), + maskedIp.getMask().asCidrMaskLength()); + } else { + ip4Prefix = Ip4Prefix.valueOf( + match.get(MatchField.IPV4_SRC).getInt(), + Ip4Prefix.MAX_MASK_LENGTH); + } + builder.matchIPSrc(ip4Prefix); + break; + case IPV4_DST: + if (match.isPartiallyMasked(MatchField.IPV4_DST)) { + Masked maskedIp = match.getMasked(MatchField.IPV4_DST); + ip4Prefix = Ip4Prefix.valueOf( + maskedIp.getValue().getInt(), + maskedIp.getMask().asCidrMaskLength()); + } else { + ip4Prefix = Ip4Prefix.valueOf( + match.get(MatchField.IPV4_DST).getInt(), + Ip4Prefix.MAX_MASK_LENGTH); + } + builder.matchIPDst(ip4Prefix); + break; + case TCP_SRC: + builder.matchTcpSrc(TpPort.tpPort(match.get(MatchField.TCP_SRC).getPort())); + break; + case TCP_DST: + builder.matchTcpDst(TpPort.tpPort(match.get(MatchField.TCP_DST).getPort())); + break; + case UDP_SRC: + builder.matchUdpSrc(TpPort.tpPort(match.get(MatchField.UDP_SRC).getPort())); + break; + case UDP_DST: + builder.matchUdpDst(TpPort.tpPort(match.get(MatchField.UDP_DST).getPort())); + break; + case MPLS_LABEL: + builder.matchMplsLabel(MplsLabel.mplsLabel((int) match.get(MatchField.MPLS_LABEL) + .getValue())); + break; + case MPLS_BOS: + builder.matchMplsBos(match.get(MatchField.MPLS_BOS).getValue()); + break; + case SCTP_SRC: + builder.matchSctpSrc(TpPort.tpPort(match.get(MatchField.SCTP_SRC).getPort())); + break; + case SCTP_DST: + builder.matchSctpDst(TpPort.tpPort(match.get(MatchField.SCTP_DST).getPort())); + break; + case ICMPV4_TYPE: + byte icmpType = (byte) match.get(MatchField.ICMPV4_TYPE).getType(); + builder.matchIcmpType(icmpType); + break; + case ICMPV4_CODE: + byte icmpCode = (byte) match.get(MatchField.ICMPV4_CODE).getCode(); + builder.matchIcmpCode(icmpCode); + break; + case IPV6_SRC: + if (match.isPartiallyMasked(MatchField.IPV6_SRC)) { + Masked maskedIp = match.getMasked(MatchField.IPV6_SRC); + ip6Prefix = Ip6Prefix.valueOf( + maskedIp.getValue().getBytes(), + maskedIp.getMask().asCidrMaskLength()); + } else { + ip6Prefix = Ip6Prefix.valueOf( + match.get(MatchField.IPV6_SRC).getBytes(), + Ip6Prefix.MAX_MASK_LENGTH); + } + builder.matchIPv6Src(ip6Prefix); + break; + case IPV6_DST: + if (match.isPartiallyMasked(MatchField.IPV6_DST)) { + Masked maskedIp = match.getMasked(MatchField.IPV6_DST); + ip6Prefix = Ip6Prefix.valueOf( + maskedIp.getValue().getBytes(), + maskedIp.getMask().asCidrMaskLength()); + } else { + ip6Prefix = Ip6Prefix.valueOf( + match.get(MatchField.IPV6_DST).getBytes(), + Ip6Prefix.MAX_MASK_LENGTH); + } + builder.matchIPv6Dst(ip6Prefix); + break; + case IPV6_FLABEL: + int flowLabel = + match.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue(); + builder.matchIPv6FlowLabel(flowLabel); + break; + case ICMPV6_TYPE: + byte icmpv6type = (byte) match.get(MatchField.ICMPV6_TYPE).getValue(); + builder.matchIcmpv6Type(icmpv6type); + break; + case ICMPV6_CODE: + byte icmpv6code = (byte) match.get(MatchField.ICMPV6_CODE).getValue(); + builder.matchIcmpv6Code(icmpv6code); + break; + case IPV6_ND_TARGET: + ip6Address = + Ip6Address.valueOf(match.get(MatchField.IPV6_ND_TARGET).getBytes()); + builder.matchIPv6NDTargetAddress(ip6Address); + break; + case IPV6_ND_SLL: + mac = MacAddress.valueOf(match.get(MatchField.IPV6_ND_SLL).getLong()); + builder.matchIPv6NDSourceLinkLayerAddress(mac); + break; + case IPV6_ND_TLL: + mac = MacAddress.valueOf(match.get(MatchField.IPV6_ND_TLL).getLong()); + builder.matchIPv6NDTargetLinkLayerAddress(mac); + break; + case IPV6_EXTHDR: + builder.matchIPv6ExthdrFlags((short) match.get(MatchField.IPV6_EXTHDR) + .getValue()); + break; + case OCH_SIGID: + CircuitSignalID sigId = match.get(MatchField.OCH_SIGID); + builder.add(matchLambda(Lambda.ochSignal( + lookupGridType(sigId.getGridType()), lookupChannelSpacing(sigId.getChannelSpacing()), + sigId.getChannelNumber(), sigId.getSpectralWidth()) + )); + break; + case OCH_SIGTYPE: + U8 sigType = match.get(MatchField.OCH_SIGTYPE); + builder.add(matchOchSignalType(lookupOchSignalType((byte) sigType.getValue()))); + break; + case TUNNEL_ID: + long tunnelId = match.get(MatchField.TUNNEL_ID).getValue(); + builder.matchTunnelId(tunnelId); + break; + case ARP_OP: + case ARP_SHA: + case ARP_SPA: + case ARP_THA: + case ARP_TPA: + case MPLS_TC: + default: + log.warn("Match type {} not yet implemented.", field.id); + } + } + return builder.build(); + } +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java new file mode 100644 index 00000000..e050524a --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java @@ -0,0 +1,444 @@ +/* + * Copyright 2014-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.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.flow.FlowRule; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPDscpCriterion; +import org.onosproject.net.flow.criteria.IPEcnCriterion; +import org.onosproject.net.flow.criteria.IPProtocolCriterion; +import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion; +import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion; +import org.onosproject.net.flow.criteria.IcmpCodeCriterion; +import org.onosproject.net.flow.criteria.IcmpTypeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; +import org.onosproject.net.flow.criteria.MetadataCriterion; +import org.onosproject.net.flow.criteria.MplsBosCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.criteria.OchSignalCriterion; +import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; +import org.onosproject.net.flow.criteria.PortCriterion; +import org.onosproject.net.flow.criteria.SctpPortCriterion; +import org.onosproject.net.flow.criteria.TcpPortCriterion; +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.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.OFFlowAdd; +import org.projectfloodlight.openflow.protocol.OFFlowDelete; +import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.match.Match; +import org.projectfloodlight.openflow.protocol.match.MatchField; +import org.projectfloodlight.openflow.types.CircuitSignalID; +import org.projectfloodlight.openflow.types.EthType; +import org.projectfloodlight.openflow.types.ICMPv4Code; +import org.projectfloodlight.openflow.types.ICMPv4Type; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; +import org.projectfloodlight.openflow.types.IPv6FlowLabel; +import org.projectfloodlight.openflow.types.IpDscp; +import org.projectfloodlight.openflow.types.IpEcn; +import org.projectfloodlight.openflow.types.IpProtocol; +import org.projectfloodlight.openflow.types.MacAddress; +import org.projectfloodlight.openflow.types.Masked; +import org.projectfloodlight.openflow.types.OFBooleanValue; +import org.projectfloodlight.openflow.types.OFMetadata; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.OFVlanVidMatch; +import org.projectfloodlight.openflow.types.TransportPort; +import org.projectfloodlight.openflow.types.U16; +import org.projectfloodlight.openflow.types.U32; +import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.U8; +import org.projectfloodlight.openflow.types.VlanPcp; +import org.projectfloodlight.openflow.types.VlanVid; +import org.slf4j.Logger; + +/** + * Builder for OpenFlow flow mods based on FlowRules. + */ +public abstract class FlowModBuilder { + + private final Logger log = getLogger(getClass()); + + private final OFFactory factory; + private final FlowRule flowRule; + private final TrafficSelector selector; + protected final Long xid; + + /** + * Creates a new flow mod builder. + * + * @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 + * @return the new flow mod builder + */ + public static FlowModBuilder builder(FlowRule flowRule, + OFFactory factory, + Optional xid) { + switch (factory.getVersion()) { + case OF_10: + return new FlowModBuilderVer10(flowRule, factory, xid); + case OF_13: + return new FlowModBuilderVer13(flowRule, factory, xid); + default: + throw new UnsupportedOperationException( + "No flow mod builder for protocol version " + factory.getVersion()); + } + } + + /** + * Constructs a flow mod builder. + * + * @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 + */ + protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional xid) { + this.factory = factory; + this.flowRule = flowRule; + this.selector = flowRule.selector(); + this.xid = xid.orElse(0L); + + } + + /** + * Builds an ADD flow mod. + * + * @return the flow mod + */ + public abstract OFFlowAdd buildFlowAdd(); + + /** + * Builds a MODIFY flow mod. + * + * @return the flow mod + */ + public abstract OFFlowMod buildFlowMod(); + + /** + * Builds a DELETE flow mod. + * + * @return the flow mod + */ + public abstract OFFlowDelete buildFlowDel(); + + /** + * Builds the match for the flow mod. + * + * @return the match + */ + // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES + protected Match buildMatch() { + Match.Builder mBuilder = factory.buildMatch(); + Ip6Address ip6Address; + Ip4Prefix ip4Prefix; + Ip6Prefix ip6Prefix; + EthCriterion ethCriterion; + IPCriterion ipCriterion; + TcpPortCriterion tcpPortCriterion; + UdpPortCriterion udpPortCriterion; + SctpPortCriterion sctpPortCriterion; + IPv6NDLinkLayerAddressCriterion llAddressCriterion; + + for (Criterion c : selector.criteria()) { + switch (c.type()) { + case IN_PORT: + PortCriterion inPort = (PortCriterion) c; + mBuilder.setExact(MatchField.IN_PORT, + OFPort.of((int) inPort.port().toLong())); + break; + case IN_PHY_PORT: + PortCriterion inPhyPort = (PortCriterion) c; + mBuilder.setExact(MatchField.IN_PORT, + OFPort.of((int) inPhyPort.port().toLong())); + break; + case METADATA: + MetadataCriterion metadata = (MetadataCriterion) c; + mBuilder.setExact(MatchField.METADATA, + OFMetadata.ofRaw(metadata.metadata())); + break; + case ETH_DST: + ethCriterion = (EthCriterion) c; + mBuilder.setExact(MatchField.ETH_DST, + MacAddress.of(ethCriterion.mac().toLong())); + break; + case ETH_SRC: + ethCriterion = (EthCriterion) c; + mBuilder.setExact(MatchField.ETH_SRC, + MacAddress.of(ethCriterion.mac().toLong())); + break; + case ETH_TYPE: + EthTypeCriterion ethType = (EthTypeCriterion) c; + mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType().toShort())); + break; + case VLAN_VID: + VlanIdCriterion vid = (VlanIdCriterion) c; + + if (vid.vlanId().equals(VlanId.ANY)) { + mBuilder.setMasked(MatchField.VLAN_VID, OFVlanVidMatch.PRESENT, + OFVlanVidMatch.PRESENT); + } else if (vid.vlanId().equals(VlanId.NONE)) { + mBuilder.setExact(MatchField.VLAN_VID, OFVlanVidMatch.NONE); + } else { + mBuilder.setExact(MatchField.VLAN_VID, + OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort()))); + } + break; + case VLAN_PCP: + VlanPcpCriterion vpcp = (VlanPcpCriterion) c; + mBuilder.setExact(MatchField.VLAN_PCP, VlanPcp.of(vpcp.priority())); + break; + case IP_DSCP: + IPDscpCriterion ipDscpCriterion = (IPDscpCriterion) c; + mBuilder.setExact(MatchField.IP_DSCP, + IpDscp.of(ipDscpCriterion.ipDscp())); + break; + case IP_ECN: + IPEcnCriterion ipEcnCriterion = (IPEcnCriterion) c; + mBuilder.setExact(MatchField.IP_ECN, + IpEcn.of(ipEcnCriterion.ipEcn())); + break; + case IP_PROTO: + IPProtocolCriterion p = (IPProtocolCriterion) c; + mBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(p.protocol())); + break; + case IPV4_SRC: + ipCriterion = (IPCriterion) c; + ip4Prefix = ipCriterion.ip().getIp4Prefix(); + if (ip4Prefix.prefixLength() != Ip4Prefix.MAX_MASK_LENGTH) { + Ip4Address maskAddr = + Ip4Address.makeMaskPrefix(ip4Prefix.prefixLength()); + Masked maskedIp = + Masked.of(IPv4Address.of(ip4Prefix.address().toInt()), + IPv4Address.of(maskAddr.toInt())); + mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp); + } else { + mBuilder.setExact(MatchField.IPV4_SRC, + IPv4Address.of(ip4Prefix.address().toInt())); + } + break; + case IPV4_DST: + ipCriterion = (IPCriterion) c; + ip4Prefix = ipCriterion.ip().getIp4Prefix(); + if (ip4Prefix.prefixLength() != Ip4Prefix.MAX_MASK_LENGTH) { + Ip4Address maskAddr = + Ip4Address.makeMaskPrefix(ip4Prefix.prefixLength()); + Masked maskedIp = + Masked.of(IPv4Address.of(ip4Prefix.address().toInt()), + IPv4Address.of(maskAddr.toInt())); + mBuilder.setMasked(MatchField.IPV4_DST, maskedIp); + } else { + mBuilder.setExact(MatchField.IPV4_DST, + IPv4Address.of(ip4Prefix.address().toInt())); + } + break; + case TCP_SRC: + tcpPortCriterion = (TcpPortCriterion) c; + mBuilder.setExact(MatchField.TCP_SRC, + TransportPort.of(tcpPortCriterion.tcpPort().toInt())); + break; + case TCP_DST: + tcpPortCriterion = (TcpPortCriterion) c; + mBuilder.setExact(MatchField.TCP_DST, + TransportPort.of(tcpPortCriterion.tcpPort().toInt())); + break; + case UDP_SRC: + udpPortCriterion = (UdpPortCriterion) c; + mBuilder.setExact(MatchField.UDP_SRC, + TransportPort.of(udpPortCriterion.udpPort().toInt())); + break; + case UDP_DST: + udpPortCriterion = (UdpPortCriterion) c; + mBuilder.setExact(MatchField.UDP_DST, + TransportPort.of(udpPortCriterion.udpPort().toInt())); + break; + case SCTP_SRC: + sctpPortCriterion = (SctpPortCriterion) c; + mBuilder.setExact(MatchField.SCTP_SRC, + TransportPort.of(sctpPortCriterion.sctpPort().toInt())); + break; + case SCTP_DST: + sctpPortCriterion = (SctpPortCriterion) c; + mBuilder.setExact(MatchField.SCTP_DST, + TransportPort.of(sctpPortCriterion.sctpPort().toInt())); + break; + case ICMPV4_TYPE: + IcmpTypeCriterion icmpType = (IcmpTypeCriterion) c; + mBuilder.setExact(MatchField.ICMPV4_TYPE, + ICMPv4Type.of(icmpType.icmpType())); + break; + case ICMPV4_CODE: + IcmpCodeCriterion icmpCode = (IcmpCodeCriterion) c; + mBuilder.setExact(MatchField.ICMPV4_CODE, + ICMPv4Code.of(icmpCode.icmpCode())); + break; + case IPV6_SRC: + ipCriterion = (IPCriterion) c; + ip6Prefix = ipCriterion.ip().getIp6Prefix(); + if (ip6Prefix.prefixLength() != Ip6Prefix.MAX_MASK_LENGTH) { + Ip6Address maskAddr = + Ip6Address.makeMaskPrefix(ip6Prefix.prefixLength()); + Masked maskedIp = + Masked.of(IPv6Address.of(ip6Prefix.address().toString()), + IPv6Address.of(maskAddr.toString())); + mBuilder.setMasked(MatchField.IPV6_SRC, maskedIp); + } else { + mBuilder.setExact(MatchField.IPV6_SRC, + IPv6Address.of(ip6Prefix.address().toString())); + } + break; + case IPV6_DST: + ipCriterion = (IPCriterion) c; + ip6Prefix = ipCriterion.ip().getIp6Prefix(); + if (ip6Prefix.prefixLength() != Ip6Prefix.MAX_MASK_LENGTH) { + Ip6Address maskAddr = + Ip6Address.makeMaskPrefix(ip6Prefix.prefixLength()); + Masked maskedIp = + Masked.of(IPv6Address.of(ip6Prefix.address().toString()), + IPv6Address.of(maskAddr.toString())); + mBuilder.setMasked(MatchField.IPV6_DST, maskedIp); + } else { + mBuilder.setExact(MatchField.IPV6_DST, + IPv6Address.of(ip6Prefix.address().toString())); + } + break; + case IPV6_FLABEL: + IPv6FlowLabelCriterion flowLabelCriterion = + (IPv6FlowLabelCriterion) c; + mBuilder.setExact(MatchField.IPV6_FLABEL, + IPv6FlowLabel.of(flowLabelCriterion.flowLabel())); + break; + case ICMPV6_TYPE: + Icmpv6TypeCriterion icmpv6Type = (Icmpv6TypeCriterion) c; + mBuilder.setExact(MatchField.ICMPV6_TYPE, + U8.of(icmpv6Type.icmpv6Type())); + break; + case ICMPV6_CODE: + Icmpv6CodeCriterion icmpv6Code = (Icmpv6CodeCriterion) c; + mBuilder.setExact(MatchField.ICMPV6_CODE, + U8.of(icmpv6Code.icmpv6Code())); + break; + case IPV6_ND_TARGET: + IPv6NDTargetAddressCriterion targetAddressCriterion = + (IPv6NDTargetAddressCriterion) c; + ip6Address = targetAddressCriterion.targetAddress(); + mBuilder.setExact(MatchField.IPV6_ND_TARGET, + IPv6Address.of(ip6Address.toOctets())); + break; + case IPV6_ND_SLL: + llAddressCriterion = + (IPv6NDLinkLayerAddressCriterion) c; + mBuilder.setExact(MatchField.IPV6_ND_SLL, + MacAddress.of(llAddressCriterion.mac().toLong())); + break; + case IPV6_ND_TLL: + llAddressCriterion = + (IPv6NDLinkLayerAddressCriterion) c; + mBuilder.setExact(MatchField.IPV6_ND_TLL, + MacAddress.of(llAddressCriterion.mac().toLong())); + break; + case MPLS_LABEL: + MplsCriterion mp = (MplsCriterion) c; + mBuilder.setExact(MatchField.MPLS_LABEL, U32.of(mp.label().toInt())); + break; + case IPV6_EXTHDR: + IPv6ExthdrFlagsCriterion exthdrFlagsCriterion = + (IPv6ExthdrFlagsCriterion) c; + mBuilder.setExact(MatchField.IPV6_EXTHDR, + U16.of(exthdrFlagsCriterion.exthdrFlags())); + break; + case OCH_SIGID: + try { + OchSignalCriterion ochSignalCriterion = (OchSignalCriterion) c; + OchSignal signal = ochSignalCriterion.lambda(); + byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType()); + byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing()); + mBuilder.setExact(MatchField.OCH_SIGID, + new CircuitSignalID(gridType, channelSpacing, + (short) signal.spacingMultiplier(), (short) signal.slotGranularity())); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + } + break; + case OCH_SIGTYPE: + OchSignalTypeCriterion sc = (OchSignalTypeCriterion) c; + byte signalType = OpenFlowValueMapper.lookupOchSignalType(sc.signalType()); + mBuilder.setExact(MatchField.OCH_SIGTYPE, U8.of(signalType)); + break; + case TUNNEL_ID: + TunnelIdCriterion tunnelId = (TunnelIdCriterion) c; + mBuilder.setExact(MatchField.TUNNEL_ID, + U64.of(tunnelId.tunnelId())); + break; + case MPLS_BOS: + MplsBosCriterion mplsBos = (MplsBosCriterion) c; + mBuilder.setExact(MatchField.MPLS_BOS, + mplsBos.mplsBos() ? OFBooleanValue.TRUE + : OFBooleanValue.FALSE); + break; + case ARP_OP: + case ARP_SHA: + case ARP_SPA: + case ARP_THA: + case ARP_TPA: + case MPLS_TC: + case PBB_ISID: + default: + log.warn("Match type {} not yet implemented.", c.type()); + } + } + return mBuilder.build(); + } + + /** + * Returns the flow rule for this builder. + * + * @return the flow rule + */ + protected FlowRule flowRule() { + return flowRule; + } + + /** + * Returns the factory used for building OpenFlow constructs. + * + * @return the factory + */ + protected OFFactory factory() { + return factory; + } + +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java new file mode 100644 index 00000000..c9de4500 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java @@ -0,0 +1,230 @@ +/* + * Copyright 2014-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.provider.of.flow.impl; + +import org.onlab.packet.Ip4Address; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; +import org.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.OFFlowAdd; +import org.projectfloodlight.openflow.protocol.OFFlowDelete; +import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.OFFlowModFlags; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.match.Match; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.MacAddress; +import org.projectfloodlight.openflow.types.OFBufferId; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.VlanPcp; +import org.projectfloodlight.openflow.types.VlanVid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +/** + * Flow mod builder for OpenFlow 1.0. + */ +public class FlowModBuilderVer10 extends FlowModBuilder { + + private final Logger log = LoggerFactory.getLogger(getClass()); + private static final int OFPCML_NO_BUFFER = 0xffff; + + private final TrafficTreatment treatment; + + /** + * Constructor for a flow mod builder for OpenFlow 1.0. + * + * @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 + */ + protected FlowModBuilderVer10(FlowRule flowRule, + OFFactory factory, Optional xid) { + super(flowRule, factory, xid); + + this.treatment = flowRule.treatment(); + } + + @Override + public OFFlowAdd buildFlowAdd() { + Match match = buildMatch(); + List actions = buildActions(); + + long cookie = flowRule().id().value(); + + + OFFlowAdd fm = factory().buildFlowAdd() + .setXid(xid) + .setCookie(U64.of(cookie)) + .setBufferId(OFBufferId.NO_BUFFER) + .setActions(actions) + .setMatch(match) + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) + .setPriority(flowRule().priority()) + .build(); + + return fm; + } + + @Override + public OFFlowMod buildFlowMod() { + Match match = buildMatch(); + List actions = buildActions(); + + long cookie = flowRule().id().value(); + + OFFlowMod fm = factory().buildFlowModify() + .setXid(xid) + .setCookie(U64.of(cookie)) + .setBufferId(OFBufferId.NO_BUFFER) + .setActions(actions) + .setMatch(match) + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) + .setPriority(flowRule().priority()) + .build(); + + return fm; + } + + @Override + public OFFlowDelete buildFlowDel() { + Match match = buildMatch(); + + long cookie = flowRule().id().value(); + + OFFlowDelete fm = factory().buildFlowDelete() + .setXid(xid) + .setCookie(U64.of(cookie)) + .setBufferId(OFBufferId.NO_BUFFER) + .setMatch(match) + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) + .setPriority(flowRule().priority()) + .build(); + + return fm; + } + + private List buildActions() { + List acts = new LinkedList<>(); + OFAction act; + if (treatment == null) { + return acts; + } + for (Instruction i : treatment.immediate()) { + switch (i.type()) { + case DROP: + log.warn("Saw drop action; assigning drop action"); + return Collections.emptyList(); + case L2MODIFICATION: + act = buildL2Modification(i); + if (act != null) { + acts.add(buildL2Modification(i)); + } + break; + case L3MODIFICATION: + act = buildL3Modification(i); + if (act != null) { + acts.add(buildL3Modification(i)); + } + break; + case OUTPUT: + OutputInstruction out = (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); + } + acts.add(action.build()); + break; + case L0MODIFICATION: + case GROUP: + case TABLE: + case METADATA: + log.warn("Instruction type {} not supported with protocol version {}", + i.type(), factory().getVersion()); + break; + default: + log.warn("Instruction type {} not yet implemented.", i.type()); + } + } + + return acts; + } + + private OFAction buildL3Modification(Instruction i) { + L3ModificationInstruction l3m = (L3ModificationInstruction) i; + ModIPInstruction ip; + Ip4Address ip4; + switch (l3m.subtype()) { + case IPV4_SRC: + ip = (ModIPInstruction) i; + ip4 = ip.ip().getIp4Address(); + return factory().actions().setNwSrc(IPv4Address.of(ip4.toInt())); + case IPV4_DST: + ip = (ModIPInstruction) i; + ip4 = ip.ip().getIp4Address(); + return factory().actions().setNwDst(IPv4Address.of(ip4.toInt())); + default: + log.warn("Unimplemented action type {}.", l3m.subtype()); + break; + } + return null; + } + + private OFAction buildL2Modification(Instruction i) { + L2ModificationInstruction l2m = (L2ModificationInstruction) i; + ModEtherInstruction eth; + switch (l2m.subtype()) { + case ETH_DST: + eth = (ModEtherInstruction) l2m; + return factory().actions().setDlDst(MacAddress.of(eth.mac().toLong())); + case ETH_SRC: + eth = (ModEtherInstruction) l2m; + return factory().actions().setDlSrc(MacAddress.of(eth.mac().toLong())); + case VLAN_ID: + ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m; + return factory().actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId().toShort())); + case VLAN_PCP: + ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m; + return factory().actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp())); + case VLAN_POP: + return factory().actions().stripVlan(); + case VLAN_PUSH: + return null; + default: + log.warn("Unimplemented action type {}.", l2m.subtype()); + break; + } + return null; + } + +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java new file mode 100644 index 00000000..8918d337 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java @@ -0,0 +1,458 @@ +/* + * Copyright 2014-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.provider.of.flow.impl; + +import com.google.common.collect.Lists; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.flow.instructions.Instructions.GroupInstruction; +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction; +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.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.projectfloodlight.openflow.protocol.OFFactory; +import org.projectfloodlight.openflow.protocol.OFFlowAdd; +import org.projectfloodlight.openflow.protocol.OFFlowDelete; +import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.OFFlowModFlags; +import org.projectfloodlight.openflow.protocol.action.OFAction; +import org.projectfloodlight.openflow.protocol.action.OFActionGroup; +import org.projectfloodlight.openflow.protocol.action.OFActionOutput; +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; +import org.projectfloodlight.openflow.protocol.match.Match; +import org.projectfloodlight.openflow.protocol.oxm.OFOxm; +import org.projectfloodlight.openflow.types.CircuitSignalID; +import org.projectfloodlight.openflow.types.EthType; +import org.projectfloodlight.openflow.types.IPv4Address; +import org.projectfloodlight.openflow.types.IPv6Address; +import org.projectfloodlight.openflow.types.IPv6FlowLabel; +import org.projectfloodlight.openflow.types.MacAddress; +import org.projectfloodlight.openflow.types.OFBooleanValue; +import org.projectfloodlight.openflow.types.OFBufferId; +import org.projectfloodlight.openflow.types.OFGroup; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.OFVlanVidMatch; +import org.projectfloodlight.openflow.types.TableId; +import org.projectfloodlight.openflow.types.TransportPort; +import org.projectfloodlight.openflow.types.U32; +import org.projectfloodlight.openflow.types.U64; +import org.projectfloodlight.openflow.types.VlanPcp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +/** + * Flow mod builder for OpenFlow 1.3+. + */ +public class FlowModBuilderVer13 extends FlowModBuilder { + + private final Logger log = LoggerFactory.getLogger(getClass()); + private static final int OFPCML_NO_BUFFER = 0xffff; + + private final TrafficTreatment treatment; + + /** + * Constructor for a flow mod builder for OpenFlow 1.3. + * + * @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 + */ + protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional xid) { + super(flowRule, factory, xid); + + this.treatment = flowRule.treatment(); + } + + @Override + public OFFlowAdd buildFlowAdd() { + Match match = buildMatch(); + List deferredActions = buildActions(treatment.deferred()); + List immediateActions = buildActions(treatment.immediate()); + List instructions = Lists.newLinkedList(); + + + if (treatment.clearedDeferred()) { + instructions.add(factory().instructions().clearActions()); + } + if (immediateActions.size() > 0) { + instructions.add(factory().instructions().applyActions(immediateActions)); + } + if (deferredActions.size() > 0) { + instructions.add(factory().instructions().writeActions(deferredActions)); + } + if (treatment.tableTransition() != null) { + instructions.add(buildTableGoto(treatment.tableTransition())); + } + if (treatment.writeMetadata() != null) { + instructions.add(buildMetadata(treatment.writeMetadata())); + } + + 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())) + .build(); + + return fm; + } + + @Override + public OFFlowMod buildFlowMod() { + Match match = buildMatch(); + List deferredActions = buildActions(treatment.deferred()); + List immediateActions = buildActions(treatment.immediate()); + List instructions = Lists.newLinkedList(); + + + if (immediateActions.size() > 0) { + instructions.add(factory().instructions().applyActions(immediateActions)); + } + if (treatment.clearedDeferred()) { + instructions.add(factory().instructions().clearActions()); + } + if (deferredActions.size() > 0) { + 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.metered() != null) { + instructions.add(buildMeter(treatment.metered())); + } + + 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())) + .build(); + + return fm; + } + + @Override + public OFFlowDelete buildFlowDel() { + Match match = buildMatch(); + + long cookie = flowRule().id().value(); + + OFFlowDelete fm = factory().buildFlowDelete() + .setXid(xid) + .setCookie(U64.of(cookie)) + .setBufferId(OFBufferId.NO_BUFFER) + .setMatch(match) + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) + .setPriority(flowRule().priority()) + .setTableId(TableId.of(flowRule().tableId())) + .build(); + + return fm; + } + + private List buildActions(List treatments) { + if (treatment == null) { + return Collections.emptyList(); + } + + boolean tableFound = false; + List actions = new LinkedList<>(); + for (Instruction i : treatments) { + switch (i.type()) { + case DROP: + return Collections.emptyList(); + case L0MODIFICATION: + actions.add(buildL0Modification(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: + OutputInstruction out = (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: + GroupInstruction group = (GroupInstruction) i; + OFActionGroup.Builder groupBuilder = factory().actions().buildGroup() + .setGroup(OFGroup.of(group.groupId().id())); + actions.add(groupBuilder.build()); + break; + case TABLE: + //FIXME: should not occur here. + tableFound = true; + 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 OFInstruction buildTableGoto(Instructions.TableTypeTransition i) { + OFInstruction instruction = factory().instructions().gotoTable( + TableId.of(i.tableId())); + return instruction; + } + + private 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) { + return factory().instructions().meter(metered.meterId().id()); + } + + + private OFAction buildL0Modification(Instruction i) { + L0ModificationInstruction l0m = (L0ModificationInstruction) i; + switch (l0m.subtype()) { + case LAMBDA: + return buildModLambdaInstruction((ModLambdaInstruction) i); + case OCH: + try { + return buildModOchSignalInstruction((ModOchSignalInstruction) i); + } catch (NoMappingFoundException e) { + log.warn(e.getMessage()); + break; + } + default: + log.warn("Unimplemented action type {}.", l0m.subtype()); + break; + } + return null; + } + + private OFAction buildModLambdaInstruction(ModLambdaInstruction instruction) { + return factory().actions().circuit(factory().oxms().ochSigidBasic( + new CircuitSignalID((byte) 1, (byte) 2, instruction.lambda(), (short) 1))); + } + + private OFAction buildModOchSignalInstruction(ModOchSignalInstruction instruction) { + OchSignal signal = instruction.lambda(); + byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType()); + byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing()); + + return factory().actions().circuit(factory().oxms().ochSigidBasic( + new CircuitSignalID(gridType, channelSpacing, + (short) signal.spacingMultiplier(), (short) signal.slotGranularity()) + )); + } + + private OFAction buildL2Modification(Instruction i) { + L2ModificationInstruction l2m = (L2ModificationInstruction) i; + ModEtherInstruction eth; + OFOxm oxm = null; + switch (l2m.subtype()) { + case ETH_DST: + eth = (ModEtherInstruction) l2m; + oxm = factory().oxms().ethDst(MacAddress.of(eth.mac().toLong())); + break; + case ETH_SRC: + eth = (ModEtherInstruction) l2m; + oxm = factory().oxms().ethSrc(MacAddress.of(eth.mac().toLong())); + break; + case VLAN_ID: + ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m; + oxm = factory().oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId().toShort())); + break; + case VLAN_PCP: + ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m; + oxm = factory().oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp())); + break; + case MPLS_PUSH: + PushHeaderInstructions pushHeaderInstructions = + (PushHeaderInstructions) l2m; + return factory().actions().pushMpls(EthType.of(pushHeaderInstructions + .ethernetType().toShort())); + case MPLS_POP: + PushHeaderInstructions popHeaderInstructions = + (PushHeaderInstructions) l2m; + return factory().actions().popMpls(EthType.of(popHeaderInstructions + .ethernetType().toShort())); + case MPLS_LABEL: + ModMplsLabelInstruction mplsLabel = + (ModMplsLabelInstruction) l2m; + oxm = factory().oxms().mplsLabel(U32.of(mplsLabel.mplsLabel().toInt())); + break; + case MPLS_BOS: + ModMplsBosInstruction mplsBos = (ModMplsBosInstruction) l2m; + oxm = factory().oxms() + .mplsBos(mplsBos.mplsBos() ? OFBooleanValue.TRUE + : OFBooleanValue.FALSE); + break; + case DEC_MPLS_TTL: + return factory().actions().decMplsTtl(); + case VLAN_POP: + return factory().actions().popVlan(); + case VLAN_PUSH: + PushHeaderInstructions pushVlanInstruction = (PushHeaderInstructions) l2m; + return factory().actions().pushVlan( + EthType.of(pushVlanInstruction.ethernetType().toShort())); + case TUNNEL_ID: + ModTunnelIdInstruction tunnelId = (ModTunnelIdInstruction) l2m; + oxm = factory().oxms().tunnelId(U64.of(tunnelId.tunnelId())); + break; + default: + log.warn("Unimplemented action type {}.", l2m.subtype()); + break; + } + + if (oxm != null) { + return factory().actions().buildSetField().setField(oxm).build(); + } + return null; + } + + private OFAction buildL3Modification(Instruction i) { + L3ModificationInstruction l3m = (L3ModificationInstruction) i; + ModIPInstruction ip; + Ip4Address ip4; + Ip6Address ip6; + OFOxm oxm = null; + switch (l3m.subtype()) { + case IPV4_SRC: + ip = (ModIPInstruction) i; + ip4 = ip.ip().getIp4Address(); + oxm = factory().oxms().ipv4Src(IPv4Address.of(ip4.toInt())); + break; + case IPV4_DST: + ip = (ModIPInstruction) i; + ip4 = ip.ip().getIp4Address(); + oxm = factory().oxms().ipv4Dst(IPv4Address.of(ip4.toInt())); + break; + case IPV6_SRC: + ip = (ModIPInstruction) i; + ip6 = ip.ip().getIp6Address(); + oxm = factory().oxms().ipv6Src(IPv6Address.of(ip6.toOctets())); + break; + case IPV6_DST: + ip = (ModIPInstruction) i; + ip6 = ip.ip().getIp6Address(); + oxm = factory().oxms().ipv6Dst(IPv6Address.of(ip6.toOctets())); + break; + case IPV6_FLABEL: + ModIPv6FlowLabelInstruction flowLabelInstruction = + (ModIPv6FlowLabelInstruction) i; + int flowLabel = flowLabelInstruction.flowLabel(); + oxm = factory().oxms().ipv6Flabel(IPv6FlowLabel.of(flowLabel)); + break; + case DEC_TTL: + return factory().actions().decNwTtl(); + case TTL_IN: + return factory().actions().copyTtlIn(); + case TTL_OUT: + return factory().actions().copyTtlOut(); + default: + log.warn("Unimplemented action type {}.", l3m.subtype()); + break; + } + + if (oxm != null) { + return factory().actions().buildSetField().setField(oxm).build(); + } + return null; + } + + private OFAction buildL4Modification(Instruction i) { + L4ModificationInstruction l4m = (L4ModificationInstruction) i; + ModTransportPortInstruction tp; + OFOxm oxm = null; + switch (l4m.subtype()) { + case TCP_SRC: + tp = (ModTransportPortInstruction) l4m; + oxm = factory().oxms().tcpSrc(TransportPort.of(tp.port().toInt())); + break; + case TCP_DST: + tp = (ModTransportPortInstruction) l4m; + oxm = factory().oxms().tcpDst(TransportPort.of(tp.port().toInt())); + break; + case UDP_SRC: + tp = (ModTransportPortInstruction) l4m; + oxm = factory().oxms().udpSrc(TransportPort.of(tp.port().toInt())); + break; + case UDP_DST: + tp = (ModTransportPortInstruction) l4m; + oxm = factory().oxms().udpDst(TransportPort.of(tp.port().toInt())); + break; + default: + log.warn("Unimplemented action type {}.", l4m.subtype()); + break; + } + + if (oxm != null) { + return factory().actions().buildSetField().setField(oxm).build(); + } + return null; + } + +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java new file mode 100644 index 00000000..c4c81afa --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowStatsCollector.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 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.provider.of.flow.impl; + +import org.onlab.util.SharedExecutors; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.RoleState; +import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest; +import org.projectfloodlight.openflow.types.OFPort; +import org.projectfloodlight.openflow.types.TableId; +import org.slf4j.Logger; + +import java.util.Timer; +import java.util.TimerTask; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Collects flow statistics for the specified switch. + */ +class FlowStatsCollector { + + private final Logger log = getLogger(getClass()); + + public static final int SECONDS = 1000; + + private final OpenFlowSwitch sw; + private Timer timer; + private TimerTask task; + + private int pollInterval; + + /** + * Creates a new collector for the given switch and poll frequency. + * + * @param timer timer to use for scheduling + * @param sw switch to pull + * @param pollInterval poll frequency in seconds + */ + FlowStatsCollector(Timer timer, OpenFlowSwitch sw, int pollInterval) { + this.timer = timer; + this.sw = sw; + this.pollInterval = pollInterval; + } + + /** + * Adjusts poll frequency. + * + * @param pollInterval poll frequency in seconds + */ + synchronized void adjustPollInterval(int pollInterval) { + this.pollInterval = pollInterval; + task.cancel(); + task = new InternalTimerTask(); + timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000); + } + + private class InternalTimerTask extends TimerTask { + @Override + public void run() { + if (sw.getRole() == RoleState.MASTER) { + log.trace("Collecting stats for {}", sw.getStringId()); + OFFlowStatsRequest request = sw.factory().buildFlowStatsRequest() + .setMatch(sw.factory().matchWildcardAll()) + .setTableId(TableId.ALL) + .setOutPort(OFPort.NO_MASK) + .build(); + sw.sendMsg(request); + } + } + } + + public synchronized void start() { + // Initially start polling quickly. Then drop down to configured value + log.debug("Starting Stats collection thread for {}", sw.getStringId()); + task = new InternalTimerTask(); + SharedExecutors.getTimer().scheduleAtFixedRate(task, 1 * SECONDS, + pollInterval * SECONDS); + } + + public synchronized void stop() { + log.debug("Stopping Stats collection thread for {}", sw.getStringId()); + task.cancel(); + task = null; + } + +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java new file mode 100644 index 00000000..898b286d --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NoMappingFoundException.java @@ -0,0 +1,31 @@ +/* + * 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.provider.of.flow.impl; + +/** + * Thrown to indicate that no mapping for the input value is found. + */ +public class NoMappingFoundException extends RuntimeException { + /** + * Creates an instance with the specified values. + * + * @param input input value of mapping causing this exception + * @param output the desired class which the input value is mapped to + */ + public NoMappingFoundException(Object input, Class output) { + super(String.format("No mapping found for %s when converting to %s", input, output.getName())); + } +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java new file mode 100644 index 00000000..de079e03 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java @@ -0,0 +1,453 @@ +/* + * Copyright 2014 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.provider.of.flow.impl; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +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; +import org.apache.felix.scr.annotations.Modified; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +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.flow.CompletedBatchOperation; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleBatchEntry; +import org.onosproject.net.flow.FlowRuleBatchOperation; +import org.onosproject.net.flow.FlowRuleExtPayLoad; +import org.onosproject.net.flow.FlowRuleProvider; +import org.onosproject.net.flow.FlowRuleProviderRegistry; +import org.onosproject.net.flow.FlowRuleProviderService; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.statistic.DefaultLoad; +import org.onosproject.openflow.controller.Dpid; +import org.onosproject.openflow.controller.OpenFlowController; +import org.onosproject.openflow.controller.OpenFlowEventListener; +import org.onosproject.openflow.controller.OpenFlowSwitch; +import org.onosproject.openflow.controller.OpenFlowSwitchListener; +import org.onosproject.openflow.controller.RoleState; +import org.onosproject.openflow.controller.ThirdPartyMessage; +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.OFErrorType; +import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.OFFlowRemoved; +import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; +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.errormsg.OFBadRequestErrorMsg; +import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.Dictionary; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.Timer; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.onlab.util.Tools.get; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Provider which uses an OpenFlow controller to detect network end-station + * hosts. + */ +@Component(immediate = true) +public class OpenFlowRuleProvider extends AbstractProvider + implements FlowRuleProvider { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleProviderRegistry providerRegistry; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected OpenFlowController controller; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + private static final int DEFAULT_POLL_FREQUENCY = 10; + @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY, + label = "Frequency (in seconds) for polling flow statistics") + private int flowPollFrequency = DEFAULT_POLL_FREQUENCY; + + private FlowRuleProviderService providerService; + + private final InternalFlowProvider listener = new InternalFlowProvider(); + + private Cache pendingBatches; + + private final Timer timer = new Timer("onos-openflow-collector"); + private final Map collectors = Maps.newHashMap(); + + /** + * Creates an OpenFlow host provider. + */ + public OpenFlowRuleProvider() { + super(new ProviderId("of", "org.onosproject.provider.openflow")); + } + + @Activate + public void activate(ComponentContext context) { + cfgService.registerProperties(getClass()); + providerService = providerRegistry.register(this); + controller.addListener(listener); + controller.addEventListener(listener); + + pendingBatches = createBatchCache(); + createCollectors(); + + log.info("Started"); + } + + @Deactivate + public void deactivate(ComponentContext context) { + cfgService.unregisterProperties(getClass(), false); + stopCollectors(); + providerRegistry.unregister(this); + providerService = null; + + log.info("Stopped"); + } + + @Modified + public void modified(ComponentContext context) { + Dictionary properties = context.getProperties(); + int newFlowPollFrequency; + try { + String s = get(properties, "flowPollFrequency"); + newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim()); + + } catch (NumberFormatException | ClassCastException e) { + newFlowPollFrequency = flowPollFrequency; + } + + if (newFlowPollFrequency != flowPollFrequency) { + flowPollFrequency = newFlowPollFrequency; + adjustRate(); + } + + log.info("Settings: flowPollFrequency={}", flowPollFrequency); + } + + private Cache createBatchCache() { + return CacheBuilder.newBuilder() + .expireAfterWrite(10, TimeUnit.SECONDS) + .removalListener((RemovalNotification notification) -> { + if (notification.getCause() == RemovalCause.EXPIRED) { + providerService.batchOperationCompleted(notification.getKey(), + notification.getValue().failedCompletion()); + } + }).build(); + } + + private void createCollectors() { + controller.getSwitches().forEach(this::createCollector); + } + + private void createCollector(OpenFlowSwitch sw) { + FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency); + fsc.start(); + collectors.put(new Dpid(sw.getId()), fsc); + } + + private void stopCollectors() { + collectors.values().forEach(FlowStatsCollector::stop); + collectors.clear(); + } + + private void adjustRate() { + DefaultLoad.setPollInterval(flowPollFrequency); + collectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency)); + } + + @Override + public void applyFlowRule(FlowRule... flowRules) { + for (FlowRule flowRule : flowRules) { + applyRule(flowRule); + } + } + + private void applyRule(FlowRule flowRule) { + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId() + .uri())); + FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad(); + if (hasPayload(flowRuleExtPayLoad)) { + OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad()); + sw.sendMsg(msg); + return; + } + sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), + Optional.empty()).buildFlowAdd()); + } + + @Override + public void removeFlowRule(FlowRule... flowRules) { + for (FlowRule flowRule : flowRules) { + removeRule(flowRule); + } + } + + private void removeRule(FlowRule flowRule) { + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId() + .uri())); + FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad(); + if (hasPayload(flowRuleExtPayLoad)) { + OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad()); + sw.sendMsg(msg); + return; + } + sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), + Optional.empty()).buildFlowDel()); + } + + @Override + public void removeRulesById(ApplicationId id, FlowRule... flowRules) { + // TODO: optimize using the ApplicationId + removeFlowRule(flowRules); + } + + @Override + public void executeBatch(FlowRuleBatchOperation batch) { + + pendingBatches.put(batch.id(), new InternalCacheEntry(batch)); + + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(batch.deviceId() + .uri())); + OFFlowMod mod; + for (FlowRuleBatchEntry fbe : batch.getOperations()) { + // flow is the third party privacy flow + + FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad(); + if (hasPayload(flowRuleExtPayLoad)) { + OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad()); + sw.sendMsg(msg); + continue; + } + FlowModBuilder builder = FlowModBuilder.builder(fbe.target(), sw + .factory(), Optional.of(batch.id())); + switch (fbe.operator()) { + case ADD: + mod = builder.buildFlowAdd(); + break; + case REMOVE: + mod = builder.buildFlowDel(); + break; + case MODIFY: + mod = builder.buildFlowMod(); + break; + default: + log.error("Unsupported batch operation {}; skipping flowmod {}", + fbe.operator(), fbe); + continue; + } + sw.sendMsg(mod); + } + OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest() + .setXid(batch.id()); + sw.sendMsg(builder.build()); + } + + private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) { + return flowRuleExtPayLoad != null && + flowRuleExtPayLoad.payLoad() != null && + flowRuleExtPayLoad.payLoad().length > 0; + } + + private class InternalFlowProvider + implements OpenFlowSwitchListener, OpenFlowEventListener { + + @Override + public void switchAdded(Dpid dpid) { + createCollector(controller.getSwitch(dpid)); + } + + @Override + public void switchRemoved(Dpid dpid) { + FlowStatsCollector collector = collectors.remove(dpid); + if (collector != null) { + collector.stop(); + } + } + + @Override + public void switchChanged(Dpid dpid) { + } + + @Override + public void portChanged(Dpid dpid, OFPortStatus status) { + // TODO: Decide whether to evict flows internal store. + } + + @Override + public void handleMessage(Dpid dpid, OFMessage msg) { + OpenFlowSwitch sw = controller.getSwitch(dpid); + switch (msg.getType()) { + case FLOW_REMOVED: + OFFlowRemoved removed = (OFFlowRemoved) msg; + + FlowEntry fr = new FlowEntryBuilder(dpid, removed).build(); + providerService.flowRemoved(fr); + break; + case STATS_REPLY: + if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) { + pushFlowMetrics(dpid, (OFFlowStatsReply) msg); + } + break; + case BARRIER_REPLY: + try { + InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid()); + if (entry != null) { + providerService + .batchOperationCompleted(msg.getXid(), + entry.completed()); + } else { + log.warn("Received unknown Barrier Reply: {}", + msg.getXid()); + } + } finally { + pendingBatches.invalidate(msg.getXid()); + } + break; + case ERROR: + // TODO: This needs to get suppressed in a better way. + if (msg instanceof OFBadRequestErrorMsg && + ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) { + log.debug("Received error message {} from {}", msg, dpid); + } else { + log.warn("Received error message {} from {}", msg, dpid); + } + + OFErrorMsg error = (OFErrorMsg) msg; + if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) { + OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error; + if (fmFailed.getData().getParsedMessage().isPresent()) { + OFMessage m = fmFailed.getData().getParsedMessage().get(); + OFFlowMod fm = (OFFlowMod) m; + InternalCacheEntry entry = + pendingBatches.getIfPresent(msg.getXid()); + if (entry != null) { + entry.appendFailure(new FlowEntryBuilder(dpid, fm).build()); + } else { + log.error("No matching batch for this error: {}", error); + } + } else { + // FIXME: Potentially add flowtracking to avoid this message. + log.error("Flow installation failed but switch didn't" + + " tell us which one."); + } + } + break; + default: + log.debug("Unhandled message type: {}", msg.getType()); + } + + } + + @Override + public void receivedRoleReply(Dpid dpid, RoleState requested, + RoleState response) { + // Do nothing here for now. + } + + private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) { + + DeviceId did = DeviceId.deviceId(Dpid.uri(dpid)); + OpenFlowSwitch sw = controller.getSwitch(dpid); + + List flowEntries = replies.getEntries().stream() + .map(entry -> new FlowEntryBuilder(dpid, entry).build()) + .collect(Collectors.toList()); + + providerService.pushFlowMetrics(did, flowEntries); + } + } + + /** + * The internal cache entry holding the original request as well as + * accumulating the any failures along the way. + *

+ * If this entry is evicted from the cache then the entire operation is + * considered failed. Otherwise, only the failures reported by the device + * will be propagated up. + */ + private class InternalCacheEntry { + + private final FlowRuleBatchOperation operation; + private final Set failures = Sets.newConcurrentHashSet(); + + public InternalCacheEntry(FlowRuleBatchOperation operation) { + this.operation = operation; + } + + /** + * Appends a failed rule to the set of failed items. + * + * @param rule the failed rule + */ + public void appendFailure(FlowRule rule) { + failures.add(rule); + } + + /** + * Fails the entire batch and returns the failed operation. + * + * @return the failed operation + */ + public CompletedBatchOperation failedCompletion() { + Set fails = operation.getOperations().stream() + .map(op -> op.target()).collect(Collectors.toSet()); + return new CompletedBatchOperation(false, + Collections + .unmodifiableSet(fails), + operation.deviceId()); + } + + /** + * Returns the completed operation and whether the batch suceeded. + * + * @return the completed operation + */ + public CompletedBatchOperation completed() { + return new CompletedBatchOperation( + failures.isEmpty(), + Collections + .unmodifiableSet(failures), + operation.deviceId()); + } + } + +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java new file mode 100644 index 00000000..2f0831c6 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowValueMapper.java @@ -0,0 +1,152 @@ +/* + * 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.provider.of.flow.impl; + +import com.google.common.collect.BiMap; +import com.google.common.collect.EnumHashBiMap; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.OchSignalType; + +/** + * Collection of helper methods to convert protocol agnostic models to values used in OpenFlow spec. + */ +final class OpenFlowValueMapper { + + // prohibit instantiation + private OpenFlowValueMapper() {} + + private static final BiMap GRID_TYPES = EnumHashBiMap.create(GridType.class); + static { + // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values + GRID_TYPES.put(GridType.DWDM, (byte) 1); // OFPGRIDT_DWDM of enum ofp_grid_type + GRID_TYPES.put(GridType.CWDM, (byte) 2); // OFPGRIDT_CWDM of enum ofp_grid_type + GRID_TYPES.put(GridType.FLEX, (byte) 3); // OFPGRIDT_FLEX of enum ofp_grid_type + } + + private static final BiMap CHANNEL_SPACING = EnumHashBiMap.create(ChannelSpacing.class); + static { + // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values + CHANNEL_SPACING.put(ChannelSpacing.CHL_100GHZ, (byte) 1); // OFPCS_100GHZ of enum ofp_chl_spacing + CHANNEL_SPACING.put(ChannelSpacing.CHL_50GHZ, (byte) 2); // OFPCS_50GHZ of enum ofp_chl_spacing + CHANNEL_SPACING.put(ChannelSpacing.CHL_25GHZ, (byte) 3); // OFPCS_25GHZ of enum ofp_chl_spacing + CHANNEL_SPACING.put(ChannelSpacing.CHL_12P5GHZ, (byte) 4); // OFPCS_12P5GHZ of enum ofp_chl_spacing + CHANNEL_SPACING.put(ChannelSpacing.CHL_6P25GHZ, (byte) 5); // OFPCS_6P25GHZ of enum ofp_chl_spacing + } + + private static final BiMap OCH_SIGNAL_TYPES = EnumHashBiMap.create(OchSignalType.class); + static { + // See ONF "Optical Transport Protocol Extensions Version 1.0" for the following values + OCH_SIGNAL_TYPES.put(OchSignalType.FIXED_GRID, (byte) 1); // OFPOCHT_FIX_GRID of enum ofp_och_signal_type + OCH_SIGNAL_TYPES.put(OchSignalType.FLEX_GRID, (byte) 2); // OFPOCHT_FLEX_GRID of enum ofp_och_signal_type + } + + /** + * Looks up the specified input value to the corresponding value with the specified map. + * + * @param map bidirectional mapping + * @param input input value + * @param cls class of output value + * @param type of input value + * @param type of output value + * @return the corresponding value stored in the specified map + * @throws NoMappingFoundException if no corresponding value is found + */ + private static O lookup(BiMap map, I input, Class cls) { + if (!map.containsKey(input)) { + throw new NoMappingFoundException(input, cls); + } + + return map.get(input); + } + + /** + * Looks up the corresponding byte value defined in + * ONF "Optical Transport Protocol Extensions Version 1.0" + * from the specified {@link GridType} instance. + * + * @param type grid type + * @return the byte value corresponding to the specified grid type + * @throws NoMappingFoundException if the specified grid type is not found + */ + static byte lookupGridType(GridType type) { + return lookup(GRID_TYPES, type, Byte.class); + } + + /** + * Looks up the corresponding {@link GridType} instance + * from the specified byte value for grid type + * defined in ONF "Optical Transport Protocol Extensions Version 1.0". + * + * @param type byte value as grid type defined the spec + * @return the corresponding GridType instance + */ + static GridType lookupGridType(byte type) { + return lookup(GRID_TYPES.inverse(), type, GridType.class); + } + + /** + * Looks up the corresponding byte value for channel spacing defined in + * ONF "Optical Transport Protocol Extensions Version 1.0" + * from the specified {@link ChannelSpacing} instance. + * + * @param spacing channel spacing + * @return byte value corresponding to the specified channel spacing + * @throws NoMappingFoundException if the specified channel spacing is not found + */ + static byte lookupChannelSpacing(ChannelSpacing spacing) { + return lookup(CHANNEL_SPACING, spacing, Byte.class); + } + + /** + * Looks up the corresponding {@link ChannelSpacing} instance + * from the specified byte value for channel spacing + * defined in ONF "Optical Transport Protocol Extensions Version 1.0". + * + * @param spacing byte value as channel spacing defined the spec + * @return the corresponding ChannelSpacing instance + * @throws NoMappingFoundException if the specified channel spacing is not found + */ + static ChannelSpacing lookupChannelSpacing(byte spacing) { + return lookup(CHANNEL_SPACING.inverse(), spacing, ChannelSpacing.class); + } + + /** + * Looks up the corresponding byte value for Och signal type defined in + * ONF "Optical Transport Protocol Extensions Version 1.0" + * from the specified {@link OchSignalType} instance. + * + * @param signalType optical signal type + * @return byte value corresponding to the specified OCh signal type + * @throws NoMappingFoundException if the specified Och signal type is not found + */ + static byte lookupOchSignalType(OchSignalType signalType) { + return lookup(OCH_SIGNAL_TYPES, signalType, Byte.class); + } + + /** + * Looks up the the corresponding {@link OchSignalType} instance + * from the specified byte value for Och signal type defined in + * ONF "Optical Transport Protocol Extensions Version 1.0". + * + * @param signalType byte value as Och singal type defined the spec + * @return the corresponding OchSignalType instance + * @throws NoMappingFoundException if the specified Och signal type is not found + */ + static OchSignalType lookupOchSignalType(byte signalType) { + return lookup(OCH_SIGNAL_TYPES.inverse(), signalType, OchSignalType.class); + } +} diff --git a/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java new file mode 100644 index 00000000..2acc1510 --- /dev/null +++ b/framework/src/onos/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Provider that uses OpenFlow controller as a means of ending and receiving flow information. + */ +package org.onosproject.provider.of.flow.impl; -- cgit 1.2.3-korg