Committed by
Gerrit Code Review
added support for multicast in olt pipeline
Change-Id: I25c6ab18d23035094851b0800f719f28e210d403
Showing
1 changed file
with
186 additions
and
60 deletions
... | @@ -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 | } | ... | ... |
-
Please register or login to post a comment