blob: 5eaa20e26800d5d1feae7cd246fa921f51f9227c [file] [log] [blame]
Ray Milkeyd43fe452015-05-29 09:35:12 -07001/*
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 */
16package org.onosproject.codec.impl;
17
18import java.io.IOException;
19import java.io.InputStream;
20import java.util.SortedMap;
21import java.util.TreeMap;
22
23import org.junit.Before;
24import org.junit.Test;
25import org.onlab.packet.Ethernet;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.IpPrefix;
28import org.onlab.packet.MacAddress;
29import org.onlab.packet.MplsLabel;
30import org.onlab.packet.VlanId;
31import org.onosproject.codec.JsonCodec;
32import org.onosproject.core.CoreService;
33import org.onosproject.net.ChannelSpacing;
34import org.onosproject.net.GridType;
35import org.onosproject.net.Lambda;
36import org.onosproject.net.OchSignal;
37import org.onosproject.net.PortNumber;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.criteria.Criterion;
40import org.onosproject.net.flow.criteria.EthCriterion;
41import org.onosproject.net.flow.criteria.EthTypeCriterion;
42import org.onosproject.net.flow.criteria.IPCriterion;
43import org.onosproject.net.flow.criteria.IPDscpCriterion;
44import org.onosproject.net.flow.criteria.IPEcnCriterion;
45import org.onosproject.net.flow.criteria.IPProtocolCriterion;
46import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion;
47import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion;
48import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion;
49import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion;
50import org.onosproject.net.flow.criteria.IcmpCodeCriterion;
51import org.onosproject.net.flow.criteria.IcmpTypeCriterion;
52import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
53import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
54import org.onosproject.net.flow.criteria.IndexedLambdaCriterion;
55import org.onosproject.net.flow.criteria.MplsCriterion;
56import org.onosproject.net.flow.criteria.OchSignalCriterion;
57import org.onosproject.net.flow.criteria.PortCriterion;
58import org.onosproject.net.flow.criteria.SctpPortCriterion;
59import org.onosproject.net.flow.criteria.TcpPortCriterion;
60import org.onosproject.net.flow.criteria.UdpPortCriterion;
61import org.onosproject.net.flow.criteria.VlanIdCriterion;
62import org.onosproject.net.flow.criteria.VlanPcpCriterion;
63import org.onosproject.net.flow.instructions.Instruction;
64import org.onosproject.net.flow.instructions.Instructions;
65import org.onosproject.net.flow.instructions.L0ModificationInstruction;
66import org.onosproject.net.flow.instructions.L2ModificationInstruction;
67import org.onosproject.net.flow.instructions.L3ModificationInstruction;
68
69import com.fasterxml.jackson.databind.JsonNode;
70import com.fasterxml.jackson.databind.node.ObjectNode;
71
72import static org.easymock.EasyMock.createMock;
73import static org.easymock.EasyMock.expect;
74import static org.easymock.EasyMock.replay;
75import static org.hamcrest.MatcherAssert.assertThat;
76import static org.hamcrest.Matchers.instanceOf;
77import static org.hamcrest.Matchers.is;
78import static org.hamcrest.Matchers.notNullValue;
79import static org.onosproject.net.NetTestTools.APP_ID;
80
81/**
82 * Flow rule codec unit tests.
83 */
84public class FlowRuleCodecTest {
85
86 MockCodecContext context;
87 JsonCodec<FlowRule> flowRuleCodec;
88 final CoreService mockCoreService = createMock(CoreService.class);
89
90 /**
91 * Sets up for each test. Creates a context and fetches the flow rule
92 * codec.
93 */
94 @Before
95 public void setUp() {
96 context = new MockCodecContext();
97 flowRuleCodec = context.codec(FlowRule.class);
98 assertThat(flowRuleCodec, notNullValue());
99
100 expect(mockCoreService.getAppId(APP_ID.id()))
101 .andReturn(APP_ID).anyTimes();
102 replay(mockCoreService);
103 context.registerService(CoreService.class, mockCoreService);
104 }
105
106 /**
107 * Reads in a rule from the given resource and decodes it.
108 *
109 * @param resourceName resource to use to read the JSON for the rule
110 * @return decoded flow rule
111 * @throws IOException if processing the resource fails
112 */
113 private FlowRule getRule(String resourceName) throws IOException {
114 InputStream jsonStream = FlowRuleCodecTest.class
115 .getResourceAsStream(resourceName);
116 JsonNode json = context.mapper().readTree(jsonStream);
117 assertThat(json, notNullValue());
118 FlowRule rule = flowRuleCodec.decode((ObjectNode) json, context);
119 assertThat(rule, notNullValue());
120 return rule;
121 }
122
123 /**
124 * Checks that the data shared by all the resources is correct for a
125 * given rule.
126 *
127 * @param rule rule to check
128 */
129 private void checkCommonData(FlowRule rule) {
130 assertThat(rule.appId(), is(APP_ID.id()));
131 assertThat(rule.isPermanent(), is(false));
132 assertThat(rule.timeout(), is(1));
133 assertThat(rule.priority(), is(1));
134 assertThat(rule.deviceId().toString(), is("of:0000000000000001"));
135 }
136
137 /**
138 * Checks that a simple rule decodes properly.
139 *
140 * @throws IOException if the resource cannot be processed
141 */
142 @Test
143 public void codecSimpleFlowTest() throws IOException {
144 FlowRule rule = getRule("simple-flow.json");
145
146 checkCommonData(rule);
147
148 assertThat(rule.selector().criteria().size(), is(1));
149 Criterion criterion1 = rule.selector().criteria().iterator().next();
150 assertThat(criterion1.type(), is(Criterion.Type.ETH_TYPE));
151 assertThat(((EthTypeCriterion) criterion1).ethType(), is(2054));
152
153 assertThat(rule.treatment().allInstructions().size(), is(1));
154 Instruction instruction1 = rule.treatment().allInstructions().get(0);
155 assertThat(instruction1.type(), is(Instruction.Type.OUTPUT));
156 assertThat(((Instructions.OutputInstruction) instruction1).port(), is(PortNumber.CONTROLLER));
157 }
158
159 SortedMap<String, Instruction> instructions = new TreeMap<>();
160
161 /**
162 * Looks up an instruction in the instruction map based on type and subtype.
163 *
164 * @param type type string
165 * @param subType subtype string
166 * @return instruction that matches
167 */
168 private Instruction getInstruction(Instruction.Type type, String subType) {
169 Instruction instruction = instructions.get(type.name() + "/" + subType);
170 assertThat(instruction, notNullValue());
171 assertThat(instruction.type(), is(type));
172 return instruction;
173 }
174
175 /**
176 * Checks that a rule with one of each instruction type decodes properly.
177 *
178 * @throws IOException if the resource cannot be processed
179 */
180 @Test
181 public void decodeInstructionsFlowTest() throws Exception {
182 FlowRule rule = getRule("instructions-flow.json");
183
184 checkCommonData(rule);
185
186 rule.treatment().allInstructions()
187 .stream()
188 .forEach(instruction ->
189 {
190 String subType;
191 if (instruction.type() == Instruction.Type.L0MODIFICATION) {
192 subType = ((L0ModificationInstruction) instruction)
193 .subtype().name();
194 } else if (instruction.type() == Instruction.Type.L2MODIFICATION) {
195 subType = ((L2ModificationInstruction) instruction)
196 .subtype().name();
197 } else if (instruction.type() == Instruction.Type.L3MODIFICATION) {
198 subType = ((L3ModificationInstruction) instruction)
199 .subtype().name();
200 } else {
201 subType = "";
202 }
203 instructions.put(
204 instruction.type().name() + "/" + subType, instruction);
205 });
206
207 assertThat(rule.treatment().allInstructions().size(), is(19));
208
209 Instruction instruction;
210
211 instruction = getInstruction(Instruction.Type.OUTPUT, "");
212 assertThat(instruction.type(), is(Instruction.Type.OUTPUT));
213 assertThat(((Instructions.OutputInstruction) instruction).port(), is(PortNumber.CONTROLLER));
214
215 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
216 L2ModificationInstruction.L2SubType.ETH_SRC.name());
217 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
218 assertThat(((L2ModificationInstruction.ModEtherInstruction) instruction).mac(),
219 is(MacAddress.valueOf("12:34:56:78:90:12")));
220
221 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
222 L2ModificationInstruction.L2SubType.ETH_DST.name());
223 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
224 assertThat(((L2ModificationInstruction.ModEtherInstruction) instruction).mac(),
225 is(MacAddress.valueOf("98:76:54:32:01:00")));
226
227 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
228 L2ModificationInstruction.L2SubType.VLAN_ID.name());
229 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
230 assertThat(((L2ModificationInstruction.ModVlanIdInstruction) instruction).vlanId().toShort(),
231 is((short) 22));
232
233 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
234 L2ModificationInstruction.L2SubType.VLAN_PCP.name());
235 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
236 assertThat(((L2ModificationInstruction.ModVlanPcpInstruction) instruction).vlanPcp(),
237 is((byte) 1));
238
239 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
240 L2ModificationInstruction.L2SubType.MPLS_LABEL.name());
241 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
242 assertThat(((L2ModificationInstruction.ModMplsLabelInstruction) instruction)
243 .label().shortValue(),
244 is((short) 777));
245
246 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
247 L2ModificationInstruction.L2SubType.MPLS_PUSH.name());
248 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
249 assertThat((short) ((L2ModificationInstruction.PushHeaderInstructions) instruction)
250 .ethernetType(),
251 is(Ethernet.MPLS_UNICAST));
252
253 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
254 L2ModificationInstruction.L2SubType.MPLS_POP.name());
255 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
256 assertThat((short) ((L2ModificationInstruction.PushHeaderInstructions) instruction)
257 .ethernetType(),
258 is(Ethernet.MPLS_UNICAST));
259
260 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
261 L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name());
262 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
263 assertThat(instruction, instanceOf(L2ModificationInstruction.ModMplsTtlInstruction.class));
264
265 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
266 L2ModificationInstruction.L2SubType.VLAN_POP.name());
267 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
268 assertThat(instruction, instanceOf(L2ModificationInstruction.PopVlanInstruction.class));
269
270 instruction = getInstruction(Instruction.Type.L2MODIFICATION,
271 L2ModificationInstruction.L2SubType.VLAN_PUSH.name());
272 assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION));
273 assertThat(instruction, instanceOf(L2ModificationInstruction.PushHeaderInstructions.class));
274
275 instruction = getInstruction(Instruction.Type.L3MODIFICATION,
276 L3ModificationInstruction.L3SubType.IPV4_SRC.name());
277 assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION));
278 assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(),
279 is(IpAddress.valueOf("1.2.3.4")));
280
281 instruction = getInstruction(Instruction.Type.L3MODIFICATION,
282 L3ModificationInstruction.L3SubType.IPV4_DST.name());
283 assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION));
284 assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(),
285 is(IpAddress.valueOf("1.2.3.3")));
286
287 instruction = getInstruction(Instruction.Type.L3MODIFICATION,
288 L3ModificationInstruction.L3SubType.IPV6_SRC.name());
289 assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION));
290 assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(),
291 is(IpAddress.valueOf("1.2.3.2")));
292
293 instruction = getInstruction(Instruction.Type.L3MODIFICATION,
294 L3ModificationInstruction.L3SubType.IPV6_DST.name());
295 assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION));
296 assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(),
297 is(IpAddress.valueOf("1.2.3.1")));
298
299 instruction = getInstruction(Instruction.Type.L3MODIFICATION,
300 L3ModificationInstruction.L3SubType.IPV6_FLABEL.name());
301 assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION));
302 assertThat(((L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction)
303 .flowLabel(),
304 is(8));
305
306 instruction = getInstruction(Instruction.Type.L0MODIFICATION,
307 L0ModificationInstruction.L0SubType.LAMBDA.name());
308 assertThat(instruction.type(), is(Instruction.Type.L0MODIFICATION));
309 assertThat(((L0ModificationInstruction.ModLambdaInstruction) instruction)
310 .lambda(),
311 is((short) 7));
312
313 instruction = getInstruction(Instruction.Type.L0MODIFICATION,
314 L0ModificationInstruction.L0SubType.OCH.name());
315 assertThat(instruction.type(), is(Instruction.Type.L0MODIFICATION));
316 L0ModificationInstruction.ModOchSignalInstruction och =
317 (L0ModificationInstruction.ModOchSignalInstruction) instruction;
318 assertThat(och.lambda().spacingMultiplier(), is(4));
319 assertThat(och.lambda().slotGranularity(), is(8));
320 assertThat(och.lambda().gridType(), is(GridType.DWDM));
321 assertThat(och.lambda().channelSpacing(), is(ChannelSpacing.CHL_100GHZ));
322 }
323
324 SortedMap<String, Criterion> criteria = new TreeMap<>();
325
326 /**
327 * Looks up a criterion in the instruction map based on type and subtype.
328 *
329 * @param type type string
330 * @return criterion that matches
331 */
332 private Criterion getCriterion(Criterion.Type type) {
333 Criterion criterion = criteria.get(type.name());
334 assertThat(criterion.type(), is(type));
335 return criterion;
336 }
337
338 /**
339 * Checks that a rule with one of each kind of criterion decodes properly.
340 *
341 * @throws IOException if the resource cannot be processed
342 */
343 @Test
344 public void codecCriteriaFlowTest() throws Exception {
345 FlowRule rule = getRule("criteria-flow.json");
346
347 checkCommonData(rule);
348
349 assertThat(rule.selector().criteria().size(), is(32));
350
351 rule.selector().criteria()
352 .stream()
353 .forEach(criterion ->
354 criteria.put(criterion.type().name(), criterion));
355
356 Criterion criterion;
357
358 criterion = getCriterion(Criterion.Type.ETH_TYPE);
359 assertThat(((EthTypeCriterion) criterion).ethType(), is(2054));
360
361 criterion = getCriterion(Criterion.Type.ETH_DST);
362 assertThat(((EthCriterion) criterion).mac(),
363 is(MacAddress.valueOf("00:11:22:33:44:55")));
364
365 criterion = getCriterion(Criterion.Type.ETH_SRC);
366 assertThat(((EthCriterion) criterion).mac(),
367 is(MacAddress.valueOf("00:11:22:33:44:55")));
368
369 criterion = getCriterion(Criterion.Type.IN_PORT);
370 assertThat(((PortCriterion) criterion).port(),
371 is(PortNumber.portNumber(23)));
372
373 criterion = getCriterion(Criterion.Type.IN_PHY_PORT);
374 assertThat(((PortCriterion) criterion).port(),
375 is(PortNumber.portNumber(44)));
376
377 criterion = getCriterion(Criterion.Type.VLAN_VID);
378 assertThat(((VlanIdCriterion) criterion).vlanId(),
379 is(VlanId.vlanId((short) 777)));
380
381 criterion = getCriterion(Criterion.Type.VLAN_PCP);
382 assertThat(((VlanPcpCriterion) criterion).priority(),
383 is(((byte) 3)));
384
385 criterion = getCriterion(Criterion.Type.IP_DSCP);
386 assertThat(((IPDscpCriterion) criterion).ipDscp(),
387 is(((byte) 2)));
388
389 criterion = getCriterion(Criterion.Type.IP_ECN);
390 assertThat(((IPEcnCriterion) criterion).ipEcn(),
391 is(((byte) 1)));
392
393 criterion = getCriterion(Criterion.Type.IP_PROTO);
394 assertThat(((IPProtocolCriterion) criterion).protocol(),
395 is(((short) 4)));
396
397 criterion = getCriterion(Criterion.Type.IPV4_SRC);
398 assertThat(((IPCriterion) criterion).ip(),
399 is((IpPrefix.valueOf("1.2.0.0/32"))));
400
401 criterion = getCriterion(Criterion.Type.IPV4_DST);
402 assertThat(((IPCriterion) criterion).ip(),
403 is((IpPrefix.valueOf("2.2.0.0/32"))));
404
405 criterion = getCriterion(Criterion.Type.IPV6_SRC);
406 assertThat(((IPCriterion) criterion).ip(),
407 is((IpPrefix.valueOf("3.2.0.0/32"))));
408
409 criterion = getCriterion(Criterion.Type.IPV6_DST);
410 assertThat(((IPCriterion) criterion).ip(),
411 is((IpPrefix.valueOf("4.2.0.0/32"))));
412
413 criterion = getCriterion(Criterion.Type.TCP_SRC);
414 assertThat(((TcpPortCriterion) criterion).tcpPort(),
415 is(80));
416
417 criterion = getCriterion(Criterion.Type.TCP_DST);
418 assertThat(((TcpPortCriterion) criterion).tcpPort(),
419 is(443));
420
421 criterion = getCriterion(Criterion.Type.UDP_SRC);
422 assertThat(((UdpPortCriterion) criterion).udpPort(),
423 is(180));
424
425 criterion = getCriterion(Criterion.Type.UDP_DST);
426 assertThat(((UdpPortCriterion) criterion).udpPort(),
427 is(1443));
428
429 criterion = getCriterion(Criterion.Type.SCTP_SRC);
430 assertThat(((SctpPortCriterion) criterion).sctpPort(),
431 is(280));
432
433 criterion = getCriterion(Criterion.Type.SCTP_DST);
434 assertThat(((SctpPortCriterion) criterion).sctpPort(),
435 is(2443));
436
437 criterion = getCriterion(Criterion.Type.ICMPV4_TYPE);
438 assertThat(((IcmpTypeCriterion) criterion).icmpType(),
439 is((short) 24));
440
441 criterion = getCriterion(Criterion.Type.ICMPV4_CODE);
442 assertThat(((IcmpCodeCriterion) criterion).icmpCode(),
443 is((short) 16));
444
445 criterion = getCriterion(Criterion.Type.ICMPV6_TYPE);
446 assertThat(((Icmpv6TypeCriterion) criterion).icmpv6Type(),
447 is((short) 14));
448
449 criterion = getCriterion(Criterion.Type.ICMPV6_CODE);
450 assertThat(((Icmpv6CodeCriterion) criterion).icmpv6Code(),
451 is((short) 6));
452
453 criterion = getCriterion(Criterion.Type.IPV6_FLABEL);
454 assertThat(((IPv6FlowLabelCriterion) criterion).flowLabel(),
455 is(8));
456
457 criterion = getCriterion(Criterion.Type.IPV6_ND_TARGET);
458 assertThat(((IPv6NDTargetAddressCriterion) criterion)
459 .targetAddress().toString(),
460 is("1111:2222:3333:4444:5555:6666:7777:8888"));
461
462 criterion = getCriterion(Criterion.Type.IPV6_ND_SLL);
463 assertThat(((IPv6NDLinkLayerAddressCriterion) criterion).mac(),
464 is(MacAddress.valueOf("00:11:22:33:44:56")));
465
466 criterion = getCriterion(Criterion.Type.IPV6_ND_TLL);
467 assertThat(((IPv6NDLinkLayerAddressCriterion) criterion).mac(),
468 is(MacAddress.valueOf("00:11:22:33:44:57")));
469
470 criterion = getCriterion(Criterion.Type.MPLS_LABEL);
471 assertThat(((MplsCriterion) criterion).label(),
472 is(MplsLabel.mplsLabel(123)));
473
474 criterion = getCriterion(Criterion.Type.IPV6_EXTHDR);
475 assertThat(((IPv6ExthdrFlagsCriterion) criterion).exthdrFlags(),
476 is(99));
477
478 criterion = getCriterion(Criterion.Type.OCH_SIGID);
479 assertThat(((IndexedLambdaCriterion) criterion).lambda(),
480 is(Lambda.indexedLambda(122)));
481 }
482
483 /**
484 * Checks that a rule with a SigId criterion decodes properly.
485 *
486 * @throws IOException if the resource cannot be processed
487 */
488 @Test
489 public void codecSigIdCriteriaFlowTest() throws Exception {
490 FlowRule rule = getRule("sigid-flow.json");
491
492 checkCommonData(rule);
493
494 assertThat(rule.selector().criteria().size(), is(1));
495 Criterion criterion = rule.selector().criteria().iterator().next();
496 assertThat(criterion.type(), is(Criterion.Type.OCH_SIGID));
497 Lambda lambda = ((OchSignalCriterion) criterion).lambda();
498 assertThat(lambda, instanceOf(OchSignal.class));
499 OchSignal ochSignal = (OchSignal) lambda;
500 assertThat(ochSignal.spacingMultiplier(), is(3));
501 assertThat(ochSignal.slotGranularity(), is(4));
502 assertThat(ochSignal.gridType(), is(GridType.CWDM));
503 assertThat(ochSignal.channelSpacing(), is(ChannelSpacing.CHL_25GHZ));
504 }
505
506}