Committed by
Gerrit Code Review
REST API to create flows
Change-Id: I5d001782249c0eab249d7aa857ae465da95b5955
Showing
22 changed files
with
815 additions
and
164 deletions
| ... | @@ -35,6 +35,7 @@ import org.onosproject.net.Path; | ... | @@ -35,6 +35,7 @@ import org.onosproject.net.Path; |
| 35 | import org.onosproject.net.Port; | 35 | import org.onosproject.net.Port; |
| 36 | import org.onosproject.net.driver.Driver; | 36 | import org.onosproject.net.driver.Driver; |
| 37 | import org.onosproject.net.flow.FlowEntry; | 37 | import org.onosproject.net.flow.FlowEntry; |
| 38 | +import org.onosproject.net.flow.FlowRule; | ||
| 38 | import org.onosproject.net.flow.TrafficSelector; | 39 | import org.onosproject.net.flow.TrafficSelector; |
| 39 | import org.onosproject.net.flow.TrafficTreatment; | 40 | import org.onosproject.net.flow.TrafficTreatment; |
| 40 | import org.onosproject.net.flow.criteria.Criterion; | 41 | import org.onosproject.net.flow.criteria.Criterion; |
| ... | @@ -83,6 +84,7 @@ public class CodecManager implements CodecService { | ... | @@ -83,6 +84,7 @@ public class CodecManager implements CodecService { |
| 83 | registerCodec(Intent.class, new IntentCodec()); | 84 | registerCodec(Intent.class, new IntentCodec()); |
| 84 | registerCodec(ConnectivityIntent.class, new ConnectivityIntentCodec()); | 85 | registerCodec(ConnectivityIntent.class, new ConnectivityIntentCodec()); |
| 85 | registerCodec(FlowEntry.class, new FlowEntryCodec()); | 86 | registerCodec(FlowEntry.class, new FlowEntryCodec()); |
| 87 | + registerCodec(FlowRule.class, new FlowRuleCodec()); | ||
| 86 | registerCodec(TrafficTreatment.class, new TrafficTreatmentCodec()); | 88 | registerCodec(TrafficTreatment.class, new TrafficTreatmentCodec()); |
| 87 | registerCodec(TrafficSelector.class, new TrafficSelectorCodec()); | 89 | registerCodec(TrafficSelector.class, new TrafficSelectorCodec()); |
| 88 | registerCodec(Instruction.class, new InstructionCodec()); | 90 | registerCodec(Instruction.class, new InstructionCodec()); | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.codec.impl; | ||
| 17 | + | ||
| 18 | +import org.onlab.packet.IpAddress; | ||
| 19 | +import org.onlab.packet.MacAddress; | ||
| 20 | +import org.onlab.packet.MplsLabel; | ||
| 21 | +import org.onlab.packet.VlanId; | ||
| 22 | +import org.onosproject.net.ChannelSpacing; | ||
| 23 | +import org.onosproject.net.GridType; | ||
| 24 | +import org.onosproject.net.Lambda; | ||
| 25 | +import org.onosproject.net.OchSignal; | ||
| 26 | +import org.onosproject.net.PortNumber; | ||
| 27 | +import org.onosproject.net.flow.instructions.Instruction; | ||
| 28 | +import org.onosproject.net.flow.instructions.Instructions; | ||
| 29 | +import org.onosproject.net.flow.instructions.L0ModificationInstruction; | ||
| 30 | +import org.onosproject.net.flow.instructions.L2ModificationInstruction; | ||
| 31 | +import org.onosproject.net.flow.instructions.L3ModificationInstruction; | ||
| 32 | + | ||
| 33 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 34 | + | ||
| 35 | +import static org.onlab.util.Tools.nullIsIllegal; | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * Decoding portion of the instruction codec. | ||
| 39 | + */ | ||
| 40 | +public final class DecodeInstructionCodec { | ||
| 41 | + private final ObjectNode json; | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * Creates a decode instruction codec object. | ||
| 45 | + * | ||
| 46 | + * @param json JSON object to decode | ||
| 47 | + */ | ||
| 48 | + public DecodeInstructionCodec(ObjectNode json) { | ||
| 49 | + this.json = json; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * Decodes a Layer 2 instruction. | ||
| 54 | + * | ||
| 55 | + * @return instruction object decoded from the JSON | ||
| 56 | + * @throws IllegalArgumentException if the JSON is invalid | ||
| 57 | + */ | ||
| 58 | + private Instruction decodeL2() { | ||
| 59 | + String subType = json.get(InstructionCodec.SUBTYPE).asText(); | ||
| 60 | + | ||
| 61 | + if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) { | ||
| 62 | + String mac = nullIsIllegal(json.get(InstructionCodec.MAC), | ||
| 63 | + InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
| 64 | + return Instructions.modL2Src(MacAddress.valueOf(mac)); | ||
| 65 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) { | ||
| 66 | + String mac = nullIsIllegal(json.get(InstructionCodec.MAC), | ||
| 67 | + InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
| 68 | + return Instructions.modL2Dst(MacAddress.valueOf(mac)); | ||
| 69 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) { | ||
| 70 | + short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID), | ||
| 71 | + InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 72 | + return Instructions.modVlanId(VlanId.vlanId(vlanId)); | ||
| 73 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) { | ||
| 74 | + byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP), | ||
| 75 | + InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 76 | + return Instructions.modVlanPcp(vlanPcp); | ||
| 77 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) { | ||
| 78 | + int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL), | ||
| 79 | + InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 80 | + return Instructions.modMplsLabel(MplsLabel.mplsLabel(label)); | ||
| 81 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) { | ||
| 82 | + return Instructions.pushMpls(); | ||
| 83 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) { | ||
| 84 | + return Instructions.popMpls(); | ||
| 85 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) { | ||
| 86 | + return Instructions.decMplsTtl(); | ||
| 87 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) { | ||
| 88 | + return Instructions.popVlan(); | ||
| 89 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) { | ||
| 90 | + return Instructions.pushVlan(); | ||
| 91 | + } | ||
| 92 | + throw new IllegalArgumentException("L2 Instruction subtype " | ||
| 93 | + + subType + " is not supported"); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + /** | ||
| 97 | + * Decodes a Layer 3 instruction. | ||
| 98 | + * | ||
| 99 | + * @return instruction object decoded from the JSON | ||
| 100 | + * @throws IllegalArgumentException if the JSON is invalid | ||
| 101 | + */ | ||
| 102 | + private Instruction decodeL3() { | ||
| 103 | + String subType = json.get(InstructionCodec.SUBTYPE).asText(); | ||
| 104 | + | ||
| 105 | + if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) { | ||
| 106 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
| 107 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
| 108 | + return Instructions.modL3Src(ip); | ||
| 109 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) { | ||
| 110 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
| 111 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
| 112 | + return Instructions.modL3Dst(ip); | ||
| 113 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) { | ||
| 114 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
| 115 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
| 116 | + return Instructions.modL3IPv6Src(ip); | ||
| 117 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) { | ||
| 118 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
| 119 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
| 120 | + return Instructions.modL3IPv6Dst(ip); | ||
| 121 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) { | ||
| 122 | + int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL), | ||
| 123 | + InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 124 | + return Instructions.modL3IPv6FlowLabel(flowLabel); | ||
| 125 | + } | ||
| 126 | + throw new IllegalArgumentException("L3 Instruction subtype " | ||
| 127 | + + subType + " is not supported"); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * Decodes a Layer 0 instruction. | ||
| 132 | + * | ||
| 133 | + * @return instruction object decoded from the JSON | ||
| 134 | + * @throws IllegalArgumentException if the JSON is invalid | ||
| 135 | + */ | ||
| 136 | + private Instruction decodeL0() { | ||
| 137 | + String subType = json.get(InstructionCodec.SUBTYPE).asText(); | ||
| 138 | + | ||
| 139 | + | ||
| 140 | + if (subType.equals(L0ModificationInstruction.L0SubType.LAMBDA.name())) { | ||
| 141 | + int lambda = nullIsIllegal(json.get(InstructionCodec.LAMBDA), | ||
| 142 | + InstructionCodec.LAMBDA + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 143 | + return Instructions.modL0Lambda(Lambda.indexedLambda(lambda)); | ||
| 144 | + } else if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) { | ||
| 145 | + String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE), | ||
| 146 | + InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
| 147 | + GridType gridType = GridType.valueOf(gridTypeString); | ||
| 148 | + if (gridType == null) { | ||
| 149 | + throw new IllegalArgumentException("Unknown grid type " | ||
| 150 | + + gridTypeString); | ||
| 151 | + } | ||
| 152 | + String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING), | ||
| 153 | + InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
| 154 | + ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString); | ||
| 155 | + if (channelSpacing == null) { | ||
| 156 | + throw new IllegalArgumentException("Unknown channel spacing " | ||
| 157 | + + channelSpacingString); | ||
| 158 | + } | ||
| 159 | + int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER), | ||
| 160 | + InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 161 | + int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY), | ||
| 162 | + InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
| 163 | + return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing, | ||
| 164 | + spacingMultiplier, slotGranularity)); | ||
| 165 | + } | ||
| 166 | + throw new IllegalArgumentException("L0 Instruction subtype " | ||
| 167 | + + subType + " is not supported"); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + /** | ||
| 171 | + * Decodes the JSON into an instruction object. | ||
| 172 | + * | ||
| 173 | + * @return Criterion object | ||
| 174 | + * @throws IllegalArgumentException if the JSON is invalid | ||
| 175 | + */ | ||
| 176 | + public Instruction decode() { | ||
| 177 | + String type = json.get(InstructionCodec.TYPE).asText(); | ||
| 178 | + | ||
| 179 | + if (type.equals(Instruction.Type.OUTPUT.name())) { | ||
| 180 | + PortNumber portNumber = | ||
| 181 | + PortNumber.portNumber(nullIsIllegal(json.get(InstructionCodec.PORT), | ||
| 182 | + InstructionCodec.PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong()); | ||
| 183 | + return Instructions.createOutput(portNumber); | ||
| 184 | + } else if (type.equals(Instruction.Type.DROP.name())) { | ||
| 185 | + return Instructions.createDrop(); | ||
| 186 | + } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) { | ||
| 187 | + return decodeL0(); | ||
| 188 | + } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) { | ||
| 189 | + return decodeL2(); | ||
| 190 | + } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) { | ||
| 191 | + return decodeL3(); | ||
| 192 | + } | ||
| 193 | + throw new IllegalArgumentException("Instruction type " | ||
| 194 | + + type + " is not supported"); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | +} |
This diff is collapsed. Click to expand it.
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.codec.impl; | ||
| 17 | + | ||
| 18 | +import org.onosproject.codec.CodecContext; | ||
| 19 | +import org.onosproject.net.OchSignal; | ||
| 20 | +import org.onosproject.net.flow.instructions.Instruction; | ||
| 21 | +import org.onosproject.net.flow.instructions.Instructions; | ||
| 22 | +import org.onosproject.net.flow.instructions.L0ModificationInstruction; | ||
| 23 | +import org.onosproject.net.flow.instructions.L2ModificationInstruction; | ||
| 24 | +import org.onosproject.net.flow.instructions.L3ModificationInstruction; | ||
| 25 | +import org.slf4j.Logger; | ||
| 26 | +import org.slf4j.LoggerFactory; | ||
| 27 | + | ||
| 28 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * JSON encoding of Instructions. | ||
| 32 | + */ | ||
| 33 | +public final class EncodeInstructionCodec { | ||
| 34 | + protected static final Logger log = LoggerFactory.getLogger(EncodeInstructionCodec.class); | ||
| 35 | + private final Instruction instruction; | ||
| 36 | + private final CodecContext context; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Creates an instruction object encoder. | ||
| 40 | + * | ||
| 41 | + * @param instruction instruction to encode | ||
| 42 | + * @param context codec context for the encoding | ||
| 43 | + */ | ||
| 44 | + public EncodeInstructionCodec(Instruction instruction, CodecContext context) { | ||
| 45 | + this.instruction = instruction; | ||
| 46 | + this.context = context; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * Encode an L0 modification instruction. | ||
| 52 | + * | ||
| 53 | + * @param result json node that the instruction attributes are added to | ||
| 54 | + */ | ||
| 55 | + private void encodeL0(ObjectNode result) { | ||
| 56 | + L0ModificationInstruction instruction = | ||
| 57 | + (L0ModificationInstruction) this.instruction; | ||
| 58 | + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); | ||
| 59 | + | ||
| 60 | + switch (instruction.subtype()) { | ||
| 61 | + case LAMBDA: | ||
| 62 | + final L0ModificationInstruction.ModLambdaInstruction modLambdaInstruction = | ||
| 63 | + (L0ModificationInstruction.ModLambdaInstruction) instruction; | ||
| 64 | + result.put(InstructionCodec.LAMBDA, modLambdaInstruction.lambda()); | ||
| 65 | + break; | ||
| 66 | + | ||
| 67 | + case OCH: | ||
| 68 | + L0ModificationInstruction.ModOchSignalInstruction ochSignalInstruction = | ||
| 69 | + (L0ModificationInstruction.ModOchSignalInstruction) instruction; | ||
| 70 | + OchSignal ochSignal = ochSignalInstruction.lambda(); | ||
| 71 | + result.put(InstructionCodec.GRID_TYPE, ochSignal.gridType().name()); | ||
| 72 | + result.put(InstructionCodec.CHANNEL_SPACING, ochSignal.channelSpacing().name()); | ||
| 73 | + result.put(InstructionCodec.SPACING_MULTIPLIER, ochSignal.spacingMultiplier()); | ||
| 74 | + result.put(InstructionCodec.SLOT_GRANULARITY, ochSignal.slotGranularity()); | ||
| 75 | + break; | ||
| 76 | + | ||
| 77 | + default: | ||
| 78 | + log.info("Cannot convert L0 subtype of {}", instruction.subtype()); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * Encode an L2 modification instruction. | ||
| 84 | + * | ||
| 85 | + * @param result json node that the instruction attributes are added to | ||
| 86 | + */ | ||
| 87 | + private void encodeL2(ObjectNode result) { | ||
| 88 | + L2ModificationInstruction instruction = | ||
| 89 | + (L2ModificationInstruction) this.instruction; | ||
| 90 | + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); | ||
| 91 | + | ||
| 92 | + switch (instruction.subtype()) { | ||
| 93 | + case ETH_SRC: | ||
| 94 | + case ETH_DST: | ||
| 95 | + final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = | ||
| 96 | + (L2ModificationInstruction.ModEtherInstruction) instruction; | ||
| 97 | + result.put(InstructionCodec.MAC, modEtherInstruction.mac().toString()); | ||
| 98 | + break; | ||
| 99 | + | ||
| 100 | + case VLAN_ID: | ||
| 101 | + final L2ModificationInstruction.ModVlanIdInstruction modVlanIdInstruction = | ||
| 102 | + (L2ModificationInstruction.ModVlanIdInstruction) instruction; | ||
| 103 | + result.put(InstructionCodec.VLAN_ID, modVlanIdInstruction.vlanId().toShort()); | ||
| 104 | + break; | ||
| 105 | + | ||
| 106 | + case VLAN_PCP: | ||
| 107 | + final L2ModificationInstruction.ModVlanPcpInstruction modVlanPcpInstruction = | ||
| 108 | + (L2ModificationInstruction.ModVlanPcpInstruction) instruction; | ||
| 109 | + result.put(InstructionCodec.VLAN_PCP, modVlanPcpInstruction.vlanPcp()); | ||
| 110 | + break; | ||
| 111 | + | ||
| 112 | + case MPLS_LABEL: | ||
| 113 | + final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction = | ||
| 114 | + (L2ModificationInstruction.ModMplsLabelInstruction) instruction; | ||
| 115 | + result.put(InstructionCodec.MPLS_LABEL, modMplsLabelInstruction.label()); | ||
| 116 | + break; | ||
| 117 | + | ||
| 118 | + case MPLS_PUSH: | ||
| 119 | + final L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions = | ||
| 120 | + (L2ModificationInstruction.PushHeaderInstructions) instruction; | ||
| 121 | + | ||
| 122 | + result.put(InstructionCodec.ETHERNET_TYPE, pushHeaderInstructions.ethernetType()); | ||
| 123 | + break; | ||
| 124 | + | ||
| 125 | + default: | ||
| 126 | + log.info("Cannot convert L2 subtype of {}", instruction.subtype()); | ||
| 127 | + break; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * Encode an L3 modification instruction. | ||
| 133 | + * | ||
| 134 | + * @param result json node that the instruction attributes are added to | ||
| 135 | + */ | ||
| 136 | + private void encodeL3(ObjectNode result) { | ||
| 137 | + L3ModificationInstruction instruction = | ||
| 138 | + (L3ModificationInstruction) this.instruction; | ||
| 139 | + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); | ||
| 140 | + switch (instruction.subtype()) { | ||
| 141 | + case IPV4_SRC: | ||
| 142 | + case IPV4_DST: | ||
| 143 | + case IPV6_SRC: | ||
| 144 | + case IPV6_DST: | ||
| 145 | + final L3ModificationInstruction.ModIPInstruction modIPInstruction = | ||
| 146 | + (L3ModificationInstruction.ModIPInstruction) instruction; | ||
| 147 | + result.put(InstructionCodec.IP, modIPInstruction.ip().toString()); | ||
| 148 | + break; | ||
| 149 | + | ||
| 150 | + case IPV6_FLABEL: | ||
| 151 | + final L3ModificationInstruction.ModIPv6FlowLabelInstruction | ||
| 152 | + modFlowLabelInstruction = | ||
| 153 | + (L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction; | ||
| 154 | + result.put(InstructionCodec.FLOW_LABEL, modFlowLabelInstruction.flowLabel()); | ||
| 155 | + break; | ||
| 156 | + | ||
| 157 | + default: | ||
| 158 | + log.info("Cannot convert L3 subtype of {}", instruction.subtype()); | ||
| 159 | + break; | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + /** | ||
| 164 | + * Encodes the given instruction into JSON. | ||
| 165 | + * | ||
| 166 | + * @return JSON object node representing the instruction | ||
| 167 | + */ | ||
| 168 | + public ObjectNode encode() { | ||
| 169 | + final ObjectNode result = context.mapper().createObjectNode() | ||
| 170 | + .put(InstructionCodec.TYPE, instruction.type().toString()); | ||
| 171 | + | ||
| 172 | + switch (instruction.type()) { | ||
| 173 | + case OUTPUT: | ||
| 174 | + final Instructions.OutputInstruction outputInstruction = | ||
| 175 | + (Instructions.OutputInstruction) instruction; | ||
| 176 | + result.put(InstructionCodec.PORT, outputInstruction.port().toLong()); | ||
| 177 | + break; | ||
| 178 | + | ||
| 179 | + case DROP: | ||
| 180 | + break; | ||
| 181 | + | ||
| 182 | + case L0MODIFICATION: | ||
| 183 | + encodeL0(result); | ||
| 184 | + break; | ||
| 185 | + | ||
| 186 | + case L2MODIFICATION: | ||
| 187 | + encodeL2(result); | ||
| 188 | + break; | ||
| 189 | + | ||
| 190 | + case L3MODIFICATION: | ||
| 191 | + encodeL3(result); | ||
| 192 | + break; | ||
| 193 | + | ||
| 194 | + default: | ||
| 195 | + log.info("Cannot convert instruction type of {}", instruction.type()); | ||
| 196 | + break; | ||
| 197 | + } | ||
| 198 | + return result; | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.codec.impl; | ||
| 17 | + | ||
| 18 | +import org.onosproject.codec.CodecContext; | ||
| 19 | +import org.onosproject.codec.JsonCodec; | ||
| 20 | +import org.onosproject.core.CoreService; | ||
| 21 | +import org.onosproject.net.DeviceId; | ||
| 22 | +import org.onosproject.net.flow.DefaultFlowRule; | ||
| 23 | +import org.onosproject.net.flow.FlowRule; | ||
| 24 | +import org.onosproject.net.flow.TrafficSelector; | ||
| 25 | +import org.onosproject.net.flow.TrafficTreatment; | ||
| 26 | + | ||
| 27 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 28 | + | ||
| 29 | +import static org.onlab.util.Tools.nullIsIllegal; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * Flow rule JSON codec. | ||
| 33 | + */ | ||
| 34 | +public final class FlowRuleCodec extends JsonCodec<FlowRule> { | ||
| 35 | + | ||
| 36 | + private static final String APP_ID = "appId"; | ||
| 37 | + private static final String PRIORITY = "priority"; | ||
| 38 | + private static final String TIMEOUT = "timeout"; | ||
| 39 | + private static final String IS_PERMANENT = "isPermanent"; | ||
| 40 | + private static final String DEVICE_ID = "deviceId"; | ||
| 41 | + private static final String TREATMENT = "treatment"; | ||
| 42 | + private static final String SELECTOR = "selector"; | ||
| 43 | + private static final String MISSING_MEMBER_MESSAGE = | ||
| 44 | + " member is required in FlowRule"; | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | + public FlowRule decode(ObjectNode json, CodecContext context) { | ||
| 49 | + if (json == null || !json.isObject()) { | ||
| 50 | + return null; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder(); | ||
| 54 | + | ||
| 55 | + short appId = nullIsIllegal(json.get(APP_ID), | ||
| 56 | + APP_ID + MISSING_MEMBER_MESSAGE).shortValue(); | ||
| 57 | + CoreService coreService = context.getService(CoreService.class); | ||
| 58 | + resultBuilder.fromApp(coreService.getAppId(appId)); | ||
| 59 | + | ||
| 60 | + int priority = nullIsIllegal(json.get(PRIORITY), | ||
| 61 | + PRIORITY + MISSING_MEMBER_MESSAGE).asInt(); | ||
| 62 | + resultBuilder.withPriority(priority); | ||
| 63 | + | ||
| 64 | + boolean isPermanent = nullIsIllegal(json.get(IS_PERMANENT), | ||
| 65 | + IS_PERMANENT + MISSING_MEMBER_MESSAGE).asBoolean(); | ||
| 66 | + if (isPermanent) { | ||
| 67 | + resultBuilder.makePermanent(); | ||
| 68 | + } else { | ||
| 69 | + resultBuilder.makeTemporary(nullIsIllegal(json.get(TIMEOUT), | ||
| 70 | + TIMEOUT | ||
| 71 | + + MISSING_MEMBER_MESSAGE | ||
| 72 | + + " if the flow is temporary").asInt()); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + DeviceId deviceId = DeviceId.deviceId(nullIsIllegal(json.get(DEVICE_ID), | ||
| 76 | + DEVICE_ID + MISSING_MEMBER_MESSAGE).asText()); | ||
| 77 | + resultBuilder.forDevice(deviceId); | ||
| 78 | + | ||
| 79 | + ObjectNode treatmentJson = (ObjectNode) json.get(TREATMENT); | ||
| 80 | + if (treatmentJson != null) { | ||
| 81 | + JsonCodec<TrafficTreatment> treatmentCodec = | ||
| 82 | + context.codec(TrafficTreatment.class); | ||
| 83 | + resultBuilder.withTreatment(treatmentCodec.decode(treatmentJson, context)); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + ObjectNode selectorJson = (ObjectNode) json.get(SELECTOR); | ||
| 87 | + if (selectorJson != null) { | ||
| 88 | + JsonCodec<TrafficSelector> selectorCodec = | ||
| 89 | + context.codec(TrafficSelector.class); | ||
| 90 | + resultBuilder.withSelector(selectorCodec.decode(selectorJson, context)); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + return resultBuilder.build(); | ||
| 94 | + } | ||
| 95 | +} |
| ... | @@ -17,12 +17,7 @@ package org.onosproject.codec.impl; | ... | @@ -17,12 +17,7 @@ package org.onosproject.codec.impl; |
| 17 | 17 | ||
| 18 | import org.onosproject.codec.CodecContext; | 18 | import org.onosproject.codec.CodecContext; |
| 19 | import org.onosproject.codec.JsonCodec; | 19 | import org.onosproject.codec.JsonCodec; |
| 20 | -import org.onosproject.net.OchSignal; | ||
| 21 | import org.onosproject.net.flow.instructions.Instruction; | 20 | import org.onosproject.net.flow.instructions.Instruction; |
| 22 | -import org.onosproject.net.flow.instructions.Instructions; | ||
| 23 | -import org.onosproject.net.flow.instructions.L0ModificationInstruction; | ||
| 24 | -import org.onosproject.net.flow.instructions.L2ModificationInstruction; | ||
| 25 | -import org.onosproject.net.flow.instructions.L3ModificationInstruction; | ||
| 26 | import org.slf4j.Logger; | 21 | import org.slf4j.Logger; |
| 27 | import org.slf4j.LoggerFactory; | 22 | import org.slf4j.LoggerFactory; |
| 28 | 23 | ||
| ... | @@ -37,159 +32,39 @@ public final class InstructionCodec extends JsonCodec<Instruction> { | ... | @@ -37,159 +32,39 @@ public final class InstructionCodec extends JsonCodec<Instruction> { |
| 37 | 32 | ||
| 38 | protected static final Logger log = LoggerFactory.getLogger(InstructionCodec.class); | 33 | protected static final Logger log = LoggerFactory.getLogger(InstructionCodec.class); |
| 39 | 34 | ||
| 40 | - /** | 35 | + protected static final String TYPE = "type"; |
| 41 | - * Encode an L0 modification instruction. | 36 | + protected static final String SUBTYPE = "subtype"; |
| 42 | - * | 37 | + protected static final String PORT = "port"; |
| 43 | - * @param result json node that the instruction attributes are added to | 38 | + protected static final String MAC = "mac"; |
| 44 | - * @param instruction The L0 instruction | 39 | + protected static final String VLAN_ID = "vlanId"; |
| 45 | - */ | 40 | + protected static final String VLAN_PCP = "vlanPcp"; |
| 46 | - private void encodeL0(ObjectNode result, L0ModificationInstruction instruction) { | 41 | + protected static final String MPLS_LABEL = "label"; |
| 47 | - result.put("subtype", instruction.subtype().name()); | 42 | + protected static final String IP = "ip"; |
| 43 | + protected static final String FLOW_LABEL = "flowLabel"; | ||
| 44 | + protected static final String LAMBDA = "lambda"; | ||
| 45 | + protected static final String GRID_TYPE = "gridType"; | ||
| 46 | + protected static final String CHANNEL_SPACING = "channelSpacing"; | ||
| 47 | + protected static final String SPACING_MULTIPLIER = "spacingMultiplier"; | ||
| 48 | + protected static final String SLOT_GRANULARITY = "slotGranularity"; | ||
| 49 | + protected static final String ETHERNET_TYPE = "ethernetType"; | ||
| 50 | + | ||
| 51 | + protected static final String MISSING_MEMBER_MESSAGE = | ||
| 52 | + " member is required in Instruction"; | ||
| 48 | 53 | ||
| 49 | - switch (instruction.subtype()) { | ||
| 50 | - case LAMBDA: | ||
| 51 | - final L0ModificationInstruction.ModLambdaInstruction modLambdaInstruction = | ||
| 52 | - (L0ModificationInstruction.ModLambdaInstruction) instruction; | ||
| 53 | - result.put("lambda", modLambdaInstruction.lambda()); | ||
| 54 | - break; | ||
| 55 | - | ||
| 56 | - case OCH: | ||
| 57 | - L0ModificationInstruction.ModOchSignalInstruction ochSignalInstruction = | ||
| 58 | - (L0ModificationInstruction.ModOchSignalInstruction) instruction; | ||
| 59 | - OchSignal ochSignal = ochSignalInstruction.lambda(); | ||
| 60 | - result.put("gridType", ochSignal.gridType().name()); | ||
| 61 | - result.put("channelSpacing", ochSignal.channelSpacing().name()); | ||
| 62 | - result.put("spacingMultiplier", ochSignal.spacingMultiplier()); | ||
| 63 | - result.put("slotGranularity", ochSignal.slotGranularity()); | ||
| 64 | - break; | ||
| 65 | - | ||
| 66 | - default: | ||
| 67 | - log.info("Cannot convert L0 subtype of {}", instruction.subtype()); | ||
| 68 | - } | ||
| 69 | - } | ||
| 70 | - | ||
| 71 | - /** | ||
| 72 | - * Encode an L2 modification instruction. | ||
| 73 | - * | ||
| 74 | - * @param result json node that the instruction attributes are added to | ||
| 75 | - * @param instruction The L2 instruction | ||
| 76 | - * @param context context of the request | ||
| 77 | - */ | ||
| 78 | - private void encodeL2(ObjectNode result, | ||
| 79 | - L2ModificationInstruction instruction, | ||
| 80 | - CodecContext context) { | ||
| 81 | - result.put("subtype", instruction.subtype().name()); | ||
| 82 | - | ||
| 83 | - switch (instruction.subtype()) { | ||
| 84 | - case ETH_SRC: | ||
| 85 | - case ETH_DST: | ||
| 86 | - final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = | ||
| 87 | - (L2ModificationInstruction.ModEtherInstruction) instruction; | ||
| 88 | - result.put("mac", modEtherInstruction.mac().toString()); | ||
| 89 | - break; | ||
| 90 | - | ||
| 91 | - case VLAN_ID: | ||
| 92 | - final L2ModificationInstruction.ModVlanIdInstruction modVlanIdInstruction = | ||
| 93 | - (L2ModificationInstruction.ModVlanIdInstruction) instruction; | ||
| 94 | - result.put("vlanId", modVlanIdInstruction.vlanId().toShort()); | ||
| 95 | - break; | ||
| 96 | - | ||
| 97 | - case VLAN_PCP: | ||
| 98 | - final L2ModificationInstruction.ModVlanPcpInstruction modVlanPcpInstruction = | ||
| 99 | - (L2ModificationInstruction.ModVlanPcpInstruction) instruction; | ||
| 100 | - result.put("vlanPcp", modVlanPcpInstruction.vlanPcp()); | ||
| 101 | - break; | ||
| 102 | - | ||
| 103 | - case MPLS_LABEL: | ||
| 104 | - final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction = | ||
| 105 | - (L2ModificationInstruction.ModMplsLabelInstruction) instruction; | ||
| 106 | - result.put("label", modMplsLabelInstruction.label()); | ||
| 107 | - break; | ||
| 108 | - | ||
| 109 | - case MPLS_PUSH: | ||
| 110 | - final L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions = | ||
| 111 | - (L2ModificationInstruction.PushHeaderInstructions) instruction; | ||
| 112 | - | ||
| 113 | - result.put("ethernetType", pushHeaderInstructions.ethernetType()); | ||
| 114 | - break; | ||
| 115 | - | ||
| 116 | - default: | ||
| 117 | - log.info("Cannot convert L2 subtype of {}", instruction.subtype()); | ||
| 118 | - break; | ||
| 119 | - } | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - /** | ||
| 123 | - * Encode an L3 modification instruction. | ||
| 124 | - * | ||
| 125 | - * @param result json node that the instruction attributes are added to | ||
| 126 | - * @param instruction The L3 instruction | ||
| 127 | - */ | ||
| 128 | - private void encodeL3(ObjectNode result, L3ModificationInstruction instruction) { | ||
| 129 | - result.put("subtype", instruction.subtype().name()); | ||
| 130 | - switch (instruction.subtype()) { | ||
| 131 | - case IPV4_SRC: | ||
| 132 | - case IPV4_DST: | ||
| 133 | - case IPV6_SRC: | ||
| 134 | - case IPV6_DST: | ||
| 135 | - final L3ModificationInstruction.ModIPInstruction modIPInstruction = | ||
| 136 | - (L3ModificationInstruction.ModIPInstruction) instruction; | ||
| 137 | - result.put("ip", modIPInstruction.ip().toString()); | ||
| 138 | - break; | ||
| 139 | - | ||
| 140 | - case IPV6_FLABEL: | ||
| 141 | - final L3ModificationInstruction.ModIPv6FlowLabelInstruction | ||
| 142 | - modFlowLabelInstruction = | ||
| 143 | - (L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction; | ||
| 144 | - result.put("flowLabel", modFlowLabelInstruction.flowLabel()); | ||
| 145 | - break; | ||
| 146 | - | ||
| 147 | - default: | ||
| 148 | - log.info("Cannot convert L3 subtype of {}", instruction.subtype()); | ||
| 149 | - break; | ||
| 150 | - } | ||
| 151 | - } | ||
| 152 | 54 | ||
| 153 | @Override | 55 | @Override |
| 154 | public ObjectNode encode(Instruction instruction, CodecContext context) { | 56 | public ObjectNode encode(Instruction instruction, CodecContext context) { |
| 155 | checkNotNull(instruction, "Instruction cannot be null"); | 57 | checkNotNull(instruction, "Instruction cannot be null"); |
| 156 | 58 | ||
| 157 | - final ObjectNode result = context.mapper().createObjectNode() | 59 | + return new EncodeInstructionCodec(instruction, context).encode(); |
| 158 | - .put("type", instruction.type().toString()); | 60 | + } |
| 159 | - | ||
| 160 | - | ||
| 161 | - switch (instruction.type()) { | ||
| 162 | - case OUTPUT: | ||
| 163 | - final Instructions.OutputInstruction outputInstruction = | ||
| 164 | - (Instructions.OutputInstruction) instruction; | ||
| 165 | - result.put("port", outputInstruction.port().toLong()); | ||
| 166 | - break; | ||
| 167 | - | ||
| 168 | - case DROP: | ||
| 169 | - break; | ||
| 170 | - | ||
| 171 | - case L0MODIFICATION: | ||
| 172 | - final L0ModificationInstruction l0ModificationInstruction = | ||
| 173 | - (L0ModificationInstruction) instruction; | ||
| 174 | - encodeL0(result, l0ModificationInstruction); | ||
| 175 | - break; | ||
| 176 | - | ||
| 177 | - case L2MODIFICATION: | ||
| 178 | - final L2ModificationInstruction l2ModificationInstruction = | ||
| 179 | - (L2ModificationInstruction) instruction; | ||
| 180 | - encodeL2(result, l2ModificationInstruction, context); | ||
| 181 | - break; | ||
| 182 | - | ||
| 183 | - case L3MODIFICATION: | ||
| 184 | - final L3ModificationInstruction l3ModificationInstruction = | ||
| 185 | - (L3ModificationInstruction) instruction; | ||
| 186 | - encodeL3(result, l3ModificationInstruction); | ||
| 187 | - break; | ||
| 188 | 61 | ||
| 189 | - default: | 62 | + @Override |
| 190 | - log.info("Cannot convert instruction type of {}", instruction.type()); | 63 | + public Instruction decode(ObjectNode json, CodecContext context) { |
| 191 | - break; | 64 | + if (json == null || !json.isObject()) { |
| 65 | + return null; | ||
| 192 | } | 66 | } |
| 193 | - return result; | 67 | + |
| 68 | + return new DecodeInstructionCodec(json).decode(); | ||
| 194 | } | 69 | } |
| 195 | } | 70 | } | ... | ... |
| ... | @@ -15,11 +15,15 @@ | ... | @@ -15,11 +15,15 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.codec.impl; | 16 | package org.onosproject.codec.impl; |
| 17 | 17 | ||
| 18 | +import java.util.stream.IntStream; | ||
| 19 | + | ||
| 18 | import org.onosproject.codec.CodecContext; | 20 | import org.onosproject.codec.CodecContext; |
| 19 | import org.onosproject.codec.JsonCodec; | 21 | import org.onosproject.codec.JsonCodec; |
| 22 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
| 20 | import org.onosproject.net.flow.TrafficSelector; | 23 | import org.onosproject.net.flow.TrafficSelector; |
| 21 | import org.onosproject.net.flow.criteria.Criterion; | 24 | import org.onosproject.net.flow.criteria.Criterion; |
| 22 | 25 | ||
| 26 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 23 | import com.fasterxml.jackson.databind.node.ArrayNode; | 27 | import com.fasterxml.jackson.databind.node.ArrayNode; |
| 24 | import com.fasterxml.jackson.databind.node.ObjectNode; | 28 | import com.fasterxml.jackson.databind.node.ObjectNode; |
| 25 | 29 | ||
| ... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; |
| 29 | * Traffic selector codec. | 33 | * Traffic selector codec. |
| 30 | */ | 34 | */ |
| 31 | public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { | 35 | public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { |
| 36 | + private static final String CRITERIA = "criteria"; | ||
| 37 | + | ||
| 32 | @Override | 38 | @Override |
| 33 | public ObjectNode encode(TrafficSelector selector, CodecContext context) { | 39 | public ObjectNode encode(TrafficSelector selector, CodecContext context) { |
| 34 | checkNotNull(selector, "Traffic selector cannot be null"); | 40 | checkNotNull(selector, "Traffic selector cannot be null"); |
| 35 | 41 | ||
| 36 | final ObjectNode result = context.mapper().createObjectNode(); | 42 | final ObjectNode result = context.mapper().createObjectNode(); |
| 37 | - final ArrayNode jsonCriteria = result.putArray("criteria"); | 43 | + final ArrayNode jsonCriteria = result.putArray(CRITERIA); |
| 38 | 44 | ||
| 39 | if (selector.criteria() != null) { | 45 | if (selector.criteria() != null) { |
| 40 | final JsonCodec<Criterion> criterionCodec = | 46 | final JsonCodec<Criterion> criterionCodec = |
| ... | @@ -46,4 +52,20 @@ public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { | ... | @@ -46,4 +52,20 @@ public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { |
| 46 | 52 | ||
| 47 | return result; | 53 | return result; |
| 48 | } | 54 | } |
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public TrafficSelector decode(ObjectNode json, CodecContext context) { | ||
| 58 | + final JsonCodec<Criterion> criterionCodec = | ||
| 59 | + context.codec(Criterion.class); | ||
| 60 | + | ||
| 61 | + JsonNode criteriaJson = json.get(CRITERIA); | ||
| 62 | + TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); | ||
| 63 | + if (criteriaJson != null) { | ||
| 64 | + IntStream.range(0, criteriaJson.size()) | ||
| 65 | + .forEach(i -> builder.add( | ||
| 66 | + criterionCodec.decode((ObjectNode) criteriaJson.get(i), | ||
| 67 | + context))); | ||
| 68 | + } | ||
| 69 | + return builder.build(); | ||
| 70 | + } | ||
| 49 | } | 71 | } | ... | ... |
| ... | @@ -15,11 +15,15 @@ | ... | @@ -15,11 +15,15 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.codec.impl; | 16 | package org.onosproject.codec.impl; |
| 17 | 17 | ||
| 18 | +import java.util.stream.IntStream; | ||
| 19 | + | ||
| 18 | import org.onosproject.codec.CodecContext; | 20 | import org.onosproject.codec.CodecContext; |
| 19 | import org.onosproject.codec.JsonCodec; | 21 | import org.onosproject.codec.JsonCodec; |
| 22 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
| 20 | import org.onosproject.net.flow.TrafficTreatment; | 23 | import org.onosproject.net.flow.TrafficTreatment; |
| 21 | import org.onosproject.net.flow.instructions.Instruction; | 24 | import org.onosproject.net.flow.instructions.Instruction; |
| 22 | 25 | ||
| 26 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 23 | import com.fasterxml.jackson.databind.node.ArrayNode; | 27 | import com.fasterxml.jackson.databind.node.ArrayNode; |
| 24 | import com.fasterxml.jackson.databind.node.ObjectNode; | 28 | import com.fasterxml.jackson.databind.node.ObjectNode; |
| 25 | 29 | ||
| ... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; |
| 29 | * Traffic treatment codec. | 33 | * Traffic treatment codec. |
| 30 | */ | 34 | */ |
| 31 | public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { | 35 | public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { |
| 36 | + private static final String INSTRUCTIONS = "instructions"; | ||
| 37 | + | ||
| 32 | @Override | 38 | @Override |
| 33 | public ObjectNode encode(TrafficTreatment treatment, CodecContext context) { | 39 | public ObjectNode encode(TrafficTreatment treatment, CodecContext context) { |
| 34 | checkNotNull(treatment, "Traffic treatment cannot be null"); | 40 | checkNotNull(treatment, "Traffic treatment cannot be null"); |
| 35 | 41 | ||
| 36 | final ObjectNode result = context.mapper().createObjectNode(); | 42 | final ObjectNode result = context.mapper().createObjectNode(); |
| 37 | - final ArrayNode jsonInstructions = result.putArray("instructions"); | 43 | + final ArrayNode jsonInstructions = result.putArray(INSTRUCTIONS); |
| 38 | 44 | ||
| 39 | final JsonCodec<Instruction> instructionCodec = | 45 | final JsonCodec<Instruction> instructionCodec = |
| 40 | context.codec(Instruction.class); | 46 | context.codec(Instruction.class); |
| ... | @@ -51,4 +57,20 @@ public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { | ... | @@ -51,4 +57,20 @@ public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { |
| 51 | 57 | ||
| 52 | return result; | 58 | return result; |
| 53 | } | 59 | } |
| 60 | + | ||
| 61 | + @Override | ||
| 62 | + public TrafficTreatment decode(ObjectNode json, CodecContext context) { | ||
| 63 | + final JsonCodec<Instruction> instructionsCodec = | ||
| 64 | + context.codec(Instruction.class); | ||
| 65 | + | ||
| 66 | + JsonNode instructionsJson = json.get(INSTRUCTIONS); | ||
| 67 | + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); | ||
| 68 | + if (instructionsJson != null) { | ||
| 69 | + IntStream.range(0, instructionsJson.size()) | ||
| 70 | + .forEach(i -> builder.add( | ||
| 71 | + instructionsCodec.decode((ObjectNode) instructionsJson.get(i), | ||
| 72 | + context))); | ||
| 73 | + } | ||
| 74 | + return builder.build(); | ||
| 75 | + } | ||
| 54 | } | 76 | } | ... | ... |
| ... | @@ -72,8 +72,10 @@ public class CriterionCodecTest { | ... | @@ -72,8 +72,10 @@ public class CriterionCodecTest { |
| 72 | */ | 72 | */ |
| 73 | @Test | 73 | @Test |
| 74 | public void checkCriterionTypes() throws Exception { | 74 | public void checkCriterionTypes() throws Exception { |
| 75 | + EncodeCriterionCodec encoder = new EncodeCriterionCodec( | ||
| 76 | + Criteria.dummy(), context); | ||
| 75 | EnumMap<Criterion.Type, Object> formatMap = | 77 | EnumMap<Criterion.Type, Object> formatMap = |
| 76 | - getField(criterionCodec, "formatMap"); | 78 | + getField(encoder, "formatMap"); |
| 77 | assertThat(formatMap, notNullValue()); | 79 | assertThat(formatMap, notNullValue()); |
| 78 | 80 | ||
| 79 | for (Criterion.Type type : Criterion.Type.values()) { | 81 | for (Criterion.Type type : Criterion.Type.values()) { | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -38,6 +38,8 @@ public class ImmutableCodecsTest { | ... | @@ -38,6 +38,8 @@ public class ImmutableCodecsTest { |
| 38 | assertThatClassIsImmutable(ConnectPointCodec.class); | 38 | assertThatClassIsImmutable(ConnectPointCodec.class); |
| 39 | assertThatClassIsImmutable(ConstraintCodec.class); | 39 | assertThatClassIsImmutable(ConstraintCodec.class); |
| 40 | assertThatClassIsImmutable(CriterionCodec.class); | 40 | assertThatClassIsImmutable(CriterionCodec.class); |
| 41 | + assertThatClassIsImmutable(EncodeCriterionCodec.class); | ||
| 42 | + assertThatClassIsImmutable(DecodeCriterionCodec.class); | ||
| 41 | assertThatClassIsImmutable(DeviceCodec.class); | 43 | assertThatClassIsImmutable(DeviceCodec.class); |
| 42 | assertThatClassIsImmutable(EthernetCodec.class); | 44 | assertThatClassIsImmutable(EthernetCodec.class); |
| 43 | assertThatClassIsImmutable(FlowEntryCodec.class); | 45 | assertThatClassIsImmutable(FlowEntryCodec.class); |
| ... | @@ -45,6 +47,8 @@ public class ImmutableCodecsTest { | ... | @@ -45,6 +47,8 @@ public class ImmutableCodecsTest { |
| 45 | assertThatClassIsImmutable(HostLocationCodec.class); | 47 | assertThatClassIsImmutable(HostLocationCodec.class); |
| 46 | assertThatClassIsImmutable(HostToHostIntentCodec.class); | 48 | assertThatClassIsImmutable(HostToHostIntentCodec.class); |
| 47 | assertThatClassIsImmutable(InstructionCodec.class); | 49 | assertThatClassIsImmutable(InstructionCodec.class); |
| 50 | + assertThatClassIsImmutable(EncodeInstructionCodec.class); | ||
| 51 | + assertThatClassIsImmutable(DecodeInstructionCodec.class); | ||
| 48 | assertThatClassIsImmutable(IntentCodec.class); | 52 | assertThatClassIsImmutable(IntentCodec.class); |
| 49 | assertThatClassIsImmutable(LinkCodec.class); | 53 | assertThatClassIsImmutable(LinkCodec.class); |
| 50 | assertThatClassIsImmutable(PathCodec.class); | 54 | assertThatClassIsImmutable(PathCodec.class); |
| ... | @@ -54,5 +58,6 @@ public class ImmutableCodecsTest { | ... | @@ -54,5 +58,6 @@ public class ImmutableCodecsTest { |
| 54 | assertThatClassIsImmutable(TopologyCodec.class); | 58 | assertThatClassIsImmutable(TopologyCodec.class); |
| 55 | assertThatClassIsImmutable(TrafficSelectorCodec.class); | 59 | assertThatClassIsImmutable(TrafficSelectorCodec.class); |
| 56 | assertThatClassIsImmutable(TrafficTreatmentCodec.class); | 60 | assertThatClassIsImmutable(TrafficTreatmentCodec.class); |
| 61 | + assertThatClassIsImmutable(FlowRuleCodec.class); | ||
| 57 | } | 62 | } |
| 58 | } | 63 | } | ... | ... |
| 1 | +{ | ||
| 2 | + "appId":-29467, | ||
| 3 | + "priority":1, | ||
| 4 | + "isPermanent":"false", | ||
| 5 | + "timeout":1, | ||
| 6 | + "deviceId":"of:0000000000000001", | ||
| 7 | + "selector": | ||
| 8 | + {"criteria": | ||
| 9 | + [ | ||
| 10 | + {"type":"IN_PORT", "port":23}, | ||
| 11 | + {"type":"IN_PHY_PORT", "port":44}, | ||
| 12 | + {"type":"METADATA", "metadata":123456}, | ||
| 13 | + {"type":"ETH_TYPE","ethType":2054}, | ||
| 14 | + {"type":"ETH_SRC","mac":"00:11:22:33:44:55"}, | ||
| 15 | + {"type":"ETH_DST","mac":"00:11:22:33:44:55"}, | ||
| 16 | + {"type":"VLAN_VID","vlanId":777}, | ||
| 17 | + {"type":"VLAN_PCP","priority":3}, | ||
| 18 | + {"type":"IP_DSCP","ipDscp":2}, | ||
| 19 | + {"type":"IP_ECN","ipEcn":1}, | ||
| 20 | + {"type":"IP_PROTO","protocol":4}, | ||
| 21 | + {"type":"IPV4_SRC", "ip":"1.2.0.0/32"}, | ||
| 22 | + {"type":"IPV4_DST", "ip":"2.2.0.0/32"}, | ||
| 23 | + {"type":"IPV6_SRC", "ip":"3.2.0.0/32"}, | ||
| 24 | + {"type":"IPV6_DST", "ip":"4.2.0.0/32"}, | ||
| 25 | + {"type":"TCP_SRC", "tcpPort":80}, | ||
| 26 | + {"type":"TCP_DST", "tcpPort":443}, | ||
| 27 | + {"type":"UDP_SRC", "udpPort":180}, | ||
| 28 | + {"type":"UDP_DST", "udpPort":1443}, | ||
| 29 | + {"type":"SCTP_SRC", "sctpPort":280}, | ||
| 30 | + {"type":"SCTP_DST", "sctpPort":2443}, | ||
| 31 | + {"type":"ICMPV4_TYPE", "icmpType":24}, | ||
| 32 | + {"type":"ICMPV4_CODE", "icmpCode":16}, | ||
| 33 | + {"type":"ICMPV6_TYPE", "icmpv6Type":14}, | ||
| 34 | + {"type":"ICMPV6_CODE", "icmpv6Code":6}, | ||
| 35 | + {"type":"IPV6_FLABEL", "flowLabel":8}, | ||
| 36 | + {"type":"IPV6_ND_TARGET", "targetAddress":"1111:2222:3333:4444:5555:6666:7777:8888"}, | ||
| 37 | + {"type":"IPV6_ND_SLL", "mac":"00:11:22:33:44:56"}, | ||
| 38 | + {"type":"IPV6_ND_TLL", "mac":"00:11:22:33:44:57"}, | ||
| 39 | + {"type":"MPLS_LABEL", "label":123}, | ||
| 40 | + {"type":"IPV6_EXTHDR", "exthdrFlags":99}, | ||
| 41 | + {"type":"OCH_SIGID", "lambda":122} | ||
| 42 | + ] | ||
| 43 | + } | ||
| 44 | +} |
| 1 | +{ | ||
| 2 | + "appId":-29467, | ||
| 3 | + "priority":1, | ||
| 4 | + "isPermanent":"false", | ||
| 5 | + "timeout":1, | ||
| 6 | + "deviceId":"of:0000000000000001", | ||
| 7 | + "treatment": | ||
| 8 | + { | ||
| 9 | + "instructions": | ||
| 10 | + [ | ||
| 11 | + {"type":"OUTPUT","port":-3}, | ||
| 12 | + {"type":"DROP"}, | ||
| 13 | + {"type":"L2MODIFICATION","subtype":"ETH_SRC","mac":"12:34:56:78:90:12"}, | ||
| 14 | + {"type":"L2MODIFICATION","subtype":"ETH_DST","mac":"98:76:54:32:01:00"}, | ||
| 15 | + {"type":"L2MODIFICATION","subtype":"VLAN_ID","vlanId":22}, | ||
| 16 | + {"type":"L2MODIFICATION","subtype":"VLAN_PCP","vlanPcp":1}, | ||
| 17 | + {"type":"L2MODIFICATION","subtype":"MPLS_LABEL","label":777}, | ||
| 18 | + {"type":"L2MODIFICATION","subtype":"MPLS_PUSH"}, | ||
| 19 | + {"type":"L2MODIFICATION","subtype":"MPLS_POP"}, | ||
| 20 | + {"type":"L2MODIFICATION","subtype":"DEC_MPLS_TTL"}, | ||
| 21 | + {"type":"L2MODIFICATION","subtype":"VLAN_POP"}, | ||
| 22 | + {"type":"L2MODIFICATION","subtype":"VLAN_PUSH"}, | ||
| 23 | + {"type":"L3MODIFICATION","subtype":"IPV4_SRC", "ip":"1.2.3.4"}, | ||
| 24 | + {"type":"L3MODIFICATION","subtype":"IPV4_DST", "ip":"1.2.3.3"}, | ||
| 25 | + {"type":"L3MODIFICATION","subtype":"IPV6_SRC", "ip":"1.2.3.2"}, | ||
| 26 | + {"type":"L3MODIFICATION","subtype":"IPV6_DST", "ip":"1.2.3.1"}, | ||
| 27 | + {"type":"L3MODIFICATION","subtype":"IPV6_FLABEL", "flowLabel":8}, | ||
| 28 | + {"type":"L0MODIFICATION","subtype":"LAMBDA","lambda":7}, | ||
| 29 | + {"type":"L0MODIFICATION","subtype":"OCH","gridType":"DWDM", | ||
| 30 | + "channelSpacing":"CHL_100GHZ","spacingMultiplier":4,"slotGranularity":8} | ||
| 31 | + ], | ||
| 32 | + "deferred":[] | ||
| 33 | + }, | ||
| 34 | + "selector": {"criteria":[{"type":"ETH_TYPE","ethType":2054}]} | ||
| 35 | +} |
| 1 | +{ | ||
| 2 | + "appId":-29467, | ||
| 3 | + "priority":1, | ||
| 4 | + "isPermanent":"false", | ||
| 5 | + "timeout":1, | ||
| 6 | + "deviceId":"of:0000000000000001", | ||
| 7 | + "selector": | ||
| 8 | + {"criteria": | ||
| 9 | + [ | ||
| 10 | + {"type":"OCH_SIGID", | ||
| 11 | + "ochSignalId": | ||
| 12 | + { | ||
| 13 | + "gridType":"CWDM", | ||
| 14 | + "channelSpacing":"CHL_25GHZ", | ||
| 15 | + "spacingMultiplier":3, | ||
| 16 | + "slotGranularity":4 | ||
| 17 | + } | ||
| 18 | + } | ||
| 19 | + ] | ||
| 20 | + } | ||
| 21 | +} |
| ... | @@ -123,7 +123,7 @@ public abstract class Tools { | ... | @@ -123,7 +123,7 @@ public abstract class Tools { |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | /** | 125 | /** |
| 126 | - * Returns the specified item if that items is null; otherwise throws | 126 | + * Returns the specified item if that item is not null; otherwise throws |
| 127 | * not found exception. | 127 | * not found exception. |
| 128 | * | 128 | * |
| 129 | * @param item item to check | 129 | * @param item item to check |
| ... | @@ -140,6 +140,23 @@ public abstract class Tools { | ... | @@ -140,6 +140,23 @@ public abstract class Tools { |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | /** | 142 | /** |
| 143 | + * Returns the specified item if that item is not null; otherwise throws | ||
| 144 | + * bad argument exception. | ||
| 145 | + * | ||
| 146 | + * @param item item to check | ||
| 147 | + * @param message not found message | ||
| 148 | + * @param <T> item type | ||
| 149 | + * @return item if not null | ||
| 150 | + * @throws IllegalArgumentException if item is null | ||
| 151 | + */ | ||
| 152 | + public static <T> T nullIsIllegal(T item, String message) { | ||
| 153 | + if (item == null) { | ||
| 154 | + throw new IllegalArgumentException(message); | ||
| 155 | + } | ||
| 156 | + return item; | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + /** | ||
| 143 | * Converts a string from hex to long. | 160 | * Converts a string from hex to long. |
| 144 | * | 161 | * |
| 145 | * @param string hex number in string form; sans 0x | 162 | * @param string hex number in string form; sans 0x | ... | ... |
web/api/src/main/java/org/onosproject/rest/exceptions/IllegalArgumentExceptionMapper.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2014-2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.rest.exceptions; | ||
| 17 | + | ||
| 18 | +import javax.ws.rs.core.Response; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Mapper for illegal argument exceptions to the BAD_REQUEST response code. | ||
| 22 | + */ | ||
| 23 | +public class IllegalArgumentExceptionMapper extends AbstractMapper<IllegalArgumentException> { | ||
| 24 | + @Override | ||
| 25 | + protected Response.Status responseStatus() { | ||
| 26 | + return Response.Status.BAD_REQUEST; | ||
| 27 | + } | ||
| 28 | +} | ||
| 29 | + |
| ... | @@ -15,22 +15,29 @@ | ... | @@ -15,22 +15,29 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.rest.resources; | 16 | package org.onosproject.rest.resources; |
| 17 | 17 | ||
| 18 | -import com.fasterxml.jackson.databind.node.ArrayNode; | 18 | +import java.io.IOException; |
| 19 | -import com.fasterxml.jackson.databind.node.ObjectNode; | 19 | +import java.io.InputStream; |
| 20 | + | ||
| 21 | +import javax.ws.rs.Consumes; | ||
| 22 | +import javax.ws.rs.GET; | ||
| 23 | +import javax.ws.rs.POST; | ||
| 24 | +import javax.ws.rs.Path; | ||
| 25 | +import javax.ws.rs.PathParam; | ||
| 26 | +import javax.ws.rs.Produces; | ||
| 27 | +import javax.ws.rs.core.MediaType; | ||
| 28 | +import javax.ws.rs.core.Response; | ||
| 29 | + | ||
| 20 | import org.onlab.util.ItemNotFoundException; | 30 | import org.onlab.util.ItemNotFoundException; |
| 21 | import org.onosproject.net.Device; | 31 | import org.onosproject.net.Device; |
| 22 | import org.onosproject.net.DeviceId; | 32 | import org.onosproject.net.DeviceId; |
| 23 | import org.onosproject.net.device.DeviceService; | 33 | import org.onosproject.net.device.DeviceService; |
| 24 | import org.onosproject.net.flow.FlowEntry; | 34 | import org.onosproject.net.flow.FlowEntry; |
| 35 | +import org.onosproject.net.flow.FlowRule; | ||
| 25 | import org.onosproject.net.flow.FlowRuleService; | 36 | import org.onosproject.net.flow.FlowRuleService; |
| 26 | import org.onosproject.rest.AbstractWebResource; | 37 | import org.onosproject.rest.AbstractWebResource; |
| 27 | 38 | ||
| 28 | -import javax.ws.rs.GET; | 39 | +import com.fasterxml.jackson.databind.node.ArrayNode; |
| 29 | -import javax.ws.rs.Path; | 40 | +import com.fasterxml.jackson.databind.node.ObjectNode; |
| 30 | -import javax.ws.rs.PathParam; | ||
| 31 | -import javax.ws.rs.Produces; | ||
| 32 | -import javax.ws.rs.core.MediaType; | ||
| 33 | -import javax.ws.rs.core.Response; | ||
| 34 | 41 | ||
| 35 | /** | 42 | /** |
| 36 | * REST resource for interacting with the inventory of flows. | 43 | * REST resource for interacting with the inventory of flows. |
| ... | @@ -113,4 +120,27 @@ public class FlowsWebResource extends AbstractWebResource { | ... | @@ -113,4 +120,27 @@ public class FlowsWebResource extends AbstractWebResource { |
| 113 | } | 120 | } |
| 114 | return ok(root).build(); | 121 | return ok(root).build(); |
| 115 | } | 122 | } |
| 123 | + | ||
| 124 | + /** | ||
| 125 | + * Creates a flow rule from a POST of a JSON string and attempts to apply it. | ||
| 126 | + * | ||
| 127 | + * @param stream input JSON | ||
| 128 | + * @return status of the request - ACCEPTED if the JSON is correct, | ||
| 129 | + * BAD_REQUEST if the JSON is invalid | ||
| 130 | + */ | ||
| 131 | + @POST | ||
| 132 | + @Consumes(MediaType.APPLICATION_JSON) | ||
| 133 | + @Produces(MediaType.APPLICATION_JSON) | ||
| 134 | + public Response createFlow(InputStream stream) { | ||
| 135 | + try { | ||
| 136 | + FlowRuleService service = get(FlowRuleService.class); | ||
| 137 | + ObjectNode root = (ObjectNode) mapper().readTree(stream); | ||
| 138 | + FlowRule rule = codec(FlowRule.class).decode(root, this); | ||
| 139 | + service.applyFlowRules(rule); | ||
| 140 | + } catch (IOException ex) { | ||
| 141 | + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); | ||
| 142 | + } | ||
| 143 | + return Response.status(Response.Status.ACCEPTED).build(); | ||
| 144 | + } | ||
| 145 | + | ||
| 116 | } | 146 | } | ... | ... |
| ... | @@ -61,6 +61,7 @@ | ... | @@ -61,6 +61,7 @@ |
| 61 | org.onosproject.rest.exceptions.ServerErrorMapper, | 61 | org.onosproject.rest.exceptions.ServerErrorMapper, |
| 62 | org.onosproject.rest.exceptions.BadRequestMapper, | 62 | org.onosproject.rest.exceptions.BadRequestMapper, |
| 63 | org.onosproject.rest.exceptions.WebApplicationExceptionMapper, | 63 | org.onosproject.rest.exceptions.WebApplicationExceptionMapper, |
| 64 | + org.onosproject.rest.exceptions.IllegalArgumentExceptionMapper, | ||
| 64 | org.onosproject.rest.resources.JsonBodyWriter, | 65 | org.onosproject.rest.resources.JsonBodyWriter, |
| 65 | 66 | ||
| 66 | org.onosproject.rest.resources.ApplicationsWebResource, | 67 | org.onosproject.rest.resources.ApplicationsWebResource, | ... | ... |
| ... | @@ -15,10 +15,13 @@ | ... | @@ -15,10 +15,13 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.rest; | 16 | package org.onosproject.rest; |
| 17 | 17 | ||
| 18 | +import java.net.HttpURLConnection; | ||
| 18 | import java.util.HashMap; | 19 | import java.util.HashMap; |
| 19 | import java.util.HashSet; | 20 | import java.util.HashSet; |
| 20 | import java.util.Set; | 21 | import java.util.Set; |
| 21 | 22 | ||
| 23 | +import javax.ws.rs.core.MediaType; | ||
| 24 | + | ||
| 22 | import org.hamcrest.Description; | 25 | import org.hamcrest.Description; |
| 23 | import org.hamcrest.TypeSafeMatcher; | 26 | import org.hamcrest.TypeSafeMatcher; |
| 24 | import org.junit.After; | 27 | import org.junit.After; |
| ... | @@ -30,11 +33,13 @@ import org.onlab.packet.MacAddress; | ... | @@ -30,11 +33,13 @@ import org.onlab.packet.MacAddress; |
| 30 | import org.onlab.rest.BaseResource; | 33 | import org.onlab.rest.BaseResource; |
| 31 | import org.onosproject.codec.CodecService; | 34 | import org.onosproject.codec.CodecService; |
| 32 | import org.onosproject.codec.impl.CodecManager; | 35 | import org.onosproject.codec.impl.CodecManager; |
| 36 | +import org.onosproject.core.CoreService; | ||
| 33 | import org.onosproject.core.DefaultGroupId; | 37 | import org.onosproject.core.DefaultGroupId; |
| 34 | import org.onosproject.core.GroupId; | 38 | import org.onosproject.core.GroupId; |
| 35 | import org.onosproject.net.DefaultDevice; | 39 | import org.onosproject.net.DefaultDevice; |
| 36 | import org.onosproject.net.Device; | 40 | import org.onosproject.net.Device; |
| 37 | import org.onosproject.net.DeviceId; | 41 | import org.onosproject.net.DeviceId; |
| 42 | +import org.onosproject.net.NetTestTools; | ||
| 38 | import org.onosproject.net.device.DeviceService; | 43 | import org.onosproject.net.device.DeviceService; |
| 39 | import org.onosproject.net.flow.DefaultTrafficSelector; | 44 | import org.onosproject.net.flow.DefaultTrafficSelector; |
| 40 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 45 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
| ... | @@ -51,12 +56,15 @@ import org.onosproject.net.flow.instructions.Instructions; | ... | @@ -51,12 +56,15 @@ import org.onosproject.net.flow.instructions.Instructions; |
| 51 | import com.eclipsesource.json.JsonArray; | 56 | import com.eclipsesource.json.JsonArray; |
| 52 | import com.eclipsesource.json.JsonObject; | 57 | import com.eclipsesource.json.JsonObject; |
| 53 | import com.google.common.collect.ImmutableSet; | 58 | import com.google.common.collect.ImmutableSet; |
| 59 | +import com.sun.jersey.api.client.ClientResponse; | ||
| 54 | import com.sun.jersey.api.client.UniformInterfaceException; | 60 | import com.sun.jersey.api.client.UniformInterfaceException; |
| 55 | import com.sun.jersey.api.client.WebResource; | 61 | import com.sun.jersey.api.client.WebResource; |
| 56 | 62 | ||
| 57 | import static org.easymock.EasyMock.anyObject; | 63 | import static org.easymock.EasyMock.anyObject; |
| 64 | +import static org.easymock.EasyMock.anyShort; | ||
| 58 | import static org.easymock.EasyMock.createMock; | 65 | import static org.easymock.EasyMock.createMock; |
| 59 | import static org.easymock.EasyMock.expect; | 66 | import static org.easymock.EasyMock.expect; |
| 67 | +import static org.easymock.EasyMock.expectLastCall; | ||
| 60 | import static org.easymock.EasyMock.replay; | 68 | import static org.easymock.EasyMock.replay; |
| 61 | import static org.easymock.EasyMock.verify; | 69 | import static org.easymock.EasyMock.verify; |
| 62 | import static org.hamcrest.Matchers.containsString; | 70 | import static org.hamcrest.Matchers.containsString; |
| ... | @@ -72,6 +80,8 @@ import static org.junit.Assert.fail; | ... | @@ -72,6 +80,8 @@ import static org.junit.Assert.fail; |
| 72 | */ | 80 | */ |
| 73 | public class FlowsResourceTest extends ResourceTest { | 81 | public class FlowsResourceTest extends ResourceTest { |
| 74 | final FlowRuleService mockFlowService = createMock(FlowRuleService.class); | 82 | final FlowRuleService mockFlowService = createMock(FlowRuleService.class); |
| 83 | + CoreService mockCoreService = createMock(CoreService.class); | ||
| 84 | + | ||
| 75 | final HashMap<DeviceId, Set<FlowEntry>> rules = new HashMap<>(); | 85 | final HashMap<DeviceId, Set<FlowEntry>> rules = new HashMap<>(); |
| 76 | 86 | ||
| 77 | final DeviceService mockDeviceService = createMock(DeviceService.class); | 87 | final DeviceService mockDeviceService = createMock(DeviceService.class); |
| ... | @@ -245,6 +255,11 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -245,6 +255,11 @@ public class FlowsResourceTest extends ResourceTest { |
| 245 | expect(mockDeviceService.getDevices()) | 255 | expect(mockDeviceService.getDevices()) |
| 246 | .andReturn(ImmutableSet.of(device1, device2)); | 256 | .andReturn(ImmutableSet.of(device1, device2)); |
| 247 | 257 | ||
| 258 | + // Mock Core Service | ||
| 259 | + expect(mockCoreService.getAppId(anyShort())) | ||
| 260 | + .andReturn(NetTestTools.APP_ID).anyTimes(); | ||
| 261 | + replay(mockCoreService); | ||
| 262 | + | ||
| 248 | // Register the services needed for the test | 263 | // Register the services needed for the test |
| 249 | final CodecManager codecService = new CodecManager(); | 264 | final CodecManager codecService = new CodecManager(); |
| 250 | codecService.activate(); | 265 | codecService.activate(); |
| ... | @@ -252,7 +267,8 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -252,7 +267,8 @@ public class FlowsResourceTest extends ResourceTest { |
| 252 | new TestServiceDirectory() | 267 | new TestServiceDirectory() |
| 253 | .add(FlowRuleService.class, mockFlowService) | 268 | .add(FlowRuleService.class, mockFlowService) |
| 254 | .add(DeviceService.class, mockDeviceService) | 269 | .add(DeviceService.class, mockDeviceService) |
| 255 | - .add(CodecService.class, codecService); | 270 | + .add(CodecService.class, codecService) |
| 271 | + .add(CoreService.class, mockCoreService); | ||
| 256 | 272 | ||
| 257 | BaseResource.setServiceDirectory(testDirectory); | 273 | BaseResource.setServiceDirectory(testDirectory); |
| 258 | } | 274 | } |
| ... | @@ -263,6 +279,7 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -263,6 +279,7 @@ public class FlowsResourceTest extends ResourceTest { |
| 263 | @After | 279 | @After |
| 264 | public void tearDownTest() { | 280 | public void tearDownTest() { |
| 265 | verify(mockFlowService); | 281 | verify(mockFlowService); |
| 282 | + verify(mockCoreService); | ||
| 266 | } | 283 | } |
| 267 | 284 | ||
| 268 | /** | 285 | /** |
| ... | @@ -542,4 +559,27 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -542,4 +559,27 @@ public class FlowsResourceTest extends ResourceTest { |
| 542 | containsString("returned a response status of")); | 559 | containsString("returned a response status of")); |
| 543 | } | 560 | } |
| 544 | } | 561 | } |
| 562 | + | ||
| 563 | + /** | ||
| 564 | + * Tests creating a flow with POST. | ||
| 565 | + */ | ||
| 566 | + @Test | ||
| 567 | + public void testPost() { | ||
| 568 | + String json = "{\"appId\":2,\"priority\":1,\"isPermanent\":true," | ||
| 569 | + + "\"deviceId\":\"of:0000000000000001\"," | ||
| 570 | + + "\"treatment\":{\"instructions\":[ {\"type\":\"OUTPUT\",\"port\":2}]}," | ||
| 571 | + + "\"selector\":{\"criteria\":[ {\"type\":\"ETH_TYPE\",\"ethType\":2054}]}}"; | ||
| 572 | + | ||
| 573 | + mockFlowService.applyFlowRules(anyObject()); | ||
| 574 | + expectLastCall(); | ||
| 575 | + replay(mockFlowService); | ||
| 576 | + | ||
| 577 | + WebResource rs = resource(); | ||
| 578 | + | ||
| 579 | + | ||
| 580 | + ClientResponse response = rs.path("flows/") | ||
| 581 | + .type(MediaType.APPLICATION_JSON_TYPE) | ||
| 582 | + .post(ClientResponse.class, json); | ||
| 583 | + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_ACCEPTED)); | ||
| 584 | + } | ||
| 545 | } | 585 | } | ... | ... |
-
Please register or login to post a comment