alshabib
Committed by Gerrit Code Review

implementing q-in-q support

implementing filtering objectives for punting rules

Change-Id: I73945df31c4d5aa40ab4b07fc6818edd083178fb
...@@ -15,8 +15,13 @@ ...@@ -15,8 +15,13 @@
15 */ 15 */
16 package org.onosproject.driver.pipeline; 16 package org.onosproject.driver.pipeline;
17 17
18 +import com.google.common.collect.Lists;
19 +import org.apache.commons.lang3.tuple.ImmutablePair;
20 +import org.apache.commons.lang3.tuple.Pair;
18 import org.onlab.osgi.ServiceDirectory; 21 import org.onlab.osgi.ServiceDirectory;
19 import org.onlab.packet.EthType; 22 import org.onlab.packet.EthType;
23 +import org.onlab.packet.IPv4;
24 +import org.onlab.packet.VlanId;
20 import org.onosproject.core.ApplicationId; 25 import org.onosproject.core.ApplicationId;
21 import org.onosproject.core.CoreService; 26 import org.onosproject.core.CoreService;
22 import org.onosproject.net.DefaultAnnotations; 27 import org.onosproject.net.DefaultAnnotations;
...@@ -41,24 +46,38 @@ import org.onosproject.net.flow.FlowRuleOperationsContext; ...@@ -41,24 +46,38 @@ import org.onosproject.net.flow.FlowRuleOperationsContext;
41 import org.onosproject.net.flow.FlowRuleService; 46 import org.onosproject.net.flow.FlowRuleService;
42 import org.onosproject.net.flow.TrafficSelector; 47 import org.onosproject.net.flow.TrafficSelector;
43 import org.onosproject.net.flow.TrafficTreatment; 48 import org.onosproject.net.flow.TrafficTreatment;
49 +import org.onosproject.net.flow.criteria.Criteria;
50 +import org.onosproject.net.flow.criteria.Criterion;
51 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
52 +import org.onosproject.net.flow.criteria.IPProtocolCriterion;
53 +import org.onosproject.net.flow.criteria.PortCriterion;
54 +import org.onosproject.net.flow.instructions.Instruction;
44 import org.onosproject.net.flow.instructions.Instructions; 55 import org.onosproject.net.flow.instructions.Instructions;
56 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
45 import org.onosproject.net.flowobjective.FilteringObjective; 57 import org.onosproject.net.flowobjective.FilteringObjective;
46 import org.onosproject.net.flowobjective.ForwardingObjective; 58 import org.onosproject.net.flowobjective.ForwardingObjective;
47 import org.onosproject.net.flowobjective.NextObjective; 59 import org.onosproject.net.flowobjective.NextObjective;
60 +import org.onosproject.net.flowobjective.Objective;
48 import org.onosproject.net.flowobjective.ObjectiveError; 61 import org.onosproject.net.flowobjective.ObjectiveError;
49 -import org.onosproject.net.packet.PacketPriority;
50 import org.onosproject.net.provider.AbstractProvider; 62 import org.onosproject.net.provider.AbstractProvider;
51 import org.onosproject.net.provider.ProviderId; 63 import org.onosproject.net.provider.ProviderId;
52 import org.slf4j.Logger; 64 import org.slf4j.Logger;
53 65
66 +import java.util.Collection;
67 +import java.util.List;
68 +import java.util.Optional;
69 +import java.util.stream.Collectors;
70 +
54 import static com.google.common.base.Preconditions.checkNotNull; 71 import static com.google.common.base.Preconditions.checkNotNull;
55 import static org.slf4j.LoggerFactory.getLogger; 72 import static org.slf4j.LoggerFactory.getLogger;
56 73
57 /** 74 /**
58 * Pipeliner for OLT device. 75 * Pipeliner for OLT device.
59 */ 76 */
77 +
60 public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { 78 public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
61 79
80 + private static final Integer QQ_TABLE = 1;
62 private final Logger log = getLogger(getClass()); 81 private final Logger log = getLogger(getClass());
63 82
64 static final ProviderId PID = new ProviderId("olt", "org.onosproject.olt", true); 83 static final ProviderId PID = new ProviderId("olt", "org.onosproject.olt", true);
...@@ -75,9 +94,9 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { ...@@ -75,9 +94,9 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
75 94
76 private DeviceProvider provider = new AnnotationProvider(); 95 private DeviceProvider provider = new AnnotationProvider();
77 96
78 -
79 @Override 97 @Override
80 public void init(DeviceId deviceId, PipelinerContext context) { 98 public void init(DeviceId deviceId, PipelinerContext context) {
99 + log.debug("Initiate OLT pipeline");
81 this.serviceDirectory = context.directory(); 100 this.serviceDirectory = context.directory();
82 this.deviceId = deviceId; 101 this.deviceId = deviceId;
83 DeviceProviderRegistry registry = 102 DeviceProviderRegistry registry =
...@@ -85,105 +104,375 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { ...@@ -85,105 +104,375 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
85 flowRuleService = serviceDirectory.get(FlowRuleService.class); 104 flowRuleService = serviceDirectory.get(FlowRuleService.class);
86 coreService = serviceDirectory.get(CoreService.class); 105 coreService = serviceDirectory.get(CoreService.class);
87 106
88 - /*try {
89 - DeviceProviderService providerService = registry.register(provider);
90 - providerService.deviceConnected(deviceId,
91 - description(deviceId, DEVICE, OLT));
92 - } finally {
93 - registry.unregister(provider);
94 - }*/
95 -
96 appId = coreService.registerApplication( 107 appId = coreService.registerApplication(
97 "org.onosproject.driver.OLTPipeline"); 108 "org.onosproject.driver.OLTPipeline");
98 109
99 - TrafficSelector selector = DefaultTrafficSelector.builder() 110 + }
100 - .matchEthType(EthType.EtherType.EAPOL.ethType().toShort())
101 - .build();
102 111
103 - TrafficTreatment treatment = DefaultTrafficTreatment.builder() 112 + @Override
104 - .punt() 113 + public void filter(FilteringObjective filter) {
105 - .build(); 114 + Instructions.OutputInstruction output;
106 115
107 - FlowRule flowRule = new DefaultFlowRule(deviceId, selector, treatment, 116 + if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
108 - PacketPriority.CONTROL.priorityValue(), 117 + output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
109 - appId, 0, true, null); 118 + .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
119 + .limit(1)
120 + .findFirst().get();
110 121
111 - //flowRuleService.applyFlowRules(flowRule); 122 + if (output != null && !output.port().equals(PortNumber.CONTROLLER)) {
123 + fail(filter, ObjectiveError.UNSUPPORTED);
124 + return;
125 + }
126 + } else {
127 + fail(filter, ObjectiveError.BADPARAMS);
128 + return;
112 } 129 }
113 130
114 - @Override 131 + if (filter.key().type() != Criterion.Type.IN_PORT) {
115 - public void filter(FilteringObjective filter) { 132 + fail(filter, ObjectiveError.BADPARAMS);
116 - throw new UnsupportedOperationException("OLT does not filter."); 133 + return;
117 } 134 }
118 135
136 + EthTypeCriterion ethType = (EthTypeCriterion)
137 + filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
138 +
139 + if (ethType == null) {
140 + fail(filter, ObjectiveError.BADPARAMS);
141 + return;
142 + }
143 +
144 + if (ethType.ethType().equals(EthType.EtherType.EAPOL)) {
145 + provisionEapol(filter, ethType, output);
146 + } else if (ethType.ethType().equals(EthType.EtherType.IPV4)) {
147 + IPProtocolCriterion ipProto = (IPProtocolCriterion)
148 + filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
149 + if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
150 + provisionIGMP(filter, ethType, ipProto, output);
151 + }
152 + } else {
153 + fail(filter, ObjectiveError.UNSUPPORTED);
154 + }
155 +
156 + }
157 +
158 +
119 @Override 159 @Override
120 public void forward(ForwardingObjective fwd) { 160 public void forward(ForwardingObjective fwd) {
121 - FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); 161 + TrafficTreatment treatment = fwd.treatment();
162 +
163 + List<Instruction> instructions = treatment.allInstructions();
122 164
123 - if (fwd.flag() != ForwardingObjective.Flag.VERSATILE) { 165 + Optional<Instruction> vlanIntruction = instructions.stream()
124 - throw new UnsupportedOperationException( 166 + .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
125 - "Only VERSATILE is supported."); 167 + .filter(i -> ((L2ModificationInstruction) i).subtype() ==
168 + L2ModificationInstruction.L2SubType.VLAN_PUSH ||
169 + ((L2ModificationInstruction) i).subtype() ==
170 + L2ModificationInstruction.L2SubType.VLAN_POP)
171 + .findAny();
172 +
173 + if (!vlanIntruction.isPresent()) {
174 + fail(fwd, ObjectiveError.BADPARAMS);
175 + return;
126 } 176 }
127 177
128 - boolean isPunt = fwd.treatment().immediate().stream().anyMatch(i -> { 178 + L2ModificationInstruction vlanIns =
129 - if (i instanceof Instructions.OutputInstruction) { 179 + (L2ModificationInstruction) vlanIntruction.get();
130 - Instructions.OutputInstruction out = (Instructions.OutputInstruction) i; 180 +
131 - return out.port().equals(PortNumber.CONTROLLER); 181 + if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
182 + installUpstreamRules(fwd);
183 + } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
184 + installDownstreamRules(fwd);
185 + } else {
186 + log.error("Unknown OLT operation: {}", fwd);
187 + fail(fwd, ObjectiveError.UNSUPPORTED);
188 + return;
132 } 189 }
133 - return false;
134 - });
135 190
136 - if (isPunt) { 191 + pass(fwd);
192 +
193 + }
194 +
195 + @Override
196 + public void next(NextObjective nextObjective) {
197 + throw new UnsupportedOperationException("OLT does not next hop.");
198 + }
199 +
200 + private void installDownstreamRules(ForwardingObjective fwd) {
201 + List<Pair<Instruction, Instruction>> vlanOps =
202 + vlanOps(fwd,
203 + L2ModificationInstruction.L2SubType.VLAN_POP);
204 +
205 + if (vlanOps == null) {
137 return; 206 return;
138 } 207 }
139 208
140 - TrafficSelector selector = fwd.selector(); 209 + Instruction output = fetchOutput(fwd, "downstream");
141 - TrafficTreatment treatment = fwd.treatment(); 210 +
211 + if (output == null) {
212 + return;
213 + }
214 +
215 + Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
216 +
217 + FlowRule.Builder inner = DefaultFlowRule.builder()
218 + .forDevice(deviceId)
219 + .fromApp(appId)
220 + .makePermanent()
221 + .withPriority(fwd.priority())
222 + .withSelector(fwd.selector())
223 + .withTreatment(buildTreatment(popAndRewrite.getLeft(),
224 + Instructions.transition(QQ_TABLE)));
225 + PortCriterion inPort = (PortCriterion)
226 + fwd.selector().getCriterion(Criterion.Type.IN_PORT);
227 +
228 + FlowRule.Builder outer = DefaultFlowRule.builder()
229 + .forDevice(deviceId)
230 + .fromApp(appId)
231 + .forTable(QQ_TABLE)
232 + .makePermanent()
233 + .withPriority(fwd.priority())
234 + .withSelector(buildSelector(inPort))
235 + .withTreatment(buildTreatment(popAndRewrite.getRight(),
236 + output));
237 +
238 + applyRules(fwd, inner, outer);
239 +
240 + }
241 +
242 + private void installUpstreamRules(ForwardingObjective fwd) {
243 + List<Pair<Instruction, Instruction>> vlanOps =
244 + vlanOps(fwd,
245 + L2ModificationInstruction.L2SubType.VLAN_PUSH);
246 +
247 + if (vlanOps == null) {
248 + return;
249 + }
250 +
251 + Instruction output = fetchOutput(fwd, "upstream");
252 +
253 + if (output == null) {
254 + return;
255 + }
256 +
257 + Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
258 +
259 + Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
260 +
261 + FlowRule.Builder inner = DefaultFlowRule.builder()
262 + .forDevice(deviceId)
263 + .fromApp(appId)
264 + .makePermanent()
265 + .withPriority(fwd.priority())
266 + .withSelector(fwd.selector())
267 + .withTreatment(buildTreatment(innerPair.getRight(),
268 + Instructions.transition(QQ_TABLE)));
269 +
270 + PortCriterion inPort = (PortCriterion)
271 + fwd.selector().getCriterion(Criterion.Type.IN_PORT);
272 +
273 + VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
274 + innerPair.getRight()).vlanId();
142 275
143 - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() 276 + FlowRule.Builder outer = DefaultFlowRule.builder()
144 .forDevice(deviceId) 277 .forDevice(deviceId)
278 + .fromApp(appId)
279 + .forTable(QQ_TABLE)
280 + .makePermanent()
281 + .withPriority(fwd.priority())
282 + .withSelector(buildSelector(inPort,
283 + Criteria.matchVlanId(cVlanId)))
284 + .withTreatment(buildTreatment(outerPair.getLeft(),
285 + outerPair.getRight(),
286 + output));
287 +
288 + applyRules(fwd, inner, outer);
289 +
290 + }
291 +
292 + private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
293 + Instruction output = fwd.treatment().allInstructions().stream()
294 + .filter(i -> i.type() == Instruction.Type.OUTPUT)
295 + .findFirst().orElse(null);
296 +
297 + if (output == null) {
298 + log.error("OLT {} rule has no output", direction);
299 + fail(fwd, ObjectiveError.BADPARAMS);
300 + return null;
301 + }
302 + return output;
303 + }
304 +
305 + private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
306 + L2ModificationInstruction.L2SubType type) {
307 +
308 + List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
309 + fwd.treatment().allInstructions(), type);
310 +
311 + if (vlanOps == null) {
312 + String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
313 + ? "downstream" : "upstream";
314 + log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
315 + fail(fwd, ObjectiveError.BADPARAMS);
316 + return null;
317 + }
318 + return vlanOps;
319 + }
320 +
321 +
322 + private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
323 + L2ModificationInstruction.L2SubType type) {
324 +
325 + List<Instruction> vlanPushs = findL2Instructions(
326 + type,
327 + instructions);
328 + List<Instruction> vlanSets = findL2Instructions(
329 + L2ModificationInstruction.L2SubType.VLAN_ID,
330 + instructions);
331 +
332 + if (vlanPushs.size() != vlanSets.size()) {
333 + return null;
334 + }
335 +
336 + List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
337 +
338 + for (int i = 0; i < vlanPushs.size(); i++) {
339 + pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
340 + }
341 + return pairs;
342 + }
343 +
344 + private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
345 + List<Instruction> actions) {
346 + return actions.stream()
347 + .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
348 + .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
349 + .collect(Collectors.toList());
350 + }
351 +
352 + private void provisionEapol(FilteringObjective filter,
353 + EthTypeCriterion ethType,
354 + Instructions.OutputInstruction output) {
355 +
356 + TrafficSelector selector = buildSelector(filter.key(), ethType);
357 + TrafficTreatment treatment = buildTreatment(output);
358 + buildAndApplyRule(filter, selector, treatment);
359 +
360 + }
361 +
362 + private void provisionIGMP(FilteringObjective filter, EthTypeCriterion ethType,
363 + IPProtocolCriterion ipProto,
364 + Instructions.OutputInstruction output) {
365 + TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
366 + TrafficTreatment treatment = buildTreatment(output);
367 + buildAndApplyRule(filter, selector, treatment);
368 + }
369 +
370 + private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
371 + TrafficTreatment treatment) {
372 + FlowRule rule = DefaultFlowRule.builder()
373 + .forDevice(deviceId)
374 + .forTable(0)
375 + .fromApp(filter.appId())
376 + .makePermanent()
145 .withSelector(selector) 377 .withSelector(selector)
146 .withTreatment(treatment) 378 .withTreatment(treatment)
147 - .fromApp(fwd.appId()) 379 + .build();
148 - .withPriority(fwd.priority());
149 380
150 - if (fwd.permanent()) { 381 + FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
151 - ruleBuilder.makePermanent(); 382 +
152 - } else { 383 + switch (filter.type()) {
153 - ruleBuilder.makeTemporary(fwd.timeout()); 384 + case PERMIT:
385 + opsBuilder.add(rule);
386 + break;
387 + case DENY:
388 + opsBuilder.remove(rule);
389 + break;
390 + default:
391 + log.warn("Unknown filter type : {}", filter.type());
392 + fail(filter, ObjectiveError.UNSUPPORTED);
154 } 393 }
155 394
395 + applyFlowRules(opsBuilder, filter);
396 + }
397 +
398 + private void applyRules(ForwardingObjective fwd,
399 + FlowRule.Builder inner, FlowRule.Builder outer) {
400 + FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
156 switch (fwd.op()) { 401 switch (fwd.op()) {
157 case ADD: 402 case ADD:
158 - flowBuilder.add(ruleBuilder.build()); 403 + builder.add(inner.build()).add(outer.build());
159 break; 404 break;
160 case REMOVE: 405 case REMOVE:
161 - flowBuilder.remove(ruleBuilder.build()); 406 + builder.remove(inner.build()).remove(outer.build());
407 + break;
408 + case ADD_TO_EXISTING:
409 + break;
410 + case REMOVE_FROM_EXISTING:
162 break; 411 break;
163 default: 412 default:
164 - log.warn("Unknown operation {}", fwd.op()); 413 + log.warn("Unknown forwarding operation: {}", fwd.op());
414 + }
415 +
416 + applyFlowRules(builder, fwd);
165 } 417 }
166 418
167 - flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { 419 + private void applyFlowRules(FlowRuleOperations.Builder builder,
420 + Objective objective) {
421 + flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
168 @Override 422 @Override
169 public void onSuccess(FlowRuleOperations ops) { 423 public void onSuccess(FlowRuleOperations ops) {
170 - if (fwd.context().isPresent()) { 424 + pass(objective);
171 - fwd.context().get().onSuccess(fwd);
172 - }
173 } 425 }
174 426
175 @Override 427 @Override
176 public void onError(FlowRuleOperations ops) { 428 public void onError(FlowRuleOperations ops) {
177 - if (fwd.context().isPresent()) { 429 + fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
178 - fwd.context().get().onError(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
179 - }
180 } 430 }
181 })); 431 }));
182 } 432 }
183 433
184 - @Override 434 + private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
185 - public void next(NextObjective nextObjective) { 435 + return criteria.stream()
186 - throw new UnsupportedOperationException("OLT does not next hop."); 436 + .filter(c -> c.type().equals(Criterion.Type.ETH_TYPE))
437 + .limit(1)
438 + .findFirst().orElse(null);
439 + }
440 +
441 + private TrafficSelector buildSelector(Criterion... criteria) {
442 +
443 +
444 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
445 +
446 + for (Criterion c : criteria) {
447 + sBuilder.add(c);
448 + }
449 +
450 + return sBuilder.build();
451 + }
452 +
453 + private TrafficTreatment buildTreatment(Instruction... instructions) {
454 +
455 +
456 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
457 +
458 + for (Instruction i : instructions) {
459 + tBuilder.add(i);
460 + }
461 +
462 + return tBuilder.build();
463 + }
464 +
465 +
466 + private void fail(Objective obj, ObjectiveError error) {
467 + if (obj.context().isPresent()) {
468 + obj.context().get().onError(obj, error);
469 + }
470 + }
471 +
472 + private void pass(Objective obj) {
473 + if (obj.context().isPresent()) {
474 + obj.context().get().onSuccess(obj);
475 + }
187 } 476 }
188 477
189 /** 478 /**
......