Ray Milkey
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());
......
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 +}
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()) {
......
...@@ -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 +}
1 +{
2 + "appId":-29467,
3 + "priority":1,
4 + "isPermanent":"false",
5 + "timeout":1,
6 + "deviceId":"of:0000000000000001",
7 + "treatment":
8 + {"instructions":
9 + [{"type":"OUTPUT","port":-3}],"deferred":[]},
10 + "selector":
11 + {"criteria":
12 + [{"type":"ETH_TYPE","ethType":2054}]}
13 +}
...@@ -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
......
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 }
......