blob: 5e69b0e2e93f8cf215c8392b1c4b925bb458c701 [file] [log] [blame]
Ray Milkeyd43fe452015-05-29 09:35:12 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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;
Jian Lidab72562016-04-12 14:10:32 -070020import org.onlab.osgi.DefaultServiceDirectory;
21import org.onlab.osgi.ServiceDirectory;
Ray Milkeyd43fe452015-05-29 09:35:12 -070022import org.onlab.packet.IpAddress;
23import org.onlab.packet.MacAddress;
24import org.onlab.packet.MplsLabel;
Hyunsun Moonfab29502015-08-25 13:39:16 -070025import org.onlab.packet.TpPort;
Ray Milkeyd43fe452015-05-29 09:35:12 -070026import org.onlab.packet.VlanId;
Yafit Hadar5796d972015-10-15 13:16:11 +030027import org.onlab.util.HexString;
Jonathan Harte3bcfc32016-08-16 17:12:49 -070028import org.onosproject.codec.CodecContext;
Jian Lidab72562016-04-12 14:10:32 -070029import org.onosproject.codec.ExtensionTreatmentCodec;
Jian Lice8c5602016-03-03 21:43:24 -080030import org.onosproject.core.DefaultGroupId;
31import org.onosproject.core.GroupId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070032import org.onosproject.net.ChannelSpacing;
Jian Lidab72562016-04-12 14:10:32 -070033import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070035import org.onosproject.net.GridType;
Ray Milkeyd43fe452015-05-29 09:35:12 -070036import org.onosproject.net.OchSignal;
Yafit Hadar5796d972015-10-15 13:16:11 +030037import org.onosproject.net.OduSignalId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070038import org.onosproject.net.PortNumber;
Jian Lidab72562016-04-12 14:10:32 -070039import org.onosproject.net.device.DeviceService;
40import org.onosproject.net.flow.instructions.ExtensionTreatment;
Ray Milkeyd43fe452015-05-29 09:35:12 -070041import org.onosproject.net.flow.instructions.Instruction;
42import org.onosproject.net.flow.instructions.Instructions;
43import org.onosproject.net.flow.instructions.L0ModificationInstruction;
Yafit Hadar5796d972015-10-15 13:16:11 +030044import org.onosproject.net.flow.instructions.L1ModificationInstruction;
Ray Milkeyd43fe452015-05-29 09:35:12 -070045import org.onosproject.net.flow.instructions.L2ModificationInstruction;
46import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Hyunsun Moonfab29502015-08-25 13:39:16 -070047import org.onosproject.net.flow.instructions.L4ModificationInstruction;
Jian Li47b26232016-03-07 09:59:59 -080048import org.onosproject.net.meter.MeterId;
Jian Lidab72562016-04-12 14:10:32 -070049import org.slf4j.Logger;
Ray Milkeyd43fe452015-05-29 09:35:12 -070050
Jian Li1ef82db2016-03-03 14:43:21 -080051import static org.onlab.util.Tools.nullIsIllegal;
Jian Lidab72562016-04-12 14:10:32 -070052import static org.slf4j.LoggerFactory.getLogger;
Ray Milkeyd43fe452015-05-29 09:35:12 -070053
54/**
55 * Decoding portion of the instruction codec.
56 */
Ray Milkey6d7968e2015-07-06 14:30:02 -070057public final class DecodeInstructionCodecHelper {
Jian Lidab72562016-04-12 14:10:32 -070058 protected static final Logger log = getLogger(DecodeInstructionCodecHelper.class);
Ray Milkeyd43fe452015-05-29 09:35:12 -070059 private final ObjectNode json;
Jonathan Harte3bcfc32016-08-16 17:12:49 -070060 private final CodecContext context;
Ray Milkeyd43fe452015-05-29 09:35:12 -070061
62 /**
63 * Creates a decode instruction codec object.
64 *
65 * @param json JSON object to decode
66 */
Jonathan Harte3bcfc32016-08-16 17:12:49 -070067 public DecodeInstructionCodecHelper(ObjectNode json, CodecContext context) {
Ray Milkeyd43fe452015-05-29 09:35:12 -070068 this.json = json;
Jonathan Harte3bcfc32016-08-16 17:12:49 -070069 this.context = context;
Ray Milkeyd43fe452015-05-29 09:35:12 -070070 }
71
72 /**
73 * Decodes a Layer 2 instruction.
74 *
75 * @return instruction object decoded from the JSON
76 * @throws IllegalArgumentException if the JSON is invalid
77 */
78 private Instruction decodeL2() {
79 String subType = json.get(InstructionCodec.SUBTYPE).asText();
80
81 if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) {
82 String mac = nullIsIllegal(json.get(InstructionCodec.MAC),
83 InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
84 return Instructions.modL2Src(MacAddress.valueOf(mac));
85 } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) {
86 String mac = nullIsIllegal(json.get(InstructionCodec.MAC),
87 InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
88 return Instructions.modL2Dst(MacAddress.valueOf(mac));
89 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) {
90 short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID),
91 InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
92 return Instructions.modVlanId(VlanId.vlanId(vlanId));
93 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) {
94 byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP),
95 InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
96 return Instructions.modVlanPcp(vlanPcp);
97 } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) {
98 int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL),
99 InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
100 return Instructions.modMplsLabel(MplsLabel.mplsLabel(label));
101 } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) {
102 return Instructions.pushMpls();
103 } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) {
104 return Instructions.popMpls();
105 } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) {
106 return Instructions.decMplsTtl();
107 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) {
108 return Instructions.popVlan();
109 } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) {
110 return Instructions.pushVlan();
Hyunsun Moon7080a0d2015-08-14 19:18:48 -0700111 } else if (subType.equals(L2ModificationInstruction.L2SubType.TUNNEL_ID.name())) {
112 long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID),
113 InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong();
114 return Instructions.modTunnelId(tunnelId);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700115 }
116 throw new IllegalArgumentException("L2 Instruction subtype "
117 + subType + " is not supported");
118 }
119
120 /**
121 * Decodes a Layer 3 instruction.
122 *
123 * @return instruction object decoded from the JSON
124 * @throws IllegalArgumentException if the JSON is invalid
125 */
126 private Instruction decodeL3() {
127 String subType = json.get(InstructionCodec.SUBTYPE).asText();
128
129 if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) {
130 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
131 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
132 return Instructions.modL3Src(ip);
133 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) {
134 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
135 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
136 return Instructions.modL3Dst(ip);
137 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) {
138 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
139 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
140 return Instructions.modL3IPv6Src(ip);
141 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) {
142 IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
143 InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
144 return Instructions.modL3IPv6Dst(ip);
145 } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) {
146 int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL),
147 InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
148 return Instructions.modL3IPv6FlowLabel(flowLabel);
149 }
150 throw new IllegalArgumentException("L3 Instruction subtype "
151 + subType + " is not supported");
152 }
153
154 /**
155 * Decodes a Layer 0 instruction.
156 *
157 * @return instruction object decoded from the JSON
158 * @throws IllegalArgumentException if the JSON is invalid
159 */
160 private Instruction decodeL0() {
161 String subType = json.get(InstructionCodec.SUBTYPE).asText();
162
Sho SHIMIZUcc137a92016-03-11 15:10:54 -0800163 if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) {
Ray Milkeyd43fe452015-05-29 09:35:12 -0700164 String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE),
165 InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
166 GridType gridType = GridType.valueOf(gridTypeString);
167 if (gridType == null) {
168 throw new IllegalArgumentException("Unknown grid type "
169 + gridTypeString);
170 }
171 String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING),
172 InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
173 ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString);
174 if (channelSpacing == null) {
175 throw new IllegalArgumentException("Unknown channel spacing "
176 + channelSpacingString);
177 }
178 int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER),
179 InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
180 int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY),
181 InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
182 return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing,
183 spacingMultiplier, slotGranularity));
184 }
185 throw new IllegalArgumentException("L0 Instruction subtype "
186 + subType + " is not supported");
187 }
188
189 /**
Yafit Hadar5796d972015-10-15 13:16:11 +0300190 * Decodes a Layer 1 instruction.
191 *
192 * @return instruction object decoded from the JSON
193 * @throws IllegalArgumentException if the JSON is invalid
194 */
195 private Instruction decodeL1() {
196 String subType = json.get(InstructionCodec.SUBTYPE).asText();
197 if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) {
198 int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER),
199 InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
200 int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN),
201 InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
202 byte[] tributarySlotBitmap = null;
203 tributarySlotBitmap = HexString.fromHexString(
204 nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP),
205 InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
206 return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen,
207 tributarySlotBitmap));
208 }
209 throw new IllegalArgumentException("L1 Instruction subtype "
210 + subType + " is not supported");
211 }
212
213 /**
Hyunsun Moonfab29502015-08-25 13:39:16 -0700214 * Decodes a Layer 4 instruction.
215 *
216 * @return instruction object decoded from the JSON
217 * @throws IllegalArgumentException if the JSON is invalid
218 */
219 private Instruction decodeL4() {
220 String subType = json.get(InstructionCodec.SUBTYPE).asText();
221
222 if (subType.equals(L4ModificationInstruction.L4SubType.TCP_DST.name())) {
223 TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT),
224 InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
225 return Instructions.modTcpDst(tcpPort);
226 } else if (subType.equals(L4ModificationInstruction.L4SubType.TCP_SRC.name())) {
227 TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT),
228 InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
229 return Instructions.modTcpSrc(tcpPort);
230 } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_DST.name())) {
231 TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT),
232 InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
233 return Instructions.modUdpDst(udpPort);
234 } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_SRC.name())) {
235 TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT),
236 InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt());
237 return Instructions.modUdpSrc(udpPort);
238 }
239 throw new IllegalArgumentException("L4 Instruction subtype "
240 + subType + " is not supported");
241 }
242
243 /**
Jian Lidab72562016-04-12 14:10:32 -0700244 * Decodes a extension instruction.
245 *
246 * @return extension treatment
247 */
248 private Instruction decodeExtension() {
249 ObjectNode node = (ObjectNode) json.get(InstructionCodec.EXTENSION);
250 if (node != null) {
251 DeviceId deviceId = getDeviceId();
252
253 ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
254 DeviceService deviceService = serviceDirectory.get(DeviceService.class);
255 Device device = deviceService.getDevice(deviceId);
256
Jonathan Harte3bcfc32016-08-16 17:12:49 -0700257 if (device == null) {
258 throw new IllegalArgumentException("Device not found");
259 }
260
Jian Lidab72562016-04-12 14:10:32 -0700261 if (device.is(ExtensionTreatmentCodec.class)) {
262 ExtensionTreatmentCodec treatmentCodec = device.as(ExtensionTreatmentCodec.class);
Jonathan Harte3bcfc32016-08-16 17:12:49 -0700263 ExtensionTreatment treatment = treatmentCodec.decode(node, context);
Jian Lidab72562016-04-12 14:10:32 -0700264 return Instructions.extension(treatment, deviceId);
265 } else {
Jonathan Harte3bcfc32016-08-16 17:12:49 -0700266 throw new IllegalArgumentException(
267 "There is no codec to decode extension for device " + deviceId.toString());
Jian Lidab72562016-04-12 14:10:32 -0700268 }
269 }
270 return null;
271 }
272
273 /**
274 * Returns device identifier.
275 *
276 * @return device identifier
277 * @throws IllegalArgumentException if the JSON is invalid
278 */
279 private DeviceId getDeviceId() {
280 JsonNode deviceIdNode = json.get(InstructionCodec.DEVICE_ID);
281 if (deviceIdNode != null) {
282 return DeviceId.deviceId(deviceIdNode.asText());
283 }
284 throw new IllegalArgumentException("Empty device identifier");
285 }
286
287 /**
Jian Li70dffe42016-03-08 22:23:02 -0800288 * Extracts port number of the given json node.
289 *
290 * @param jsonNode json node
291 * @return port number
292 */
293 private PortNumber getPortNumber(ObjectNode jsonNode) {
294 PortNumber portNumber;
295 if (jsonNode.get(InstructionCodec.PORT).isLong() || jsonNode.get(InstructionCodec.PORT).isInt()) {
296 portNumber = PortNumber
297 .portNumber(nullIsIllegal(jsonNode.get(InstructionCodec.PORT)
298 .asLong(), InstructionCodec.PORT
299 + InstructionCodec.MISSING_MEMBER_MESSAGE));
300 } else if (jsonNode.get(InstructionCodec.PORT).isTextual()) {
301 portNumber = PortNumber
302 .fromString(nullIsIllegal(jsonNode.get(InstructionCodec.PORT)
303 .textValue(), InstructionCodec.PORT
304 + InstructionCodec.MISSING_MEMBER_MESSAGE));
305 } else {
306 throw new IllegalArgumentException("Port value "
307 + jsonNode.get(InstructionCodec.PORT).toString()
308 + " is not supported");
309 }
310 return portNumber;
311 }
312
313 /**
Ray Milkeyd43fe452015-05-29 09:35:12 -0700314 * Decodes the JSON into an instruction object.
315 *
316 * @return Criterion object
317 * @throws IllegalArgumentException if the JSON is invalid
318 */
319 public Instruction decode() {
320 String type = json.get(InstructionCodec.TYPE).asText();
321
322 if (type.equals(Instruction.Type.OUTPUT.name())) {
Jian Li70dffe42016-03-08 22:23:02 -0800323 return Instructions.createOutput(getPortNumber(json));
Ray Milkey2be39ed2016-02-22 15:54:19 -0800324 } else if (type.equals(Instruction.Type.NOACTION.name())) {
325 return Instructions.createNoAction();
Jian Li1ef82db2016-03-03 14:43:21 -0800326 } else if (type.equals(Instruction.Type.TABLE.name())) {
327 return Instructions.transition(nullIsIllegal(json.get(InstructionCodec.TABLE_ID)
328 .asInt(), InstructionCodec.TABLE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE));
Jian Lice8c5602016-03-03 21:43:24 -0800329 } else if (type.equals(Instruction.Type.GROUP.name())) {
330 GroupId groupId = new DefaultGroupId(nullIsIllegal(json.get(InstructionCodec.GROUP_ID)
331 .asInt(), InstructionCodec.GROUP_ID + InstructionCodec.MISSING_MEMBER_MESSAGE));
332 return Instructions.createGroup(groupId);
Jian Li47b26232016-03-07 09:59:59 -0800333 } else if (type.equals(Instruction.Type.METER.name())) {
334 MeterId meterId = MeterId.meterId(nullIsIllegal(json.get(InstructionCodec.METER_ID)
335 .asLong(), InstructionCodec.METER_ID + InstructionCodec.MISSING_MEMBER_MESSAGE));
336 return Instructions.meterTraffic(meterId);
Jian Li70dffe42016-03-08 22:23:02 -0800337 } else if (type.equals(Instruction.Type.QUEUE.name())) {
338 long queueId = nullIsIllegal(json.get(InstructionCodec.QUEUE_ID)
339 .asLong(), InstructionCodec.QUEUE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE);
340 return Instructions.setQueue(queueId, getPortNumber(json));
Ray Milkeyd43fe452015-05-29 09:35:12 -0700341 } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) {
342 return decodeL0();
Yafit Hadar5796d972015-10-15 13:16:11 +0300343 } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) {
344 return decodeL1();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700345 } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) {
346 return decodeL2();
347 } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) {
348 return decodeL3();
Hyunsun Moonfab29502015-08-25 13:39:16 -0700349 } else if (type.equals(Instruction.Type.L4MODIFICATION.name())) {
350 return decodeL4();
Jian Lidab72562016-04-12 14:10:32 -0700351 } else if (type.equals(Instruction.Type.EXTENSION.name())) {
352 return decodeExtension();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700353 }
354 throw new IllegalArgumentException("Instruction type "
355 + type + " is not supported");
356 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700357}