alshabib
Committed by Gerrit Code Review

added support for multicast in olt pipeline

Change-Id: I25c6ab18d23035094851b0800f719f28e210d403
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
15 */ 15 */
16 package org.onosproject.driver.pipeline; 16 package org.onosproject.driver.pipeline;
17 17
18 +import com.google.common.cache.Cache;
19 +import com.google.common.cache.CacheBuilder;
20 +import com.google.common.cache.RemovalCause;
21 +import com.google.common.cache.RemovalNotification;
18 import com.google.common.collect.Lists; 22 import com.google.common.collect.Lists;
19 import org.apache.commons.lang3.tuple.ImmutablePair; 23 import org.apache.commons.lang3.tuple.ImmutablePair;
20 import org.apache.commons.lang3.tuple.Pair; 24 import org.apache.commons.lang3.tuple.Pair;
...@@ -22,20 +26,14 @@ import org.onlab.osgi.ServiceDirectory; ...@@ -22,20 +26,14 @@ import org.onlab.osgi.ServiceDirectory;
22 import org.onlab.packet.EthType; 26 import org.onlab.packet.EthType;
23 import org.onlab.packet.IPv4; 27 import org.onlab.packet.IPv4;
24 import org.onlab.packet.VlanId; 28 import org.onlab.packet.VlanId;
29 +import org.onlab.util.KryoNamespace;
25 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
26 import org.onosproject.core.CoreService; 31 import org.onosproject.core.CoreService;
27 -import org.onosproject.net.DefaultAnnotations;
28 -import org.onosproject.net.Device;
29 import org.onosproject.net.DeviceId; 32 import org.onosproject.net.DeviceId;
30 -import org.onosproject.net.MastershipRole;
31 import org.onosproject.net.PortNumber; 33 import org.onosproject.net.PortNumber;
34 +import org.onosproject.net.behaviour.NextGroup;
32 import org.onosproject.net.behaviour.Pipeliner; 35 import org.onosproject.net.behaviour.Pipeliner;
33 import org.onosproject.net.behaviour.PipelinerContext; 36 import org.onosproject.net.behaviour.PipelinerContext;
34 -import org.onosproject.net.device.DefaultDeviceDescription;
35 -import org.onosproject.net.device.DeviceDescription;
36 -import org.onosproject.net.device.DeviceProvider;
37 -import org.onosproject.net.device.DeviceProviderRegistry;
38 -import org.onosproject.net.device.DeviceService;
39 import org.onosproject.net.driver.AbstractHandlerBehaviour; 37 import org.onosproject.net.driver.AbstractHandlerBehaviour;
40 import org.onosproject.net.flow.DefaultFlowRule; 38 import org.onosproject.net.flow.DefaultFlowRule;
41 import org.onosproject.net.flow.DefaultTrafficSelector; 39 import org.onosproject.net.flow.DefaultTrafficSelector;
...@@ -56,20 +54,32 @@ import org.onosproject.net.flow.instructions.Instruction; ...@@ -56,20 +54,32 @@ import org.onosproject.net.flow.instructions.Instruction;
56 import org.onosproject.net.flow.instructions.Instructions; 54 import org.onosproject.net.flow.instructions.Instructions;
57 import org.onosproject.net.flow.instructions.L2ModificationInstruction; 55 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
58 import org.onosproject.net.flowobjective.FilteringObjective; 56 import org.onosproject.net.flowobjective.FilteringObjective;
57 +import org.onosproject.net.flowobjective.FlowObjectiveStore;
59 import org.onosproject.net.flowobjective.ForwardingObjective; 58 import org.onosproject.net.flowobjective.ForwardingObjective;
60 import org.onosproject.net.flowobjective.NextObjective; 59 import org.onosproject.net.flowobjective.NextObjective;
61 import org.onosproject.net.flowobjective.Objective; 60 import org.onosproject.net.flowobjective.Objective;
62 import org.onosproject.net.flowobjective.ObjectiveError; 61 import org.onosproject.net.flowobjective.ObjectiveError;
63 -import org.onosproject.net.provider.AbstractProvider; 62 +import org.onosproject.net.group.DefaultGroupBucket;
64 -import org.onosproject.net.provider.ProviderId; 63 +import org.onosproject.net.group.DefaultGroupDescription;
64 +import org.onosproject.net.group.DefaultGroupKey;
65 +import org.onosproject.net.group.Group;
66 +import org.onosproject.net.group.GroupBucket;
67 +import org.onosproject.net.group.GroupBuckets;
68 +import org.onosproject.net.group.GroupDescription;
69 +import org.onosproject.net.group.GroupEvent;
70 +import org.onosproject.net.group.GroupKey;
71 +import org.onosproject.net.group.GroupListener;
72 +import org.onosproject.net.group.GroupService;
73 +import org.onosproject.store.serializers.KryoNamespaces;
65 import org.slf4j.Logger; 74 import org.slf4j.Logger;
66 75
67 import java.util.Collection; 76 import java.util.Collection;
77 +import java.util.Collections;
68 import java.util.List; 78 import java.util.List;
69 import java.util.Optional; 79 import java.util.Optional;
80 +import java.util.concurrent.TimeUnit;
70 import java.util.stream.Collectors; 81 import java.util.stream.Collectors;
71 82
72 -import static com.google.common.base.Preconditions.checkNotNull;
73 import static org.slf4j.LoggerFactory.getLogger; 83 import static org.slf4j.LoggerFactory.getLogger;
74 84
75 /** 85 /**
...@@ -79,35 +89,55 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -79,35 +89,55 @@ import static org.slf4j.LoggerFactory.getLogger;
79 public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { 89 public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
80 90
81 private static final Integer QQ_TABLE = 1; 91 private static final Integer QQ_TABLE = 1;
92 + private static final short MCAST_VLAN = 4000;
82 private final Logger log = getLogger(getClass()); 93 private final Logger log = getLogger(getClass());
83 94
84 - static final ProviderId PID = new ProviderId("olt", "org.onosproject.olt", true);
85 -
86 - static final String DEVICE = "isAccess";
87 - static final String OLT = "true";
88 -
89 private ServiceDirectory serviceDirectory; 95 private ServiceDirectory serviceDirectory;
90 private FlowRuleService flowRuleService; 96 private FlowRuleService flowRuleService;
91 - private DeviceId deviceId; 97 + private GroupService groupService;
92 private CoreService coreService; 98 private CoreService coreService;
93 99
100 + private DeviceId deviceId;
94 private ApplicationId appId; 101 private ApplicationId appId;
95 102
96 - private DeviceProvider provider = new AnnotationProvider(); 103 + protected FlowObjectiveStore flowObjectiveStore;
104 +
105 + private Cache<GroupKey, NextObjective> pendingGroups;
106 +
107 + protected static KryoNamespace appKryo = new KryoNamespace.Builder()
108 + .register(KryoNamespaces.API)
109 + .register(GroupKey.class)
110 + .register(DefaultGroupKey.class)
111 + .register(OLTPipelineGroup.class)
112 + .register(byte[].class)
113 + .build();
97 114
98 @Override 115 @Override
99 public void init(DeviceId deviceId, PipelinerContext context) { 116 public void init(DeviceId deviceId, PipelinerContext context) {
100 log.debug("Initiate OLT pipeline"); 117 log.debug("Initiate OLT pipeline");
101 this.serviceDirectory = context.directory(); 118 this.serviceDirectory = context.directory();
102 this.deviceId = deviceId; 119 this.deviceId = deviceId;
103 - DeviceProviderRegistry registry = 120 +
104 - serviceDirectory.get(DeviceProviderRegistry.class);
105 flowRuleService = serviceDirectory.get(FlowRuleService.class); 121 flowRuleService = serviceDirectory.get(FlowRuleService.class);
106 coreService = serviceDirectory.get(CoreService.class); 122 coreService = serviceDirectory.get(CoreService.class);
123 + groupService = serviceDirectory.get(GroupService.class);
124 + flowObjectiveStore = context.store();
125 +
107 126
108 appId = coreService.registerApplication( 127 appId = coreService.registerApplication(
109 "org.onosproject.driver.OLTPipeline"); 128 "org.onosproject.driver.OLTPipeline");
110 129
130 +
131 + pendingGroups = CacheBuilder.newBuilder()
132 + .expireAfterWrite(20, TimeUnit.SECONDS)
133 + .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
134 + if (notification.getCause() == RemovalCause.EXPIRED) {
135 + fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
136 + }
137 + }).build();
138 +
139 + groupService.addListener(new InnerGroupListener());
140 +
111 } 141 }
112 142
113 @Override 143 @Override
...@@ -164,6 +194,12 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { ...@@ -164,6 +194,12 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
164 194
165 @Override 195 @Override
166 public void forward(ForwardingObjective fwd) { 196 public void forward(ForwardingObjective fwd) {
197 +
198 + if (checkForMulticast(fwd)) {
199 + processMulticastRule(fwd);
200 + return;
201 + }
202 +
167 TrafficTreatment treatment = fwd.treatment(); 203 TrafficTreatment treatment = fwd.treatment();
168 204
169 List<Instruction> instructions = treatment.allInstructions(); 205 List<Instruction> instructions = treatment.allInstructions();
...@@ -198,9 +234,113 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { ...@@ -198,9 +234,113 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
198 234
199 } 235 }
200 236
237 +
201 @Override 238 @Override
202 public void next(NextObjective nextObjective) { 239 public void next(NextObjective nextObjective) {
203 - throw new UnsupportedOperationException("OLT does not next hop."); 240 + if (nextObjective.type() != NextObjective.Type.BROADCAST) {
241 + log.error("OLT only supports broadcast groups.");
242 + fail(nextObjective, ObjectiveError.BADPARAMS);
243 + }
244 +
245 + if (nextObjective.next().size() != 1) {
246 + log.error("OLT only supports singleton broadcast groups.");
247 + fail(nextObjective, ObjectiveError.BADPARAMS);
248 + }
249 +
250 + TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
251 +
252 +
253 + GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
254 + GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
255 +
256 + GroupDescription groupDesc =
257 + new DefaultGroupDescription(deviceId,
258 + GroupDescription.Type.ALL,
259 + new GroupBuckets(Collections.singletonList(bucket)),
260 + key,
261 + null,
262 + nextObjective.appId());
263 +
264 + pendingGroups.put(key, nextObjective);
265 +
266 + switch (nextObjective.op()) {
267 + case ADD:
268 + groupService.addGroup(groupDesc);
269 + break;
270 + case REMOVE:
271 + groupService.removeGroup(deviceId, key, nextObjective.appId());
272 + break;
273 + case ADD_TO_EXISTING:
274 + case REMOVE_FROM_EXISTING:
275 + //TODO: handle addition to group when caller signals it.
276 + break;
277 + default:
278 + log.warn("Unknown next objective operation: {}", nextObjective.op());
279 + }
280 +
281 +
282 + }
283 +
284 + private void processMulticastRule(ForwardingObjective fwd) {
285 + if (fwd.nextId() == null) {
286 + log.error("Multicast objective does not have a next id");
287 + fail(fwd, ObjectiveError.BADPARAMS);
288 + }
289 +
290 + OLTPipelineGroup next = getGroupForNextObjective(fwd.nextId());
291 +
292 + if (next == null) {
293 + log.error("Group for forwarding objective missing: {}", fwd);
294 + fail(fwd, ObjectiveError.GROUPMISSING);
295 + }
296 +
297 + Group group = groupService.getGroup(deviceId, next.key());
298 + TrafficTreatment treatment =
299 + buildTreatment(Instructions.createGroup(group.id()));
300 +
301 + FlowRule rule = DefaultFlowRule.builder()
302 + .forDevice(deviceId)
303 + .forTable(0)
304 + .fromApp(fwd.appId())
305 + .makePermanent()
306 + .withPriority(fwd.priority())
307 + .withSelector(fwd.selector())
308 + .withTreatment(treatment)
309 + .build();
310 +
311 + FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
312 + switch (fwd.op()) {
313 +
314 + case ADD:
315 + builder.add(rule);
316 + break;
317 + case REMOVE:
318 + builder.remove(rule);
319 + break;
320 + case ADD_TO_EXISTING:
321 + case REMOVE_FROM_EXISTING:
322 + break;
323 + default:
324 + log.warn("Unknown forwarding operation: {}", fwd.op());
325 + }
326 +
327 + applyFlowRules(builder, fwd);
328 +
329 + }
330 +
331 + private boolean checkForMulticast(ForwardingObjective fwd) {
332 +
333 + VlanIdCriterion vlan = (VlanIdCriterion) filterForCriterion(fwd.selector().criteria(),
334 + Criterion.Type.VLAN_VID);
335 +
336 + return (vlan != null && vlan.vlanId().equals(VlanId.vlanId(MCAST_VLAN)));
337 +
338 + }
339 +
340 + private OLTPipelineGroup getGroupForNextObjective(Integer nextId) {
341 + NextGroup next = flowObjectiveStore.getNextGroup(nextId);
342 + return (OLTPipelineGroup) appKryo.deserialize(next.data());
343 +
204 } 344 }
205 345
206 private void installDownstreamRules(ForwardingObjective fwd) { 346 private void installDownstreamRules(ForwardingObjective fwd) {
...@@ -338,7 +478,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { ...@@ -338,7 +478,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
338 478
339 479
340 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions, 480 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
341 - L2ModificationInstruction.L2SubType type) { 481 + L2ModificationInstruction.L2SubType type) {
342 482
343 List<Instruction> vlanPushs = findL2Instructions( 483 List<Instruction> vlanPushs = findL2Instructions(
344 type, 484 type,
...@@ -494,53 +634,39 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner { ...@@ -494,53 +634,39 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
494 } 634 }
495 } 635 }
496 636
497 - /** 637 +
498 - * Build a device description. 638 + private class InnerGroupListener implements GroupListener {
499 - * 639 + @Override
500 - * @param deviceId a deviceId 640 + public void event(GroupEvent event) {
501 - * @param key the key of the annotation 641 + if (event.type() == GroupEvent.Type.GROUP_ADDED) {
502 - * @param value the value for the annotation 642 + GroupKey key = event.subject().appCookie();
503 - * @return a device description 643 +
504 - */ 644 + NextObjective obj = pendingGroups.getIfPresent(key);
505 - private DeviceDescription description(DeviceId deviceId, String key, String value) { 645 + if (obj != null) {
506 - DeviceService deviceService = serviceDirectory.get(DeviceService.class); 646 + flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
507 - Device device = deviceService.getDevice(deviceId); 647 + pass(obj);
508 - 648 + pendingGroups.invalidate(key);
509 - checkNotNull(device, "Device not found in device service."); 649 + }
510 - 650 + }
511 - DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
512 - if (value != null) {
513 - builder.set(key, value);
514 - } else {
515 - builder.remove(key);
516 } 651 }
517 - return new DefaultDeviceDescription(device.id().uri(), device.type(),
518 - device.manufacturer(), device.hwVersion(),
519 - device.swVersion(), device.serialNumber(),
520 - device.chassisId(), builder.build());
521 } 652 }
522 653
523 - /** 654 + private static class OLTPipelineGroup implements NextGroup {
524 - * Simple ancillary provider used to annotate device.
525 - */
526 - private static final class AnnotationProvider
527 - extends AbstractProvider implements DeviceProvider {
528 - private AnnotationProvider() {
529 - super(PID);
530 - }
531 655
532 - @Override 656 + private final GroupKey key;
533 - public void triggerProbe(DeviceId deviceId) { 657 +
658 + public OLTPipelineGroup(GroupKey key) {
659 + this.key = key;
534 } 660 }
535 661
536 - @Override 662 + public GroupKey key() {
537 - public void roleChanged(DeviceId deviceId, MastershipRole newRole) { 663 + return key;
538 } 664 }
539 665
540 @Override 666 @Override
541 - public boolean isReachable(DeviceId deviceId) { 667 + public byte[] data() {
542 - return false; 668 + return appKryo.serialize(key);
543 } 669 }
544 - }
545 670
671 + }
546 } 672 }
......