blob: 5769e8f3df97b97ddcc01166492b794f8c8ae1a0 [file] [log] [blame]
Yi Tseng0b809722017-11-03 10:23:26 -07001/*
2 * Copyright 2017-present Open Networking Foundation
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
17package org.onosproject.pipelines.fabric.pipeliner;
18
19import org.junit.Test;
20import org.onlab.packet.Ethernet;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
23import org.onlab.util.ImmutableByteSequence;
24import org.onosproject.net.PortNumber;
25import org.onosproject.net.flow.DefaultFlowRule;
26import org.onosproject.net.flow.DefaultTrafficSelector;
27import org.onosproject.net.flow.DefaultTrafficTreatment;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.TableId;
30import org.onosproject.net.flow.TrafficSelector;
31import org.onosproject.net.flow.TrafficTreatment;
32import org.onosproject.net.flow.criteria.Criteria;
33import org.onosproject.net.flowobjective.DefaultFilteringObjective;
34import org.onosproject.net.flowobjective.FilteringObjective;
35import org.onosproject.net.flowobjective.ObjectiveError;
36import org.onosproject.net.group.GroupDescription;
37import org.onosproject.net.pi.runtime.PiAction;
38import org.onosproject.net.pi.runtime.PiActionParam;
39import org.onosproject.pipelines.fabric.FabricConstants;
40
41import java.util.List;
42
43import static org.junit.Assert.assertEquals;
44import static org.junit.Assert.assertTrue;
45
46/**
47 * Test cases for fabric.p4 pipeline filtering control block.
48 */
49public class FabricFilteringPipelinerTest extends FabricPipelinerTest {
50
51 /**
52 * Creates one rule for ingress_port_vlan table and 3 rules for
53 * fwd_classifier table (IPv4, IPv6 and MPLS unicast) when
54 * the condition is VLAN + MAC.
55 */
56 @Test
57 public void testRouterMacAndVlanFilter() {
58 FilteringObjective filteringObjective = buildFilteringObjective(ROUTER_MAC);
59 PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
60
61 List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
62 List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
63
64 assertTrue(groupsInstalled.isEmpty());
65
66 // in port vlan flow rule
67 FlowRule actualFlowRule = flowRulesInstalled.get(0);
Yi Tseng43ee7e82018-04-12 16:37:34 +080068 FlowRule flowRuleExpected =
69 buildExpectedVlanInPortRule(PORT_1,
70 VlanId.NONE,
71 VLAN_100,
72 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN);
Yi Tseng0b809722017-11-03 10:23:26 -070073 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
74
75 // forwarding classifier ipv4
76 actualFlowRule = flowRulesInstalled.get(1);
77 flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
78 ROUTER_MAC,
79 Ethernet.TYPE_IPV4,
80 FWD_IPV4_UNICAST);
81 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
82
83 // forwarding classifier ipv6
84 actualFlowRule = flowRulesInstalled.get(2);
85 flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
86 ROUTER_MAC,
87 Ethernet.TYPE_IPV6,
88 FWD_IPV6_UNICAST);
89 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
90
91 // forwarding classifier mpls
92 actualFlowRule = flowRulesInstalled.get(3);
93 flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
94 ROUTER_MAC,
95 Ethernet.MPLS_UNICAST,
96 FWD_MPLS);
97 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
98 }
99
100 /**
101 * Creates one rule for ingress_port_vlan table and one rule for
102 * fwd_classifier table (IPv4 multicast) when the condition is ipv4
103 * multicast mac address.
104 */
105 @Test
106 public void testIpv4MulticastFwdClass() {
107 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
108 .pushVlan()
109 .setVlanId(VLAN_100)
110 .build();
111 FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
112 .permit()
113 .withPriority(PRIORITY)
114 .withKey(Criteria.matchInPort(PORT_1))
115 .addCondition(Criteria.matchEthDst(MacAddress.IPV4_MULTICAST))
116 .addCondition(Criteria.matchVlanId(VlanId.NONE))
117 .withMeta(treatment)
118 .fromApp(APP_ID)
119 .makePermanent()
120 .add();
121 PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
122 List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
123 List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
124
125 assertTrue(groupsInstalled.isEmpty());
126
127 // in port vlan flow rule
128 FlowRule actualFlowRule = flowRulesInstalled.get(0);
Yi Tseng43ee7e82018-04-12 16:37:34 +0800129 FlowRule flowRuleExpected =
130 buildExpectedVlanInPortRule(PORT_1,
131 VlanId.NONE,
132 VLAN_100,
133 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN);
Yi Tseng0b809722017-11-03 10:23:26 -0700134 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
135
136 // forwarding classifier
137 actualFlowRule = flowRulesInstalled.get(1);
138 flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
139 MacAddress.IPV4_MULTICAST,
140 Ethernet.TYPE_IPV4,
141 FWD_IPV4_MULTICAST);
142 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
143 }
144
145 /**
146 * Creates one rule for ingress_port_vlan table and one rule for
147 * fwd_classifier table (IPv6 multicast) when the condition is ipv6
148 * multicast mac address.
149 */
150 @Test
151 public void testIpv6MulticastFwdClass() {
152 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
153 .pushVlan()
154 .setVlanId(VLAN_100)
155 .build();
156 FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
157 .permit()
158 .withPriority(PRIORITY)
159 .withKey(Criteria.matchInPort(PORT_1))
160 .addCondition(Criteria.matchEthDst(MacAddress.IPV6_MULTICAST))
161 .addCondition(Criteria.matchVlanId(VlanId.NONE))
162 .withMeta(treatment)
163 .fromApp(APP_ID)
164 .makePermanent()
165 .add();
166 PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
167 List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
168 List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
169
170 assertTrue(groupsInstalled.isEmpty());
171
172 // in port vlan flow rule
173 FlowRule actualFlowRule = flowRulesInstalled.get(0);
Yi Tseng43ee7e82018-04-12 16:37:34 +0800174 FlowRule flowRuleExpected =
175 buildExpectedVlanInPortRule(PORT_1,
176 VlanId.NONE,
177 VLAN_100,
178 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN);
Yi Tseng0b809722017-11-03 10:23:26 -0700179 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
180
181 // forwarding classifier
182 actualFlowRule = flowRulesInstalled.get(1);
183 flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
184 MacAddress.IPV6_MULTICAST,
185 Ethernet.TYPE_IPV6,
186 FWD_IPV6_MULTICAST);
187 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
188 }
189
190 /**
191 * Creates only one rule for ingress_port_vlan table if there is no condition
192 * of destination mac address.
193 * The packet will be handled by bridging table by default.
194 */
195 @Test
196 public void testFwdBridging() {
197 FilteringObjective filteringObjective = buildFilteringObjective(null);
198 PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
199 List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
200 List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
201
202 assertTrue(groupsInstalled.isEmpty());
203
204 // in port vlan flow rule
205 FlowRule actualFlowRule = flowRulesInstalled.get(0);
Yi Tseng43ee7e82018-04-12 16:37:34 +0800206 FlowRule flowRuleExpected =
207 buildExpectedVlanInPortRule(PORT_1,
208 VlanId.NONE,
209 VLAN_100,
210 FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN);
Yi Tseng0b809722017-11-03 10:23:26 -0700211 assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
212
213 // No rules in forwarding classifier, will do default action: set fwd type to bridging
214 }
215
216 /**
217 * We supports only PERMIT type of filtering objective.
218 */
219 @Test
220 public void testUnsupportedObjective() {
221 FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
222 .deny()
223 .withKey(Criteria.matchInPort(PORT_1))
224 .addCondition(Criteria.matchVlanId(VLAN_100))
225 .fromApp(APP_ID)
226 .makePermanent()
227 .add();
228
229 PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
230 pipeliner.pipelinerFilter.filter(filteringObjective);
231
232 List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
233 List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
234
235 assertTrue(flowRulesInstalled.isEmpty());
236 assertTrue(groupsInstalled.isEmpty());
237
238 assertTrue(result.error().isPresent());
239 ObjectiveError error = result.error().get();
240 assertEquals(ObjectiveError.UNSUPPORTED, error);
241 }
242
243 /**
244 * Incorrect filtering key or filtering conditions test.
245 */
246 @Test
247 public void badParamTest() {
248 // Filtering objective should contains filtering key
249 FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
250 .permit()
251 .addCondition(Criteria.matchVlanId(VLAN_100))
252 .fromApp(APP_ID)
253 .makePermanent()
254 .add();
255
256 PipelinerTranslationResult result = pipeliner.pipelinerFilter.filter(filteringObjective);
257 pipeliner.pipelinerFilter.filter(filteringObjective);
258
259 assertTrue(result.error().isPresent());
260 ObjectiveError error = result.error().get();
261 assertEquals(ObjectiveError.BADPARAMS, error);
262
263 // Filtering objective should use in_port as key
264 filteringObjective = DefaultFilteringObjective.builder()
265 .permit()
266 .withKey(Criteria.matchEthDst(ROUTER_MAC))
267 .addCondition(Criteria.matchVlanId(VLAN_100))
268 .withMeta(DefaultTrafficTreatment.emptyTreatment())
269 .fromApp(APP_ID)
270 .makePermanent()
271 .add();
272
273 result = pipeliner.pipelinerFilter.filter(filteringObjective);
274 pipeliner.pipelinerFilter.filter(filteringObjective);
275
276 assertTrue(result.error().isPresent());
277 error = result.error().get();
278 assertEquals(ObjectiveError.BADPARAMS, error);
279 }
280
281 /* Utilities */
282
283 private FilteringObjective buildFilteringObjective(MacAddress dstMac) {
284 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
285 .pushVlan()
286 .setVlanId(VLAN_100)
287 .build();
288 DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder()
289 .permit()
290 .withPriority(PRIORITY)
291 .withKey(Criteria.matchInPort(PORT_1));
292 if (dstMac != null) {
293 builder.addCondition(Criteria.matchEthDst(dstMac));
294 }
295
296 builder.addCondition(Criteria.matchVlanId(VlanId.NONE))
297 .withMeta(treatment)
298 .fromApp(APP_ID)
299 .makePermanent();
300 return builder.add();
301 }
302
303 private FlowRule buildExpectedVlanInPortRule(PortNumber inPort, VlanId vlanId,
304 VlanId internalVlan,
305 TableId tableId) {
306
307 TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
308 .matchInPort(inPort);
309 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
310 if (vlanId == null || vlanId.equals(VlanId.NONE)) {
311 selector.matchPi(VLAN_INVALID);
312 treatment.pushVlan();
313 treatment.setVlanId(internalVlan);
314 } else {
315 selector.matchPi(VLAN_VALID);
316 selector.matchVlanId(vlanId);
317 }
318
319 return DefaultFlowRule.builder()
320 .withPriority(PRIORITY)
321 .withSelector(selector.build())
322 .withTreatment(treatment.build())
323 .fromApp(APP_ID)
324 .forDevice(DEVICE_ID)
325 .makePermanent()
326 .forTable(tableId)
327 .build();
328 }
329
330 private FlowRule buildExpectedFwdClassifierRule(PortNumber inPort,
331 MacAddress dstMac,
332 short ethType,
333 byte fwdClass) {
334 TrafficSelector selector = DefaultTrafficSelector.builder()
335 .matchEthDst(dstMac)
336 .matchInPort(inPort)
337 .matchEthType(ethType)
338 .build();
Yi Tseng43ee7e82018-04-12 16:37:34 +0800339 PiActionParam classParam = new PiActionParam(FabricConstants.FWD_TYPE,
Yi Tseng0b809722017-11-03 10:23:26 -0700340 ImmutableByteSequence.copyFrom(fwdClass));
341 PiAction fwdClassifierAction = PiAction.builder()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800342 .withId(FabricConstants.FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE)
Yi Tseng0b809722017-11-03 10:23:26 -0700343 .withParameter(classParam)
344 .build();
345 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
346 .piTableAction(fwdClassifierAction)
347 .build();
348
349 return DefaultFlowRule.builder()
350 .withPriority(PRIORITY)
351 .withSelector(selector)
352 .withTreatment(treatment)
353 .fromApp(APP_ID)
354 .forDevice(DEVICE_ID)
355 .makePermanent()
Yi Tseng43ee7e82018-04-12 16:37:34 +0800356 .forTable(FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER)
Yi Tseng0b809722017-11-03 10:23:26 -0700357 .build();
358 }
359}