blob: ff55e49cf1e79228c063c7c376fe14e686294a34 [file] [log] [blame]
Ray Milkeyd43fe452015-05-29 09:35:12 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Ray Milkeyd43fe452015-05-29 09:35:12 -07003 *
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 */
16package org.onosproject.codec.impl;
17
Jian Lidab72562016-04-12 14:10:32 -070018import com.fasterxml.jackson.databind.JsonNode;
Jian Li1ef82db2016-03-03 14:43:21 -080019import com.fasterxml.jackson.databind.node.ObjectNode;
Cem Türker3baff672017-10-12 15:09:01 +030020import com.google.common.collect.Maps;
Jian Lidab72562016-04-12 14:10:32 -070021import org.onlab.osgi.DefaultServiceDirectory;
22import org.onlab.osgi.ServiceDirectory;
Konstantinos Kanonakis9215ff22016-11-04 13:28:11 -050023import org.onlab.packet.EthType;
Ray Milkeyd43fe452015-05-29 09:35:12 -070024import org.onlab.packet.IpAddress;
25import org.onlab.packet.MacAddress;
26import org.onlab.packet.MplsLabel;
Hyunsun Moonfab29502015-08-25 13:39:16 -070027import org.onlab.packet.TpPort;
Ray Milkeyd43fe452015-05-29 09:35:12 -070028import org.onlab.packet.VlanId;
Yafit Hadar5796d972015-10-15 13:16:11 +030029import org.onlab.util.HexString;
Jonathan Harte3bcfc32016-08-16 17:12:49 -070030import org.onosproject.codec.CodecContext;
Andrea Campanella2cfe8ef2017-07-13 19:45:15 +020031import org.onosproject.net.flow.ExtensionTreatmentCodec;
Jian Lice8c5602016-03-03 21:43:24 -080032import org.onosproject.core.GroupId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070033import org.onosproject.net.ChannelSpacing;
Jian Lidab72562016-04-12 14:10:32 -070034import org.onosproject.net.Device;
35import org.onosproject.net.DeviceId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070036import org.onosproject.net.GridType;
Ray Milkeyd43fe452015-05-29 09:35:12 -070037import org.onosproject.net.OchSignal;
Yafit Hadar5796d972015-10-15 13:16:11 +030038import org.onosproject.net.OduSignalId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070039import org.onosproject.net.PortNumber;
Jian Lidab72562016-04-12 14:10:32 -070040import org.onosproject.net.device.DeviceService;
Cem Türker3baff672017-10-12 15:09:01 +030041import org.onosproject.net.flow.StatTriggerField;
42import org.onosproject.net.flow.StatTriggerFlag;
Jian Lidab72562016-04-12 14:10:32 -070043import org.onosproject.net.flow.instructions.ExtensionTreatment;
Ray Milkeyd43fe452015-05-29 09:35:12 -070044import org.onosproject.net.flow.instructions.Instruction;
45import org.onosproject.net.flow.instructions.Instructions;
46import org.onosproject.net.flow.instructions.L0ModificationInstruction;
Yafit Hadar5796d972015-10-15 13:16:11 +030047import org.onosproject.net.flow.instructions.L1ModificationInstruction;
Ray Milkeyd43fe452015-05-29 09:35:12 -070048import org.onosproject.net.flow.instructions.L2ModificationInstruction;
49import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Hyunsun Moonfab29502015-08-25 13:39:16 -070050import org.onosproject.net.flow.instructions.L4ModificationInstruction;
Jian Li47b26232016-03-07 09:59:59 -080051import org.onosproject.net.meter.MeterId;
Jian Lidab72562016-04-12 14:10:32 -070052import org.slf4j.Logger;
Ray Milkeyd43fe452015-05-29 09:35:12 -070053
Cem Türker3baff672017-10-12 15:09:01 +030054import java.util.Map;
Konstantinos Kanonakis9215ff22016-11-04 13:28:11 -050055import java.util.regex.Matcher;
56import java.util.regex.Pattern;
57
Jian Li1ef82db2016-03-03 14:43:21 -080058import static org.onlab.util.Tools.nullIsIllegal;
Cem Türker3baff672017-10-12 15:09:01 +030059import static org.onosproject.codec.impl.InstructionCodec.STAT_PACKET_COUNT;
Jian Lidab72562016-04-12 14:10:32 -070060import static org.slf4j.LoggerFactory.getLogger;
Ray Milkeyd43fe452015-05-29 09:35:12 -070061
62/**
63 * Decoding portion of the instruction codec.
64 */
Ray Milkey6d7968e2015-07-06 14:30:02 -070065public final class DecodeInstructionCodecHelper {
Jian Lidab72562016-04-12 14:10:32 -070066 protected static final Logger log = getLogger(DecodeInstructionCodecHelper.class);
Ray Milkeyd43fe452015-05-29 09:35:12 -070067 private final ObjectNode json;
Jonathan Harte3bcfc32016-08-16 17:12:49 -070068 private final CodecContext context;
Konstantinos Kanonakis9215ff22016-11-04 13:28:11 -050069 private static final Pattern ETHTYPE_PATTERN = Pattern.compile("0x([0-9a-fA-F]{4})");
Ray Milkeyd43fe452015-05-29 09:35:12 -070070
71 /**
72 * Creates a decode instruction codec object.
73 *
74 * @param json JSON object to decode
Ray Milkeyef794342016-11-09 16:20:29 -080075 * @param context codec context
Ray Milkeyd43fe452015-05-29 09:35:12 -070076 */
Jonathan Harte3bcfc32016-08-16 17:12:49 -070077 public DecodeInstructionCodecHelper(ObjectNode json, CodecContext context) {
Ray Milkeyd43fe452015-05-29 09:35:12 -070078 this.json = json;
Jonathan Harte3bcfc32016-08-16 17:12:49 -070079 this.context = context;
Ray Milkeyd43fe452015-05-29 09:35:12 -070080 }
81
82 /**
83 * Decodes a Layer 2 instruction.
84 *
85 * @return instruction object decoded from the JSON
86 * @throws IllegalArgumentException if the JSON is invalid
87 */
88 private Instruction decodeL2() {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +053089 String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE),
90 InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText();
Ray Milkeyd43fe452015-05-29 09:35:12 -070091
92 if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) {
93 String mac = nullIsIllegal(json.get(InstructionCodec.MAC),
94 InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
95 return Instructions.modL2Src(MacAddress.valueOf(mac));
96 } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) {
97 String mac = nullIsIllegal(json.get(InstructionCodec.MAC),
98 InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
99 return Instructions.modL2Dst(MacAddress.valueOf(mac));
100 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) {
101 short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID),
102 InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
103 return Instructions.modVlanId(VlanId.vlanId(vlanId));
104 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) {
105 byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP),
106 InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
107 return Instructions.modVlanPcp(vlanPcp);
108 } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) {
109 int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL),
110 InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
111 return Instructions.modMplsLabel(MplsLabel.mplsLabel(label));
112 } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) {
113 return Instructions.pushMpls();
114 } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) {
Sivachidambaram Subramaniandab7f4b2017-05-15 12:28:12 +0530115 if (json.has(InstructionCodec.ETHERNET_TYPE)) {
116 return Instructions.popMpls(getEthType());
117 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700118 return Instructions.popMpls();
119 } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) {
120 return Instructions.decMplsTtl();
121 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) {
122 return Instructions.popVlan();
123 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) {
Konstantinos Kanonakis9215ff22016-11-04 13:28:11 -0500124 if (json.has(InstructionCodec.ETHERNET_TYPE)) {
125 return Instructions.pushVlan(getEthType());
126 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700127 return Instructions.pushVlan();
Hyunsun Moon7080a0d2015-08-14 19:18:48 -0700128 } else if (subType.equals(L2ModificationInstruction.L2SubType.TUNNEL_ID.name())) {
129 long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID),
130 InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong();
131 return Instructions.modTunnelId(tunnelId);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700132 }
133 throw new IllegalArgumentException("L2 Instruction subtype "
134 + subType + " is not supported");
135 }
136
137 /**
138 * Decodes a Layer 3 instruction.
139 *
140 * @return instruction object decoded from the JSON
141 * @throws IllegalArgumentException if the JSON is invalid
142 */
143 private Instruction decodeL3() {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530144 String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE),
145 InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700146
147 if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) {
148 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
149 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
150 return Instructions.modL3Src(ip);
151 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) {
152 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
153 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
154 return Instructions.modL3Dst(ip);
155 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) {
156 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
157 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
158 return Instructions.modL3IPv6Src(ip);
159 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) {
160 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
161 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
162 return Instructions.modL3IPv6Dst(ip);
163 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) {
164 int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL),
165 InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
166 return Instructions.modL3IPv6FlowLabel(flowLabel);
Jonathan Hartcc962d82016-08-09 16:52:22 -0700167 } else if (subType.equals(L3ModificationInstruction.L3SubType.TTL_IN.name())) {
168 return Instructions.copyTtlIn();
169 } else if (subType.equals(L3ModificationInstruction.L3SubType.TTL_OUT.name())) {
170 return Instructions.copyTtlOut();
171 } else if (subType.equals(L3ModificationInstruction.L3SubType.DEC_TTL.name())) {
172 return Instructions.decNwTtl();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700173 }
174 throw new IllegalArgumentException("L3 Instruction subtype "
175 + subType + " is not supported");
176 }
177
178 /**
179 * Decodes a Layer 0 instruction.
180 *
181 * @return instruction object decoded from the JSON
182 * @throws IllegalArgumentException if the JSON is invalid
183 */
184 private Instruction decodeL0() {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530185 String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE),
186 InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700187
Sho SHIMIZUcc137a92016-03-11 15:10:54 -0800188 if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) {
Ray Milkeyd43fe452015-05-29 09:35:12 -0700189 String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE),
190 InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
191 GridType gridType = GridType.valueOf(gridTypeString);
192 if (gridType == null) {
193 throw new IllegalArgumentException("Unknown grid type "
194 + gridTypeString);
195 }
196 String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING),
197 InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
198 ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString);
199 if (channelSpacing == null) {
200 throw new IllegalArgumentException("Unknown channel spacing "
201 + channelSpacingString);
202 }
203 int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER),
204 InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
205 int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY),
206 InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
207 return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing,
208 spacingMultiplier, slotGranularity));
209 }
210 throw new IllegalArgumentException("L0 Instruction subtype "
211 + subType + " is not supported");
212 }
213
214 /**
Yafit Hadar5796d972015-10-15 13:16:11 +0300215 * Decodes a Layer 1 instruction.
216 *
217 * @return instruction object decoded from the JSON
218 * @throws IllegalArgumentException if the JSON is invalid
219 */
220 private Instruction decodeL1() {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530221 String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE),
222 InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText();
Yafit Hadar5796d972015-10-15 13:16:11 +0300223 if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) {
224 int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER),
225 InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
226 int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN),
227 InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
228 byte[] tributarySlotBitmap = null;
229 tributarySlotBitmap = HexString.fromHexString(
230 nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP),
231 InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
232 return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen,
233 tributarySlotBitmap));
234 }
235 throw new IllegalArgumentException("L1 Instruction subtype "
236 + subType + " is not supported");
237 }
238
239 /**
Hyunsun Moonfab29502015-08-25 13:39:16 -0700240 * Decodes a Layer 4 instruction.
241 *
242 * @return instruction object decoded from the JSON
243 * @throws IllegalArgumentException if the JSON is invalid
244 */
245 private Instruction decodeL4() {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530246 String subType = nullIsIllegal(json.get(InstructionCodec.SUBTYPE),
247 InstructionCodec.SUBTYPE + InstructionCodec.ERROR_MESSAGE).asText();
Hyunsun Moonfab29502015-08-25 13:39:16 -0700248
249 if (subType.equals(L4ModificationInstruction.L4SubType.TCP_DST.name())) {
250 TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT),
251 InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
252 return Instructions.modTcpDst(tcpPort);
253 } else if (subType.equals(L4ModificationInstruction.L4SubType.TCP_SRC.name())) {
254 TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT),
255 InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
256 return Instructions.modTcpSrc(tcpPort);
257 } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_DST.name())) {
258 TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT),
259 InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
260 return Instructions.modUdpDst(udpPort);
261 } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_SRC.name())) {
262 TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT),
263 InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
264 return Instructions.modUdpSrc(udpPort);
265 }
266 throw new IllegalArgumentException("L4 Instruction subtype "
267 + subType + " is not supported");
268 }
269
Cem Türker3baff672017-10-12 15:09:01 +0300270 private Instruction decodeStatTrigger() {
271 String statTriggerFlag = nullIsIllegal(json.get(InstructionCodec.STAT_TRIGGER_FLAG),
272 InstructionCodec.STAT_TRIGGER_FLAG + InstructionCodec.ERROR_MESSAGE).asText();
273
274 StatTriggerFlag flag = null;
275
276 if (statTriggerFlag.equals(StatTriggerFlag.ONLY_FIRST.name())) {
277 flag = StatTriggerFlag.ONLY_FIRST;
278 } else if (statTriggerFlag.equals(StatTriggerFlag.PERIODIC.name())) {
279 flag = StatTriggerFlag.PERIODIC;
280 } else {
281 throw new IllegalArgumentException("statTriggerFlag "
282 + statTriggerFlag + " is not supported");
283 }
284 if (!json.has(InstructionCodec.STAT_THRESHOLDS)) {
285 throw new IllegalArgumentException("statThreshold is not added");
286 }
287 JsonNode statThresholdsNode = nullIsIllegal(json.get(InstructionCodec.STAT_THRESHOLDS),
288 InstructionCodec.STAT_THRESHOLDS + InstructionCodec.ERROR_MESSAGE);
289 Map<StatTriggerField, Long> statThresholdMap = getStatThreshold(statThresholdsNode);
290 if (statThresholdMap.isEmpty()) {
291 throw new IllegalArgumentException("statThreshold must have at least one property");
292 }
293 return Instructions.statTrigger(statThresholdMap, flag);
294 }
295
296 private Map<StatTriggerField, Long> getStatThreshold(JsonNode statThresholdNode) {
297 Map<StatTriggerField, Long> statThresholdMap = Maps.newEnumMap(StatTriggerField.class);
298 for (JsonNode jsonNode : statThresholdNode) {
299 if (jsonNode.hasNonNull(InstructionCodec.STAT_BYTE_COUNT)) {
300 JsonNode byteCountNode = jsonNode.get(InstructionCodec.STAT_BYTE_COUNT);
301 if (!byteCountNode.isNull() && byteCountNode.isNumber()) {
302 statThresholdMap.put(StatTriggerField.BYTE_COUNT, byteCountNode.asLong());
303 }
304 } else if (jsonNode.hasNonNull(STAT_PACKET_COUNT)) {
305 JsonNode packetCount = jsonNode.get(STAT_PACKET_COUNT);
306 if (!packetCount.isNull() && packetCount.isNumber()) {
307 statThresholdMap.put(StatTriggerField.PACKET_COUNT, packetCount.asLong());
308 }
309 } else if (jsonNode.hasNonNull(InstructionCodec.STAT_DURATION)) {
310 JsonNode duration = jsonNode.get(InstructionCodec.STAT_DURATION);
311 if (!duration.isNull() && duration.isNumber()) {
312 statThresholdMap.put(StatTriggerField.DURATION, duration.asLong());
313 }
314 } else {
315 log.error("Unsupported stat {}", jsonNode.toString());
316 }
317 }
318
319 return statThresholdMap;
320 }
321
Hyunsun Moonfab29502015-08-25 13:39:16 -0700322 /**
Jian Lidab72562016-04-12 14:10:32 -0700323 * Decodes a extension instruction.
324 *
325 * @return extension treatment
326 */
327 private Instruction decodeExtension() {
328 ObjectNode node = (ObjectNode) json.get(InstructionCodec.EXTENSION);
329 if (node != null) {
330 DeviceId deviceId = getDeviceId();
331
332 ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
333 DeviceService deviceService = serviceDirectory.get(DeviceService.class);
334 Device device = deviceService.getDevice(deviceId);
335
Jonathan Harte3bcfc32016-08-16 17:12:49 -0700336 if (device == null) {
337 throw new IllegalArgumentException("Device not found");
338 }
339
Jian Lidab72562016-04-12 14:10:32 -0700340 if (device.is(ExtensionTreatmentCodec.class)) {
341 ExtensionTreatmentCodec treatmentCodec = device.as(ExtensionTreatmentCodec.class);
Jonathan Harte3bcfc32016-08-16 17:12:49 -0700342 ExtensionTreatment treatment = treatmentCodec.decode(node, context);
Jian Lidab72562016-04-12 14:10:32 -0700343 return Instructions.extension(treatment, deviceId);
344 } else {
Jonathan Harte3bcfc32016-08-16 17:12:49 -0700345 throw new IllegalArgumentException(
346 "There is no codec to decode extension for device " + deviceId.toString());
Jian Lidab72562016-04-12 14:10:32 -0700347 }
348 }
349 return null;
350 }
351
352 /**
353 * Returns device identifier.
354 *
355 * @return device identifier
356 * @throws IllegalArgumentException if the JSON is invalid
357 */
358 private DeviceId getDeviceId() {
359 JsonNode deviceIdNode = json.get(InstructionCodec.DEVICE_ID);
360 if (deviceIdNode != null) {
361 return DeviceId.deviceId(deviceIdNode.asText());
362 }
363 throw new IllegalArgumentException("Empty device identifier");
364 }
365
366 /**
Jian Li70dffe42016-03-08 22:23:02 -0800367 * Extracts port number of the given json node.
368 *
369 * @param jsonNode json node
370 * @return port number
371 */
372 private PortNumber getPortNumber(ObjectNode jsonNode) {
373 PortNumber portNumber;
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530374 JsonNode portNode = nullIsIllegal(jsonNode.get(InstructionCodec.PORT),
375 InstructionCodec.PORT + InstructionCodec.ERROR_MESSAGE);
376 if (portNode.isLong() || portNode.isInt()) {
377 portNumber = PortNumber.portNumber(portNode.asLong());
378 } else if (portNode.isTextual()) {
379 portNumber = PortNumber.fromString(portNode.textValue());
Jian Li70dffe42016-03-08 22:23:02 -0800380 } else {
381 throw new IllegalArgumentException("Port value "
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530382 + portNode.toString()
Jian Li70dffe42016-03-08 22:23:02 -0800383 + " is not supported");
384 }
385 return portNumber;
386 }
387
388 /**
Konstantinos Kanonakis9215ff22016-11-04 13:28:11 -0500389 * Returns Ethernet type.
390 *
391 * @return ethernet type
392 * @throws IllegalArgumentException if the JSON is invalid
393 */
394 private EthType getEthType() {
395 String ethTypeStr = nullIsIllegal(json.get(InstructionCodec.ETHERNET_TYPE),
396 InstructionCodec.ETHERNET_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
397 Matcher matcher = ETHTYPE_PATTERN.matcher(ethTypeStr);
398 if (!matcher.matches()) {
399 throw new IllegalArgumentException("ETHERNET_TYPE must be a four digit hex string starting with 0x");
400 }
401 short ethernetType = (short) Integer.parseInt(matcher.group(1), 16);
402 return new EthType(ethernetType);
403 }
404
405 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700406 * Decodes the JSON into an instruction object.
407 *
408 * @return Criterion object
409 * @throws IllegalArgumentException if the JSON is invalid
410 */
411 public Instruction decode() {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530412 String type = nullIsIllegal(json.get(InstructionCodec.TYPE),
413 InstructionCodec.TYPE + InstructionCodec.ERROR_MESSAGE).asText();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700414
415 if (type.equals(Instruction.Type.OUTPUT.name())) {
Jian Li70dffe42016-03-08 22:23:02 -0800416 return Instructions.createOutput(getPortNumber(json));
Ray Milkey2be39ed2016-02-22 15:54:19 -0800417 } else if (type.equals(Instruction.Type.NOACTION.name())) {
418 return Instructions.createNoAction();
Jian Li1ef82db2016-03-03 14:43:21 -0800419 } else if (type.equals(Instruction.Type.TABLE.name())) {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530420 return Instructions.transition(nullIsIllegal(json.get(InstructionCodec.TABLE_ID),
421 InstructionCodec.TABLE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
Jian Lice8c5602016-03-03 21:43:24 -0800422 } else if (type.equals(Instruction.Type.GROUP.name())) {
Yi Tsengfa394de2017-02-01 11:26:40 -0800423 GroupId groupId = new GroupId(nullIsIllegal(json.get(InstructionCodec.GROUP_ID),
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530424 InstructionCodec.GROUP_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
Jian Lice8c5602016-03-03 21:43:24 -0800425 return Instructions.createGroup(groupId);
Jian Li47b26232016-03-07 09:59:59 -0800426 } else if (type.equals(Instruction.Type.METER.name())) {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530427 MeterId meterId = MeterId.meterId(nullIsIllegal(json.get(InstructionCodec.METER_ID),
428 InstructionCodec.METER_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong());
Jian Li47b26232016-03-07 09:59:59 -0800429 return Instructions.meterTraffic(meterId);
Jian Li70dffe42016-03-08 22:23:02 -0800430 } else if (type.equals(Instruction.Type.QUEUE.name())) {
Jayasree Ghosh8aca6772016-10-04 03:32:11 +0530431 long queueId = nullIsIllegal(json.get(InstructionCodec.QUEUE_ID),
432 InstructionCodec.QUEUE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong();
ke han74702102016-11-29 14:57:29 +0800433 if (json.get(InstructionCodec.PORT) == null ||
434 json.get(InstructionCodec.PORT).isNull()) {
435 return Instructions.setQueue(queueId, null);
436 } else {
437 return Instructions.setQueue(queueId, getPortNumber(json));
438 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700439 } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) {
440 return decodeL0();
Yafit Hadar5796d972015-10-15 13:16:11 +0300441 } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) {
442 return decodeL1();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700443 } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) {
444 return decodeL2();
445 } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) {
446 return decodeL3();
Hyunsun Moonfab29502015-08-25 13:39:16 -0700447 } else if (type.equals(Instruction.Type.L4MODIFICATION.name())) {
448 return decodeL4();
Jian Lidab72562016-04-12 14:10:32 -0700449 } else if (type.equals(Instruction.Type.EXTENSION.name())) {
450 return decodeExtension();
Cem Türker3baff672017-10-12 15:09:01 +0300451 } else if (type.equals(Instruction.Type.STAT_TRIGGER.name())) {
452 return decodeStatTrigger();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700453 }
454 throw new IllegalArgumentException("Instruction type "
455 + type + " is not supported");
456 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700457}