| /* |
| * Copyright 2015-present Open Networking Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.codec.impl; |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.databind.node.ObjectNode; |
| import com.google.common.collect.Maps; |
| import org.onlab.osgi.DefaultServiceDirectory; |
| import org.onlab.osgi.ServiceDirectory; |
| import org.onlab.packet.EthType; |
| import org.onlab.packet.IpAddress; |
| import org.onlab.packet.MacAddress; |
| import org.onlab.packet.MplsLabel; |
| import org.onlab.packet.TpPort; |
| import org.onlab.packet.VlanId; |
| import org.onlab.util.HexString; |
| import org.onlab.util.ImmutableByteSequence; |
| import org.onosproject.codec.CodecContext; |
| import org.onosproject.core.GroupId; |
| import org.onosproject.net.ChannelSpacing; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.GridType; |
| import org.onosproject.net.OchSignal; |
| import org.onosproject.net.OduSignalId; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.device.DeviceService; |
| import org.onosproject.net.flow.ExtensionTreatmentCodec; |
| import org.onosproject.net.flow.StatTriggerField; |
| import org.onosproject.net.flow.StatTriggerFlag; |
| import org.onosproject.net.flow.instructions.ExtensionTreatment; |
| import org.onosproject.net.flow.instructions.Instruction; |
| import org.onosproject.net.flow.instructions.Instructions; |
| import org.onosproject.net.flow.instructions.L0ModificationInstruction; |
| import org.onosproject.net.flow.instructions.L1ModificationInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction; |
| import org.onosproject.net.flow.instructions.L3ModificationInstruction; |
| import org.onosproject.net.flow.instructions.L4ModificationInstruction; |
| import org.onosproject.net.meter.MeterId; |
| import org.onosproject.net.pi.model.PiActionId; |
| import org.onosproject.net.pi.model.PiActionParamId; |
| import org.onosproject.net.pi.runtime.PiAction; |
| import org.onosproject.net.pi.runtime.PiActionParam; |
| import org.onosproject.net.pi.runtime.PiActionProfileGroupId; |
| import org.onosproject.net.pi.runtime.PiActionProfileMemberId; |
| import org.onosproject.net.pi.runtime.PiTableAction; |
| import org.slf4j.Logger; |
| |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import static org.onlab.util.Tools.nullIsIllegal; |
| import static org.onosproject.codec.impl.InstructionCodec.STAT_PACKET_COUNT; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Decoding portion of the instruction codec. |
| */ |
| public final class DecodeInstructionCodecHelper { |
| private static final Logger log = getLogger(DecodeInstructionCodecHelper.class); |
| private final ObjectNode json; |
| private final CodecContext context; |
| private static final Pattern ETHTYPE_PATTERN = Pattern.compile("0x([0-9a-fA-F]{4})"); |
| |
| /** |
| * Creates a decode instruction codec object. |
| * |
| * @param json JSON object to decode |
| * @param context codec context |
| */ |
| public DecodeInstructionCodecHelper(ObjectNode json, CodecContext context) { |
| this.json = json; |
| this.context = context; |
| } |
| |
| /** |
| * Decodes a Layer 2 instruction. |
| * |
| * @return instruction object decoded from the JSON |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private Instruction decodeL2() { |
| String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE), |
| InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) { |
| String mac = nullIsIllegal(json.get(InstructionCodec.MAC), |
| InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); |
| return Instructions.modL2Src(MacAddress.valueOf(mac)); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) { |
| String mac = nullIsIllegal(json.get(InstructionCodec.MAC), |
| InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); |
| return Instructions.modL2Dst(MacAddress.valueOf(mac)); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) { |
| short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID), |
| InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| return Instructions.modVlanId(VlanId.vlanId(vlanId)); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) { |
| byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP), |
| InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| return Instructions.modVlanPcp(vlanPcp); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) { |
| int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL), |
| InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| return Instructions.modMplsLabel(MplsLabel.mplsLabel(label)); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) { |
| return Instructions.pushMpls(); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) { |
| if (json.has(InstructionCodec.ETHERNET_TYPE)) { |
| return Instructions.popMpls(getEthType()); |
| } |
| return Instructions.popMpls(); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) { |
| return Instructions.decMplsTtl(); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) { |
| return Instructions.popVlan(); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) { |
| if (json.has(InstructionCodec.ETHERNET_TYPE)) { |
| return Instructions.pushVlan(getEthType()); |
| } |
| return Instructions.pushVlan(); |
| } else if (subType.equals(L2ModificationInstruction.L2SubType.TUNNEL_ID.name())) { |
| long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID), |
| InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong(); |
| return Instructions.modTunnelId(tunnelId); |
| } |
| throw new IllegalArgumentException("L2 Instruction subtype " |
| + subType + " is not supported"); |
| } |
| |
| /** |
| * Decodes a Layer 3 instruction. |
| * |
| * @return instruction object decoded from the JSON |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private Instruction decodeL3() { |
| String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE), |
| InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) { |
| IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), |
| InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); |
| return Instructions.modL3Src(ip); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) { |
| IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), |
| InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); |
| return Instructions.modL3Dst(ip); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) { |
| IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), |
| InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); |
| return Instructions.modL3IPv6Src(ip); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) { |
| IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), |
| InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); |
| return Instructions.modL3IPv6Dst(ip); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) { |
| int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL), |
| InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| return Instructions.modL3IPv6FlowLabel(flowLabel); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.TTL_IN.name())) { |
| return Instructions.copyTtlIn(); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.TTL_OUT.name())) { |
| return Instructions.copyTtlOut(); |
| } else if (subType.equals(L3ModificationInstruction.L3SubType.DEC_TTL.name())) { |
| return Instructions.decNwTtl(); |
| } |
| throw new IllegalArgumentException("L3 Instruction subtype " |
| + subType + " is not supported"); |
| } |
| |
| /** |
| * Decodes a Layer 0 instruction. |
| * |
| * @return instruction object decoded from the JSON |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private Instruction decodeL0() { |
| String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE), |
| InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) { |
| String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE), |
| InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); |
| GridType gridType = GridType.valueOf(gridTypeString); |
| if (gridType == null) { |
| throw new IllegalArgumentException("Unknown grid type " |
| + gridTypeString); |
| } |
| String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING), |
| InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); |
| ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString); |
| if (channelSpacing == null) { |
| throw new IllegalArgumentException("Unknown channel spacing " |
| + channelSpacingString); |
| } |
| int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER), |
| InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY), |
| InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing, |
| spacingMultiplier, slotGranularity)); |
| } |
| throw new IllegalArgumentException("L0 Instruction subtype " |
| + subType + " is not supported"); |
| } |
| |
| /** |
| * Decodes a Layer 1 instruction. |
| * |
| * @return instruction object decoded from the JSON |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private Instruction decodeL1() { |
| String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE), |
| InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) { |
| int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER), |
| InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN), |
| InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); |
| byte[] tributarySlotBitmap = null; |
| tributarySlotBitmap = HexString.fromHexString( |
| nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP), |
| InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); |
| return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, |
| tributarySlotBitmap)); |
| } |
| throw new IllegalArgumentException("L1 Instruction subtype " |
| + subType + " is not supported"); |
| } |
| |
| /** |
| * Decodes a Layer 4 instruction. |
| * |
| * @return instruction object decoded from the JSON |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private Instruction decodeL4() { |
| String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE), |
| InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| if (subType.equals(L4ModificationInstruction.L4SubType.TCP_DST.name())) { |
| TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT), |
| InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| return Instructions.modTcpDst(tcpPort); |
| } else if (subType.equals(L4ModificationInstruction.L4SubType.TCP_SRC.name())) { |
| TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT), |
| InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| return Instructions.modTcpSrc(tcpPort); |
| } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_DST.name())) { |
| TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT), |
| InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| return Instructions.modUdpDst(udpPort); |
| } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_SRC.name())) { |
| TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT), |
| InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| return Instructions.modUdpSrc(udpPort); |
| } |
| throw new IllegalArgumentException("L4 Instruction subtype " |
| + subType + " is not supported"); |
| } |
| |
| /** |
| * Decodes a protocol-independent instruction. |
| * |
| * @return instruction object decoded from the JSON |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private Instruction decodePi() { |
| String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE), |
| InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| if (subType.equals(PiTableAction.Type.ACTION.name())) { |
| PiActionId piActionId = PiActionId.of(nullIsIllegal( |
| json.get(InstructionCodec.PI_ACTION_ID), |
| InstructionCodec.PI_ACTION_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); |
| JsonNode params = json.get(InstructionCodec.PI_ACTION_PARAMS); |
| |
| PiAction.Builder builder = PiAction.builder(); |
| PiActionParam piActionParam; |
| PiActionParamId piActionParamId; |
| if (params != null) { |
| for (Map.Entry<String, String> param : ((Map<String, String>) |
| (context.mapper().convertValue(params, Map.class))).entrySet()) { |
| piActionParamId = PiActionParamId.of(param.getKey()); |
| piActionParam = new PiActionParam(piActionParamId, |
| ImmutableByteSequence.copyFrom( |
| HexString.fromHexString(param.getValue(), null))); |
| builder.withParameter(piActionParam); |
| } |
| } |
| |
| return Instructions.piTableAction(builder.withId(piActionId).build()); |
| } else if (subType.equals(PiTableAction.Type.ACTION_PROFILE_GROUP_ID.name())) { |
| PiActionProfileGroupId piActionGroupId = PiActionProfileGroupId.of(nullIsIllegal( |
| json.get(InstructionCodec.PI_ACTION_PROFILE_GROUP_ID), |
| InstructionCodec.PI_ACTION_PROFILE_GROUP_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| |
| return Instructions.piTableAction(piActionGroupId); |
| } else if (subType.equals(PiTableAction.Type.ACTION_PROFILE_MEMBER_ID.name())) { |
| PiActionProfileMemberId piActionProfileMemberId = PiActionProfileMemberId.of(nullIsIllegal( |
| json.get(InstructionCodec.PI_ACTION_PROFILE_MEMBER_ID), |
| InstructionCodec.PI_ACTION_PROFILE_MEMBER_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| |
| return Instructions.piTableAction(piActionProfileMemberId); |
| } |
| throw new IllegalArgumentException("Protocol-independent Instruction subtype " |
| + subType + " is not supported"); |
| } |
| |
| private Instruction decodeStatTrigger() { |
| String statTriggerFlag = nullIsIllegal(json.get(InstructionCodec.STAT_TRIGGER_FLAG), |
| InstructionCodec.STAT_TRIGGER_FLAG + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| StatTriggerFlag flag = null; |
| |
| if (statTriggerFlag.equals(StatTriggerFlag.ONLY_FIRST.name())) { |
| flag = StatTriggerFlag.ONLY_FIRST; |
| } else if (statTriggerFlag.equals(StatTriggerFlag.PERIODIC.name())) { |
| flag = StatTriggerFlag.PERIODIC; |
| } else { |
| throw new IllegalArgumentException("statTriggerFlag " |
| + statTriggerFlag + " is not supported"); |
| } |
| if (!json.has(InstructionCodec.STAT_THRESHOLDS)) { |
| throw new IllegalArgumentException("statThreshold is not added"); |
| } |
| JsonNode statThresholdsNode = nullIsIllegal(json.get(InstructionCodec.STAT_THRESHOLDS), |
| InstructionCodec.STAT_THRESHOLDS + InstructionCodec.ERROR_MESSAGE); |
| Map<StatTriggerField, Long> statThresholdMap = getStatThreshold(statThresholdsNode); |
| if (statThresholdMap.isEmpty()) { |
| throw new IllegalArgumentException("statThreshold must have at least one property"); |
| } |
| return Instructions.statTrigger(statThresholdMap, flag); |
| } |
| |
| private Map<StatTriggerField, Long> getStatThreshold(JsonNode statThresholdNode) { |
| Map<StatTriggerField, Long> statThresholdMap = Maps.newEnumMap(StatTriggerField.class); |
| for (JsonNode jsonNode : statThresholdNode) { |
| if (jsonNode.hasNonNull(InstructionCodec.STAT_BYTE_COUNT)) { |
| JsonNode byteCountNode = jsonNode.get(InstructionCodec.STAT_BYTE_COUNT); |
| if (!byteCountNode.isNull() && byteCountNode.isNumber()) { |
| statThresholdMap.put(StatTriggerField.BYTE_COUNT, byteCountNode.asLong()); |
| } |
| } else if (jsonNode.hasNonNull(STAT_PACKET_COUNT)) { |
| JsonNode packetCount = jsonNode.get(STAT_PACKET_COUNT); |
| if (!packetCount.isNull() && packetCount.isNumber()) { |
| statThresholdMap.put(StatTriggerField.PACKET_COUNT, packetCount.asLong()); |
| } |
| } else if (jsonNode.hasNonNull(InstructionCodec.STAT_DURATION)) { |
| JsonNode duration = jsonNode.get(InstructionCodec.STAT_DURATION); |
| if (!duration.isNull() && duration.isNumber()) { |
| statThresholdMap.put(StatTriggerField.DURATION, duration.asLong()); |
| } |
| } else { |
| log.error("Unsupported stat {}", jsonNode.toString()); |
| } |
| } |
| |
| return statThresholdMap; |
| } |
| |
| /** |
| * Decodes a extension instruction. |
| * |
| * @return extension treatment |
| */ |
| private Instruction decodeExtension() { |
| ObjectNode node = (ObjectNode) json.get(InstructionCodec.EXTENSION); |
| if (node != null) { |
| DeviceId deviceId = getDeviceId(); |
| |
| ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); |
| DeviceService deviceService = serviceDirectory.get(DeviceService.class); |
| Device device = deviceService.getDevice(deviceId); |
| |
| if (device == null) { |
| throw new IllegalArgumentException("Device not found"); |
| } |
| |
| if (device.is(ExtensionTreatmentCodec.class)) { |
| ExtensionTreatmentCodec treatmentCodec = device.as(ExtensionTreatmentCodec.class); |
| ExtensionTreatment treatment = treatmentCodec.decode(node, context); |
| return Instructions.extension(treatment, deviceId); |
| } else { |
| throw new IllegalArgumentException( |
| "There is no codec to decode extension for device " + deviceId.toString()); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns device identifier. |
| * |
| * @return device identifier |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private DeviceId getDeviceId() { |
| JsonNode deviceIdNode = json.get(InstructionCodec.DEVICE_ID); |
| if (deviceIdNode != null) { |
| return DeviceId.deviceId(deviceIdNode.asText()); |
| } |
| throw new IllegalArgumentException("Empty device identifier"); |
| } |
| |
| /** |
| * Extracts port number of the given json node. |
| * |
| * @param jsonNode json node |
| * @return port number |
| */ |
| private PortNumber getPortNumber(ObjectNode jsonNode) { |
| PortNumber portNumber; |
| JsonNode portNode = nullIsIllegal(jsonNode.get(InstructionCodec.PORT), |
| InstructionCodec.PORT + InstructionCodec.ERROR_MESSAGE); |
| if (portNode.isLong() || portNode.isInt()) { |
| portNumber = PortNumber.portNumber(portNode.asLong()); |
| } else if (portNode.isTextual()) { |
| portNumber = PortNumber.fromString(portNode.textValue()); |
| } else { |
| throw new IllegalArgumentException("Port value " |
| + portNode.toString() |
| + " is not supported"); |
| } |
| return portNumber; |
| } |
| |
| /** |
| * Returns Ethernet type. |
| * |
| * @return ethernet type |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| private EthType getEthType() { |
| String ethTypeStr = nullIsIllegal(json.get(InstructionCodec.ETHERNET_TYPE), |
| InstructionCodec.ETHERNET_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); |
| Matcher matcher = ETHTYPE_PATTERN.matcher(ethTypeStr); |
| if (!matcher.matches()) { |
| throw new IllegalArgumentException("ETHERNET_TYPE must be a four digit hex string starting with 0x"); |
| } |
| short ethernetType = (short) Integer.parseInt(matcher.group(1), 16); |
| return new EthType(ethernetType); |
| } |
| |
| /** |
| * Decodes the JSON into an instruction object. |
| * |
| * @return Criterion object |
| * @throws IllegalArgumentException if the JSON is invalid |
| */ |
| public Instruction decode() { |
| String type = nullIsIllegal(json.get(InstructionCodec.TYPE), |
| InstructionCodec.TYPE + InstructionCodec.ERROR_MESSAGE).asText(); |
| |
| if (type.equals(Instruction.Type.OUTPUT.name())) { |
| return Instructions.createOutput(getPortNumber(json)); |
| } else if (type.equals(Instruction.Type.NOACTION.name())) { |
| return Instructions.createNoAction(); |
| } else if (type.equals(Instruction.Type.TABLE.name())) { |
| return Instructions.transition(nullIsIllegal(json.get(InstructionCodec.TABLE_ID), |
| InstructionCodec.TABLE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| } else if (type.equals(Instruction.Type.GROUP.name())) { |
| GroupId groupId = new GroupId(nullIsIllegal(json.get(InstructionCodec.GROUP_ID), |
| InstructionCodec.GROUP_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); |
| return Instructions.createGroup(groupId); |
| } else if (type.equals(Instruction.Type.METER.name())) { |
| MeterId meterId = MeterId.meterId(nullIsIllegal(json.get(InstructionCodec.METER_ID), |
| InstructionCodec.METER_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong()); |
| return Instructions.meterTraffic(meterId); |
| } else if (type.equals(Instruction.Type.QUEUE.name())) { |
| long queueId = nullIsIllegal(json.get(InstructionCodec.QUEUE_ID), |
| InstructionCodec.QUEUE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong(); |
| if (json.get(InstructionCodec.PORT) == null || |
| json.get(InstructionCodec.PORT).isNull()) { |
| return Instructions.setQueue(queueId, null); |
| } else { |
| return Instructions.setQueue(queueId, getPortNumber(json)); |
| } |
| } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) { |
| return decodeL0(); |
| } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) { |
| return decodeL1(); |
| } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) { |
| return decodeL2(); |
| } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) { |
| return decodeL3(); |
| } else if (type.equals(Instruction.Type.L4MODIFICATION.name())) { |
| return decodeL4(); |
| } else if (type.equals(Instruction.Type.EXTENSION.name())) { |
| return decodeExtension(); |
| } else if (type.equals(Instruction.Type.STAT_TRIGGER.name())) { |
| return decodeStatTrigger(); |
| } else if (type.equals(Instruction.Type.PROTOCOL_INDEPENDENT.name())) { |
| return decodePi(); |
| } |
| |
| throw new IllegalArgumentException("Instruction type " |
| + type + " is not supported"); |
| } |
| } |