Committed by
Gerrit Code Review
Flow Objective implementation
Provides an abstraction which isolates the application from any pipeline knowledge. By using the provided objectives applications can express their forwarding desires in a pipeline agnostic way. The objectives are then consumed by a driver for the specific device who converts them into the appropriate pipeline coherent flows. Change-Id: I74a68b4971c367c0cd5b7de9d877abdd117afa98
Showing
26 changed files
with
1133 additions
and
211 deletions
... | @@ -20,7 +20,6 @@ import com.google.common.collect.HashMultimap; | ... | @@ -20,7 +20,6 @@ import com.google.common.collect.HashMultimap; |
20 | import com.google.common.collect.Maps; | 20 | import com.google.common.collect.Maps; |
21 | import com.google.common.collect.Multimap; | 21 | import com.google.common.collect.Multimap; |
22 | import com.google.common.collect.Multiset; | 22 | import com.google.common.collect.Multiset; |
23 | - | ||
24 | import org.apache.felix.scr.annotations.Activate; | 23 | import org.apache.felix.scr.annotations.Activate; |
25 | import org.apache.felix.scr.annotations.Component; | 24 | import org.apache.felix.scr.annotations.Component; |
26 | import org.apache.felix.scr.annotations.Deactivate; | 25 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -28,35 +27,29 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -28,35 +27,29 @@ import org.apache.felix.scr.annotations.Reference; |
28 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 27 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
29 | import org.onlab.packet.Ethernet; | 28 | import org.onlab.packet.Ethernet; |
30 | import org.onlab.packet.Ip4Address; | 29 | import org.onlab.packet.Ip4Address; |
30 | +import org.onlab.packet.Ip4Prefix; | ||
31 | import org.onlab.packet.Ip6Address; | 31 | import org.onlab.packet.Ip6Address; |
32 | import org.onlab.packet.IpAddress; | 32 | import org.onlab.packet.IpAddress; |
33 | import org.onlab.packet.IpPrefix; | 33 | import org.onlab.packet.IpPrefix; |
34 | +import org.onlab.packet.MacAddress; | ||
34 | import org.onlab.util.KryoNamespace; | 35 | import org.onlab.util.KryoNamespace; |
35 | import org.onosproject.config.NetworkConfigService; | 36 | import org.onosproject.config.NetworkConfigService; |
36 | import org.onosproject.core.ApplicationId; | 37 | import org.onosproject.core.ApplicationId; |
37 | import org.onosproject.core.CoreService; | 38 | import org.onosproject.core.CoreService; |
38 | import org.onosproject.net.DeviceId; | 39 | import org.onosproject.net.DeviceId; |
39 | -import org.onosproject.net.flow.DefaultFlowRule; | ||
40 | import org.onosproject.net.flow.DefaultTrafficSelector; | 40 | import org.onosproject.net.flow.DefaultTrafficSelector; |
41 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 41 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
42 | -import org.onosproject.net.flow.FlowRule; | ||
43 | -import org.onosproject.net.flow.FlowRuleOperations; | ||
44 | import org.onosproject.net.flow.FlowRuleService; | 42 | import org.onosproject.net.flow.FlowRuleService; |
45 | import org.onosproject.net.flow.TrafficSelector; | 43 | import org.onosproject.net.flow.TrafficSelector; |
46 | import org.onosproject.net.flow.TrafficTreatment; | 44 | import org.onosproject.net.flow.TrafficTreatment; |
47 | import org.onosproject.net.flow.criteria.Criteria; | 45 | import org.onosproject.net.flow.criteria.Criteria; |
48 | import org.onosproject.net.flowobjective.DefaultFilteringObjective; | 46 | import org.onosproject.net.flowobjective.DefaultFilteringObjective; |
47 | +import org.onosproject.net.flowobjective.DefaultForwardingObjective; | ||
48 | +import org.onosproject.net.flowobjective.DefaultNextObjective; | ||
49 | import org.onosproject.net.flowobjective.FilteringObjective; | 49 | import org.onosproject.net.flowobjective.FilteringObjective; |
50 | import org.onosproject.net.flowobjective.FlowObjectiveService; | 50 | import org.onosproject.net.flowobjective.FlowObjectiveService; |
51 | -import org.onosproject.net.group.DefaultGroupBucket; | 51 | +import org.onosproject.net.flowobjective.ForwardingObjective; |
52 | -import org.onosproject.net.group.DefaultGroupDescription; | 52 | +import org.onosproject.net.flowobjective.NextObjective; |
53 | -import org.onosproject.net.group.DefaultGroupKey; | ||
54 | -import org.onosproject.net.group.Group; | ||
55 | -import org.onosproject.net.group.GroupBucket; | ||
56 | -import org.onosproject.net.group.GroupBuckets; | ||
57 | -import org.onosproject.net.group.GroupDescription; | ||
58 | -import org.onosproject.net.group.GroupEvent; | ||
59 | -import org.onosproject.net.group.GroupListener; | ||
60 | import org.onosproject.net.group.GroupService; | 53 | import org.onosproject.net.group.GroupService; |
61 | import org.onosproject.net.packet.PacketService; | 54 | import org.onosproject.net.packet.PacketService; |
62 | import org.onosproject.routing.FibEntry; | 55 | import org.onosproject.routing.FibEntry; |
... | @@ -74,7 +67,8 @@ import java.util.Collections; | ... | @@ -74,7 +67,8 @@ import java.util.Collections; |
74 | import java.util.HashMap; | 67 | import java.util.HashMap; |
75 | import java.util.Map; | 68 | import java.util.Map; |
76 | import java.util.Set; | 69 | import java.util.Set; |
77 | -import java.util.stream.Collectors; | 70 | + |
71 | +import static org.onlab.util.Tools.delay; | ||
78 | 72 | ||
79 | /** | 73 | /** |
80 | * BgpRouter component. | 74 | * BgpRouter component. |
... | @@ -124,7 +118,7 @@ public class BgpRouter { | ... | @@ -124,7 +118,7 @@ public class BgpRouter { |
124 | private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap(); | 118 | private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap(); |
125 | 119 | ||
126 | // Mapping from next hop IP to next hop object containing group info | 120 | // Mapping from next hop IP to next hop object containing group info |
127 | - private final Map<IpAddress, NextHop> nextHops = Maps.newHashMap(); | 121 | + private final Map<IpAddress, Integer> nextHops = Maps.newHashMap(); |
128 | 122 | ||
129 | // Stores FIB updates that are waiting for groups to be set up | 123 | // Stores FIB updates that are waiting for groups to be set up |
130 | private final Multimap<NextHopGroupKey, FibEntry> pendingUpdates = HashMultimap.create(); | 124 | private final Multimap<NextHopGroupKey, FibEntry> pendingUpdates = HashMultimap.create(); |
... | @@ -136,7 +130,7 @@ public class BgpRouter { | ... | @@ -136,7 +130,7 @@ public class BgpRouter { |
136 | // learned from config | 130 | // learned from config |
137 | private DeviceId ctrlDeviceId; | 131 | private DeviceId ctrlDeviceId; |
138 | 132 | ||
139 | - private final GroupListener groupListener = new InternalGroupListener(); | 133 | + //private final GroupListener groupListener = new InternalGroupListener(); |
140 | 134 | ||
141 | private TunnellingConnectivityManager connectivityManager; | 135 | private TunnellingConnectivityManager connectivityManager; |
142 | 136 | ||
... | @@ -160,7 +154,7 @@ public class BgpRouter { | ... | @@ -160,7 +154,7 @@ public class BgpRouter { |
160 | appId = coreService.registerApplication(BGP_ROUTER_APP); | 154 | appId = coreService.registerApplication(BGP_ROUTER_APP); |
161 | getDeviceConfiguration(configService.getBgpSpeakers()); | 155 | getDeviceConfiguration(configService.getBgpSpeakers()); |
162 | 156 | ||
163 | - groupService.addListener(groupListener); | 157 | + //groupService.addListener(groupListener); |
164 | 158 | ||
165 | processIntfFilters(true, configService.getInterfaces()); | 159 | processIntfFilters(true, configService.getInterfaces()); |
166 | 160 | ||
... | @@ -179,6 +173,14 @@ public class BgpRouter { | ... | @@ -179,6 +173,14 @@ public class BgpRouter { |
179 | icmpHandler.start(); | 173 | icmpHandler.start(); |
180 | 174 | ||
181 | log.info("BgpRouter started"); | 175 | log.info("BgpRouter started"); |
176 | + | ||
177 | + delay(1000); | ||
178 | + | ||
179 | + FibEntry fibEntry = new FibEntry(Ip4Prefix.valueOf("10.1.0.0/16"), | ||
180 | + Ip4Address.valueOf("192.168.10.1"), | ||
181 | + MacAddress.valueOf("DE:AD:BE:EF:FE:ED")); | ||
182 | + FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry); | ||
183 | + updateFibEntry(Collections.singletonList(fibUpdate)); | ||
182 | } | 184 | } |
183 | 185 | ||
184 | @Deactivate | 186 | @Deactivate |
... | @@ -188,7 +190,7 @@ public class BgpRouter { | ... | @@ -188,7 +190,7 @@ public class BgpRouter { |
188 | icmpHandler.stop(); | 190 | icmpHandler.stop(); |
189 | processIntfFilters(false, configService.getInterfaces()); | 191 | processIntfFilters(false, configService.getInterfaces()); |
190 | 192 | ||
191 | - groupService.removeListener(groupListener); | 193 | + //groupService.removeListener(groupListener); |
192 | 194 | ||
193 | log.info("BgpRouter stopped"); | 195 | log.info("BgpRouter stopped"); |
194 | } | 196 | } |
... | @@ -213,16 +215,18 @@ public class BgpRouter { | ... | @@ -213,16 +215,18 @@ public class BgpRouter { |
213 | } | 215 | } |
214 | 216 | ||
215 | private void updateFibEntry(Collection<FibUpdate> updates) { | 217 | private void updateFibEntry(Collection<FibUpdate> updates) { |
216 | - Map<FibEntry, Group> toInstall = new HashMap<>(updates.size()); | 218 | + Map<FibEntry, Integer> toInstall = new HashMap<>(updates.size()); |
217 | 219 | ||
218 | for (FibUpdate update : updates) { | 220 | for (FibUpdate update : updates) { |
219 | FibEntry entry = update.entry(); | 221 | FibEntry entry = update.entry(); |
220 | 222 | ||
221 | addNextHop(entry); | 223 | addNextHop(entry); |
222 | 224 | ||
223 | - Group group; | 225 | + Integer nextId; |
224 | synchronized (pendingUpdates) { | 226 | synchronized (pendingUpdates) { |
225 | - NextHop nextHop = nextHops.get(entry.nextHopIp()); | 227 | + nextId = nextHops.get(entry.nextHopIp()); |
228 | + | ||
229 | + /* | ||
226 | group = groupService.getGroup(deviceId, | 230 | group = groupService.getGroup(deviceId, |
227 | new DefaultGroupKey( | 231 | new DefaultGroupKey( |
228 | appKryo.serialize(nextHop.group()))); | 232 | appKryo.serialize(nextHop.group()))); |
... | @@ -231,66 +235,70 @@ public class BgpRouter { | ... | @@ -231,66 +235,70 @@ public class BgpRouter { |
231 | log.debug("Adding pending flow {}", update.entry()); | 235 | log.debug("Adding pending flow {}", update.entry()); |
232 | pendingUpdates.put(nextHop.group(), update.entry()); | 236 | pendingUpdates.put(nextHop.group(), update.entry()); |
233 | continue; | 237 | continue; |
234 | - } | 238 | + }*/ |
235 | } | 239 | } |
236 | 240 | ||
237 | - toInstall.put(update.entry(), group); | 241 | + toInstall.put(update.entry(), nextId); |
238 | } | 242 | } |
239 | 243 | ||
240 | installFlows(toInstall); | 244 | installFlows(toInstall); |
241 | } | 245 | } |
242 | 246 | ||
243 | - private void installFlows(Map<FibEntry, Group> entriesToInstall) { | 247 | + private void installFlows(Map<FibEntry, Integer> entriesToInstall) { |
244 | - FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); | ||
245 | 248 | ||
246 | - for (Map.Entry<FibEntry, Group> entry : entriesToInstall.entrySet()) { | 249 | + for (Map.Entry<FibEntry, Integer> entry : entriesToInstall.entrySet()) { |
247 | FibEntry fibEntry = entry.getKey(); | 250 | FibEntry fibEntry = entry.getKey(); |
248 | - Group group = entry.getValue(); | 251 | + Integer nextId = entry.getValue(); |
252 | + | ||
253 | + flowObjectiveService.forward(deviceId, | ||
254 | + generateRibFlowRule(fibEntry.prefix(), nextId).add()); | ||
249 | 255 | ||
250 | - FlowRule flowRule = generateRibFlowRule(fibEntry.prefix(), group); | ||
251 | 256 | ||
252 | - builder.add(flowRule); | ||
253 | } | 257 | } |
258 | + log.info("Sending flow forwarding objective"); | ||
254 | 259 | ||
255 | - flowService.apply(builder.build()); | ||
256 | } | 260 | } |
257 | 261 | ||
258 | private synchronized void deleteFibEntry(Collection<FibUpdate> withdraws) { | 262 | private synchronized void deleteFibEntry(Collection<FibUpdate> withdraws) { |
259 | - FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); | ||
260 | 263 | ||
261 | for (FibUpdate update : withdraws) { | 264 | for (FibUpdate update : withdraws) { |
262 | FibEntry entry = update.entry(); | 265 | FibEntry entry = update.entry(); |
266 | + Integer nextId = nextHops.get(entry.nextHopIp()); | ||
263 | 267 | ||
264 | - Group group = deleteNextHop(entry.prefix()); | 268 | + /*Group group = deleteNextHop(entry.prefix()); |
265 | if (group == null) { | 269 | if (group == null) { |
266 | log.warn("Group not found when deleting {}", entry); | 270 | log.warn("Group not found when deleting {}", entry); |
267 | return; | 271 | return; |
268 | - } | 272 | + }*/ |
269 | 273 | ||
270 | - FlowRule flowRule = generateRibFlowRule(entry.prefix(), group); | 274 | + flowObjectiveService.forward(deviceId, |
275 | + generateRibFlowRule(entry.prefix(), nextId).remove()); | ||
271 | 276 | ||
272 | - builder.remove(flowRule); | ||
273 | } | 277 | } |
274 | 278 | ||
275 | - flowService.apply(builder.build()); | ||
276 | } | 279 | } |
277 | 280 | ||
278 | - private FlowRule generateRibFlowRule(IpPrefix prefix, Group group) { | 281 | + private ForwardingObjective.Builder generateRibFlowRule(IpPrefix prefix, Integer nextId) { |
279 | TrafficSelector selector = DefaultTrafficSelector.builder() | 282 | TrafficSelector selector = DefaultTrafficSelector.builder() |
280 | .matchEthType(Ethernet.TYPE_IPV4) | 283 | .matchEthType(Ethernet.TYPE_IPV4) |
281 | .matchIPDst(prefix) | 284 | .matchIPDst(prefix) |
282 | .build(); | 285 | .build(); |
283 | 286 | ||
284 | - TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
285 | - .group(group.id()) | ||
286 | - .build(); | ||
287 | 287 | ||
288 | 288 | ||
289 | int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; | 289 | int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; |
290 | 290 | ||
291 | - return new DefaultFlowRule(deviceId, selector, treatment, | 291 | + ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder() |
292 | - priority, appId, 0, true, | 292 | + .fromApp(appId) |
293 | - FlowRule.Type.IP); | 293 | + .makePermanent() |
294 | + .nextStep(nextId) | ||
295 | + .withSelector(selector) | ||
296 | + .withPriority(priority) | ||
297 | + .withFlag(ForwardingObjective.Flag.SPECIFIC); | ||
298 | + | ||
299 | + return fwdBuilder; | ||
300 | + | ||
301 | + | ||
294 | } | 302 | } |
295 | 303 | ||
296 | private synchronized void addNextHop(FibEntry entry) { | 304 | private synchronized void addNextHop(FibEntry entry) { |
... | @@ -317,6 +325,16 @@ public class BgpRouter { | ... | @@ -317,6 +325,16 @@ public class BgpRouter { |
317 | .setOutput(egressIntf.connectPoint().port()) | 325 | .setOutput(egressIntf.connectPoint().port()) |
318 | .build(); | 326 | .build(); |
319 | 327 | ||
328 | + NextObjective nextObjective = DefaultNextObjective.builder() | ||
329 | + .withId(entry.hashCode()) | ||
330 | + .addTreatment(treatment) | ||
331 | + .withType(NextObjective.Type.SIMPLE) | ||
332 | + .fromApp(appId) | ||
333 | + .add(); | ||
334 | + | ||
335 | + flowObjectiveService.next(deviceId, nextObjective); | ||
336 | + | ||
337 | + /* | ||
320 | GroupBucket bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); | 338 | GroupBucket bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment); |
321 | 339 | ||
322 | GroupDescription groupDescription | 340 | GroupDescription groupDescription |
... | @@ -328,15 +346,16 @@ public class BgpRouter { | ... | @@ -328,15 +346,16 @@ public class BgpRouter { |
328 | appId); | 346 | appId); |
329 | 347 | ||
330 | groupService.addGroup(groupDescription); | 348 | groupService.addGroup(groupDescription); |
349 | + */ | ||
331 | 350 | ||
332 | - nextHops.put(nextHop.ip(), nextHop); | 351 | + nextHops.put(nextHop.ip(), entry.hashCode()); |
333 | 352 | ||
334 | } | 353 | } |
335 | 354 | ||
336 | nextHopsCount.add(entry.nextHopIp()); | 355 | nextHopsCount.add(entry.nextHopIp()); |
337 | } | 356 | } |
338 | 357 | ||
339 | - private synchronized Group deleteNextHop(IpPrefix prefix) { | 358 | + /*private synchronized Group deleteNextHop(IpPrefix prefix) { |
340 | IpAddress nextHopIp = prefixToNextHop.remove(prefix); | 359 | IpAddress nextHopIp = prefixToNextHop.remove(prefix); |
341 | NextHop nextHop = nextHops.get(nextHopIp); | 360 | NextHop nextHop = nextHops.get(nextHopIp); |
342 | if (nextHop == null) { | 361 | if (nextHop == null) { |
... | @@ -349,7 +368,7 @@ public class BgpRouter { | ... | @@ -349,7 +368,7 @@ public class BgpRouter { |
349 | serialize(nextHop.group()))); | 368 | serialize(nextHop.group()))); |
350 | 369 | ||
351 | // FIXME disabling group deletes for now until we verify the logic is OK | 370 | // FIXME disabling group deletes for now until we verify the logic is OK |
352 | - /*if (nextHopsCount.remove(nextHopIp, 1) <= 1) { | 371 | + *//*if (nextHopsCount.remove(nextHopIp, 1) <= 1) { |
353 | // There was one or less next hops, so there are now none | 372 | // There was one or less next hops, so there are now none |
354 | 373 | ||
355 | log.debug("removing group for next hop {}", nextHop); | 374 | log.debug("removing group for next hop {}", nextHop); |
... | @@ -359,10 +378,10 @@ public class BgpRouter { | ... | @@ -359,10 +378,10 @@ public class BgpRouter { |
359 | groupService.removeGroup(deviceId, | 378 | groupService.removeGroup(deviceId, |
360 | new DefaultGroupKey(appKryo.build().serialize(nextHop.group())), | 379 | new DefaultGroupKey(appKryo.build().serialize(nextHop.group())), |
361 | appId); | 380 | appId); |
362 | - }*/ | 381 | + }*//* |
363 | 382 | ||
364 | return group; | 383 | return group; |
365 | - } | 384 | + }*/ |
366 | 385 | ||
367 | private class InternalFibListener implements FibListener { | 386 | private class InternalFibListener implements FibListener { |
368 | 387 | ||
... | @@ -385,12 +404,11 @@ public class BgpRouter { | ... | @@ -385,12 +404,11 @@ public class BgpRouter { |
385 | .forEach(ipaddr -> fob.addCondition( | 404 | .forEach(ipaddr -> fob.addCondition( |
386 | Criteria.matchIPDst(ipaddr.subnetAddress()))); | 405 | Criteria.matchIPDst(ipaddr.subnetAddress()))); |
387 | fob.permit().fromApp(appId); | 406 | fob.permit().fromApp(appId); |
388 | - flowObjectiveService.filter(deviceId, | 407 | + flowObjectiveService.filter(deviceId, fob.add()); |
389 | - Collections.singletonList(fob.add())); | ||
390 | } | 408 | } |
391 | } | 409 | } |
392 | 410 | ||
393 | - private class InternalGroupListener implements GroupListener { | 411 | + /* private class InternalGroupListener implements GroupListener { |
394 | 412 | ||
395 | @Override | 413 | @Override |
396 | public void event(GroupEvent event) { | 414 | public void event(GroupEvent event) { |
... | @@ -412,5 +430,5 @@ public class BgpRouter { | ... | @@ -412,5 +430,5 @@ public class BgpRouter { |
412 | } | 430 | } |
413 | } | 431 | } |
414 | } | 432 | } |
415 | - } | 433 | + }*/ |
416 | } | 434 | } | ... | ... |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.behaviour; | ||
17 | + | ||
18 | +/** | ||
19 | + * Default implementation of a next group. | ||
20 | + */ | ||
21 | +public class DefaultNextGroup implements NextGroup { | ||
22 | + | ||
23 | + private final byte[] data; | ||
24 | + | ||
25 | + public DefaultNextGroup(byte[] data) { | ||
26 | + this.data = data; | ||
27 | + } | ||
28 | + | ||
29 | + @Override | ||
30 | + public byte[] data() { | ||
31 | + return data; | ||
32 | + } | ||
33 | +} |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.behaviour; | ||
17 | + | ||
18 | +/** | ||
19 | + * Opaque data type for carrying group-like information. | ||
20 | + * Only relevant to a pipeliner driver. | ||
21 | + */ | ||
22 | +public interface NextGroup { | ||
23 | + | ||
24 | + /** | ||
25 | + * Serialized form of the next group. | ||
26 | + * @return a byte array. | ||
27 | + */ | ||
28 | + byte[] data(); | ||
29 | + | ||
30 | +} |
... | @@ -21,9 +21,6 @@ import org.onosproject.net.flowobjective.FilteringObjective; | ... | @@ -21,9 +21,6 @@ import org.onosproject.net.flowobjective.FilteringObjective; |
21 | import org.onosproject.net.flowobjective.ForwardingObjective; | 21 | import org.onosproject.net.flowobjective.ForwardingObjective; |
22 | import org.onosproject.net.flowobjective.NextObjective; | 22 | import org.onosproject.net.flowobjective.NextObjective; |
23 | 23 | ||
24 | -import java.util.Collection; | ||
25 | -import java.util.concurrent.Future; | ||
26 | - | ||
27 | /** | 24 | /** |
28 | * Behaviour for handling various pipelines. | 25 | * Behaviour for handling various pipelines. |
29 | */ | 26 | */ |
... | @@ -40,24 +37,21 @@ public interface Pipeliner extends HandlerBehaviour { | ... | @@ -40,24 +37,21 @@ public interface Pipeliner extends HandlerBehaviour { |
40 | /** | 37 | /** |
41 | * Installs the filtering rules onto the device. | 38 | * Installs the filtering rules onto the device. |
42 | * | 39 | * |
43 | - * @param filterObjectives the collection of filters | 40 | + * @param filterObjective a filtering objective |
44 | - * @return a future indicating the success of the operation | ||
45 | */ | 41 | */ |
46 | - Future<Boolean> filter(Collection<FilteringObjective> filterObjectives); | 42 | + void filter(FilteringObjective filterObjective); |
47 | 43 | ||
48 | /** | 44 | /** |
49 | * Installs the forwarding rules onto the device. | 45 | * Installs the forwarding rules onto the device. |
50 | * | 46 | * |
51 | - * @param forwardObjectives the collection of forwarding objectives | 47 | + * @param forwardObjective a forwarding objective |
52 | - * @return a future indicating the success of the operation | ||
53 | */ | 48 | */ |
54 | - Future<Boolean> forward(Collection<ForwardingObjective> forwardObjectives); | 49 | + void forward(ForwardingObjective forwardObjective); |
55 | 50 | ||
56 | /** | 51 | /** |
57 | * Installs the next hop elements into the device. | 52 | * Installs the next hop elements into the device. |
58 | * | 53 | * |
59 | - * @param nextObjectives the collection of next objectives | 54 | + * @param nextObjective a next objectives |
60 | - * @return a future indicating the success of the operation | ||
61 | */ | 55 | */ |
62 | - Future<Boolean> next(Collection<NextObjective> nextObjectives); | 56 | + void next(NextObjective nextObjective); |
63 | } | 57 | } | ... | ... |
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | package org.onosproject.net.behaviour; | 16 | package org.onosproject.net.behaviour; |
17 | 17 | ||
18 | import org.onlab.osgi.ServiceDirectory; | 18 | import org.onlab.osgi.ServiceDirectory; |
19 | +import org.onosproject.net.flowobjective.FlowObjectiveStore; | ||
19 | 20 | ||
20 | /** | 21 | /** |
21 | * Processing context and supporting services for the pipeline behaviour. | 22 | * Processing context and supporting services for the pipeline behaviour. |
... | @@ -30,5 +31,11 @@ public interface PipelinerContext { | ... | @@ -30,5 +31,11 @@ public interface PipelinerContext { |
30 | */ | 31 | */ |
31 | ServiceDirectory directory(); | 32 | ServiceDirectory directory(); |
32 | 33 | ||
34 | + /** | ||
35 | + * Returns the Objective Store where data can be stored and retrieved. | ||
36 | + * @return the flow objective store | ||
37 | + */ | ||
38 | + FlowObjectiveStore store(); | ||
39 | + | ||
33 | // TODO: add means to store and access shared state | 40 | // TODO: add means to store and access shared state |
34 | } | 41 | } | ... | ... |
... | @@ -23,6 +23,7 @@ import org.onosproject.net.flow.criteria.Criterion; | ... | @@ -23,6 +23,7 @@ import org.onosproject.net.flow.criteria.Criterion; |
23 | import java.util.Collection; | 23 | import java.util.Collection; |
24 | import java.util.List; | 24 | import java.util.List; |
25 | import java.util.Objects; | 25 | import java.util.Objects; |
26 | +import java.util.Optional; | ||
26 | 27 | ||
27 | import static com.google.common.base.Preconditions.checkArgument; | 28 | import static com.google.common.base.Preconditions.checkArgument; |
28 | import static com.google.common.base.Preconditions.checkNotNull; | 29 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -42,6 +43,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { | ... | @@ -42,6 +43,7 @@ public final class DefaultFilteringObjective implements FilteringObjective { |
42 | private final List<Criterion> conditions; | 43 | private final List<Criterion> conditions; |
43 | private final int id; | 44 | private final int id; |
44 | private final Operation op; | 45 | private final Operation op; |
46 | + private final Optional<ObjectiveContext> context; | ||
45 | 47 | ||
46 | private DefaultFilteringObjective(Type type, boolean permanent, int timeout, | 48 | private DefaultFilteringObjective(Type type, boolean permanent, int timeout, |
47 | ApplicationId appId, int priority, Criterion key, | 49 | ApplicationId appId, int priority, Criterion key, |
... | @@ -54,6 +56,25 @@ public final class DefaultFilteringObjective implements FilteringObjective { | ... | @@ -54,6 +56,25 @@ public final class DefaultFilteringObjective implements FilteringObjective { |
54 | this.priority = priority; | 56 | this.priority = priority; |
55 | this.conditions = conditions; | 57 | this.conditions = conditions; |
56 | this.op = op; | 58 | this.op = op; |
59 | + this.context = Optional.empty(); | ||
60 | + | ||
61 | + this.id = Objects.hash(type, key, conditions, permanent, | ||
62 | + timeout, appId, priority); | ||
63 | + } | ||
64 | + | ||
65 | + public DefaultFilteringObjective(Type type, boolean permanent, int timeout, | ||
66 | + ApplicationId appId, int priority, Criterion key, | ||
67 | + List<Criterion> conditions, | ||
68 | + ObjectiveContext context, Operation op) { | ||
69 | + this.key = key; | ||
70 | + this.type = type; | ||
71 | + this.permanent = permanent; | ||
72 | + this.timeout = timeout; | ||
73 | + this.appId = appId; | ||
74 | + this.priority = priority; | ||
75 | + this.conditions = conditions; | ||
76 | + this.op = op; | ||
77 | + this.context = Optional.ofNullable(context); | ||
57 | 78 | ||
58 | this.id = Objects.hash(type, key, conditions, permanent, | 79 | this.id = Objects.hash(type, key, conditions, permanent, |
59 | timeout, appId, priority); | 80 | timeout, appId, priority); |
... | @@ -104,6 +125,11 @@ public final class DefaultFilteringObjective implements FilteringObjective { | ... | @@ -104,6 +125,11 @@ public final class DefaultFilteringObjective implements FilteringObjective { |
104 | return op; | 125 | return op; |
105 | } | 126 | } |
106 | 127 | ||
128 | + @Override | ||
129 | + public Optional<ObjectiveContext> context() { | ||
130 | + return context; | ||
131 | + } | ||
132 | + | ||
107 | /** | 133 | /** |
108 | * Returns a new builder. | 134 | * Returns a new builder. |
109 | * | 135 | * |
... | @@ -201,6 +227,31 @@ public final class DefaultFilteringObjective implements FilteringObjective { | ... | @@ -201,6 +227,31 @@ public final class DefaultFilteringObjective implements FilteringObjective { |
201 | 227 | ||
202 | } | 228 | } |
203 | 229 | ||
230 | + @Override | ||
231 | + public FilteringObjective add(ObjectiveContext context) { | ||
232 | + List<Criterion> conditions = listBuilder.build(); | ||
233 | + checkNotNull(type, "Must have a type."); | ||
234 | + checkArgument(!conditions.isEmpty(), "Must have at least one condition."); | ||
235 | + checkNotNull(appId, "Must supply an application id"); | ||
236 | + | ||
237 | + return new DefaultFilteringObjective(type, permanent, timeout, | ||
238 | + appId, priority, key, conditions, | ||
239 | + context, Operation.ADD); | ||
240 | + } | ||
241 | + | ||
242 | + @Override | ||
243 | + public FilteringObjective remove(ObjectiveContext context) { | ||
244 | + List<Criterion> conditions = listBuilder.build(); | ||
245 | + checkNotNull(type, "Must have a type."); | ||
246 | + checkArgument(!conditions.isEmpty(), "Must have at least one condition."); | ||
247 | + checkNotNull(appId, "Must supply an application id"); | ||
248 | + | ||
249 | + | ||
250 | + return new DefaultFilteringObjective(type, permanent, timeout, | ||
251 | + appId, priority, key, conditions, | ||
252 | + context, Operation.REMOVE); | ||
253 | + } | ||
254 | + | ||
204 | 255 | ||
205 | } | 256 | } |
206 | 257 | ... | ... |
... | @@ -20,6 +20,7 @@ import org.onosproject.net.flow.TrafficSelector; | ... | @@ -20,6 +20,7 @@ import org.onosproject.net.flow.TrafficSelector; |
20 | import org.onosproject.net.flow.TrafficTreatment; | 20 | import org.onosproject.net.flow.TrafficTreatment; |
21 | 21 | ||
22 | import java.util.Objects; | 22 | import java.util.Objects; |
23 | +import java.util.Optional; | ||
23 | 24 | ||
24 | import static com.google.common.base.Preconditions.checkArgument; | 25 | import static com.google.common.base.Preconditions.checkArgument; |
25 | import static com.google.common.base.Preconditions.checkNotNull; | 26 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -38,6 +39,7 @@ public final class DefaultForwardingObjective implements ForwardingObjective { | ... | @@ -38,6 +39,7 @@ public final class DefaultForwardingObjective implements ForwardingObjective { |
38 | private final int nextId; | 39 | private final int nextId; |
39 | private final TrafficTreatment treatment; | 40 | private final TrafficTreatment treatment; |
40 | private final Operation op; | 41 | private final Operation op; |
42 | + private final Optional<ObjectiveContext> context; | ||
41 | 43 | ||
42 | private final int id; | 44 | private final int id; |
43 | 45 | ||
... | @@ -55,6 +57,29 @@ public final class DefaultForwardingObjective implements ForwardingObjective { | ... | @@ -55,6 +57,29 @@ public final class DefaultForwardingObjective implements ForwardingObjective { |
55 | this.nextId = nextId; | 57 | this.nextId = nextId; |
56 | this.treatment = treatment; | 58 | this.treatment = treatment; |
57 | this.op = op; | 59 | this.op = op; |
60 | + this.context = Optional.empty(); | ||
61 | + | ||
62 | + this.id = Objects.hash(selector, flag, permanent, | ||
63 | + timeout, appId, priority, nextId, | ||
64 | + treatment, op); | ||
65 | + } | ||
66 | + | ||
67 | + private DefaultForwardingObjective(TrafficSelector selector, | ||
68 | + Flag flag, boolean permanent, | ||
69 | + int timeout, ApplicationId appId, | ||
70 | + int priority, int nextId, | ||
71 | + TrafficTreatment treatment, | ||
72 | + ObjectiveContext context, Operation op) { | ||
73 | + this.selector = selector; | ||
74 | + this.flag = flag; | ||
75 | + this.permanent = permanent; | ||
76 | + this.timeout = timeout; | ||
77 | + this.appId = appId; | ||
78 | + this.priority = priority; | ||
79 | + this.nextId = nextId; | ||
80 | + this.treatment = treatment; | ||
81 | + this.op = op; | ||
82 | + this.context = Optional.ofNullable(context); | ||
58 | 83 | ||
59 | this.id = Objects.hash(selector, flag, permanent, | 84 | this.id = Objects.hash(selector, flag, permanent, |
60 | timeout, appId, priority, nextId, | 85 | timeout, appId, priority, nextId, |
... | @@ -113,6 +138,11 @@ public final class DefaultForwardingObjective implements ForwardingObjective { | ... | @@ -113,6 +138,11 @@ public final class DefaultForwardingObjective implements ForwardingObjective { |
113 | return op; | 138 | return op; |
114 | } | 139 | } |
115 | 140 | ||
141 | + @Override | ||
142 | + public Optional<ObjectiveContext> context() { | ||
143 | + return context; | ||
144 | + } | ||
145 | + | ||
116 | /** | 146 | /** |
117 | * Returns a new builder. | 147 | * Returns a new builder. |
118 | * | 148 | * |
... | @@ -186,7 +216,7 @@ public final class DefaultForwardingObjective implements ForwardingObjective { | ... | @@ -186,7 +216,7 @@ public final class DefaultForwardingObjective implements ForwardingObjective { |
186 | public ForwardingObjective add() { | 216 | public ForwardingObjective add() { |
187 | checkNotNull(selector, "Must have a selector"); | 217 | checkNotNull(selector, "Must have a selector"); |
188 | checkNotNull(flag, "A flag must be set"); | 218 | checkNotNull(flag, "A flag must be set"); |
189 | - checkArgument(nextId != null && treatment != null, "Must supply at " + | 219 | + checkArgument(nextId != null || treatment != null, "Must supply at " + |
190 | "least a treatment and/or a nextId"); | 220 | "least a treatment and/or a nextId"); |
191 | checkNotNull(appId, "Must supply an application id"); | 221 | checkNotNull(appId, "Must supply an application id"); |
192 | return new DefaultForwardingObjective(selector, flag, permanent, | 222 | return new DefaultForwardingObjective(selector, flag, permanent, |
... | @@ -198,12 +228,38 @@ public final class DefaultForwardingObjective implements ForwardingObjective { | ... | @@ -198,12 +228,38 @@ public final class DefaultForwardingObjective implements ForwardingObjective { |
198 | public ForwardingObjective remove() { | 228 | public ForwardingObjective remove() { |
199 | checkNotNull(selector, "Must have a selector"); | 229 | checkNotNull(selector, "Must have a selector"); |
200 | checkNotNull(flag, "A flag must be set"); | 230 | checkNotNull(flag, "A flag must be set"); |
201 | - checkArgument(nextId != null && treatment != null, "Must supply at " + | 231 | + checkArgument(nextId != null || treatment != null, "Must supply at " + |
202 | "least a treatment and/or a nextId"); | 232 | "least a treatment and/or a nextId"); |
203 | checkNotNull(appId, "Must supply an application id"); | 233 | checkNotNull(appId, "Must supply an application id"); |
204 | return new DefaultForwardingObjective(selector, flag, permanent, | 234 | return new DefaultForwardingObjective(selector, flag, permanent, |
205 | timeout, appId, priority, | 235 | timeout, appId, priority, |
206 | nextId, treatment, Operation.REMOVE); | 236 | nextId, treatment, Operation.REMOVE); |
207 | } | 237 | } |
238 | + | ||
239 | + @Override | ||
240 | + public ForwardingObjective add(ObjectiveContext context) { | ||
241 | + checkNotNull(selector, "Must have a selector"); | ||
242 | + checkNotNull(flag, "A flag must be set"); | ||
243 | + checkArgument(nextId != null || treatment != null, "Must supply at " + | ||
244 | + "least a treatment and/or a nextId"); | ||
245 | + checkNotNull(appId, "Must supply an application id"); | ||
246 | + return new DefaultForwardingObjective(selector, flag, permanent, | ||
247 | + timeout, appId, priority, | ||
248 | + nextId, treatment, | ||
249 | + context, Operation.ADD); | ||
250 | + } | ||
251 | + | ||
252 | + @Override | ||
253 | + public ForwardingObjective remove(ObjectiveContext context) { | ||
254 | + checkNotNull(selector, "Must have a selector"); | ||
255 | + checkNotNull(flag, "A flag must be set"); | ||
256 | + checkArgument(nextId != null || treatment != null, "Must supply at " + | ||
257 | + "least a treatment and/or a nextId"); | ||
258 | + checkNotNull(appId, "Must supply an application id"); | ||
259 | + return new DefaultForwardingObjective(selector, flag, permanent, | ||
260 | + timeout, appId, priority, | ||
261 | + nextId, treatment, | ||
262 | + context, Operation.REMOVE); | ||
263 | + } | ||
208 | } | 264 | } |
209 | } | 265 | } | ... | ... |
... | @@ -21,6 +21,7 @@ import org.onosproject.net.flow.TrafficTreatment; | ... | @@ -21,6 +21,7 @@ import org.onosproject.net.flow.TrafficTreatment; |
21 | 21 | ||
22 | import java.util.Collection; | 22 | import java.util.Collection; |
23 | import java.util.List; | 23 | import java.util.List; |
24 | +import java.util.Optional; | ||
24 | 25 | ||
25 | import static com.google.common.base.Preconditions.checkArgument; | 26 | import static com.google.common.base.Preconditions.checkArgument; |
26 | import static com.google.common.base.Preconditions.checkNotNull; | 27 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -34,13 +35,28 @@ public final class DefaultNextObjective implements NextObjective { | ... | @@ -34,13 +35,28 @@ public final class DefaultNextObjective implements NextObjective { |
34 | private final ApplicationId appId; | 35 | private final ApplicationId appId; |
35 | private final Type type; | 36 | private final Type type; |
36 | private final Integer id; | 37 | private final Integer id; |
38 | + private final Operation op; | ||
39 | + private final Optional<ObjectiveContext> context; | ||
37 | 40 | ||
38 | private DefaultNextObjective(Integer id, List<TrafficTreatment> treatments, | 41 | private DefaultNextObjective(Integer id, List<TrafficTreatment> treatments, |
39 | - ApplicationId appId, Type type) { | 42 | + ApplicationId appId, Type type, Operation op) { |
40 | this.treatments = treatments; | 43 | this.treatments = treatments; |
41 | this.appId = appId; | 44 | this.appId = appId; |
42 | this.type = type; | 45 | this.type = type; |
43 | this.id = id; | 46 | this.id = id; |
47 | + this.op = op; | ||
48 | + this.context = Optional.empty(); | ||
49 | + } | ||
50 | + | ||
51 | + private DefaultNextObjective(Integer id, List<TrafficTreatment> treatments, | ||
52 | + ApplicationId appId, ObjectiveContext context, | ||
53 | + Type type, Operation op) { | ||
54 | + this.treatments = treatments; | ||
55 | + this.appId = appId; | ||
56 | + this.type = type; | ||
57 | + this.id = id; | ||
58 | + this.op = op; | ||
59 | + this.context = Optional.ofNullable(context); | ||
44 | } | 60 | } |
45 | 61 | ||
46 | @Override | 62 | @Override |
... | @@ -80,7 +96,12 @@ public final class DefaultNextObjective implements NextObjective { | ... | @@ -80,7 +96,12 @@ public final class DefaultNextObjective implements NextObjective { |
80 | 96 | ||
81 | @Override | 97 | @Override |
82 | public Operation op() { | 98 | public Operation op() { |
83 | - throw new UnsupportedOperationException("Next Objective has no operation"); | 99 | + return op; |
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public Optional<ObjectiveContext> context() { | ||
104 | + return context; | ||
84 | } | 105 | } |
85 | 106 | ||
86 | /** | 107 | /** |
... | @@ -101,8 +122,6 @@ public final class DefaultNextObjective implements NextObjective { | ... | @@ -101,8 +122,6 @@ public final class DefaultNextObjective implements NextObjective { |
101 | private final ImmutableList.Builder<TrafficTreatment> listBuilder | 122 | private final ImmutableList.Builder<TrafficTreatment> listBuilder |
102 | = ImmutableList.builder(); | 123 | = ImmutableList.builder(); |
103 | 124 | ||
104 | - | ||
105 | - | ||
106 | @Override | 125 | @Override |
107 | public NextObjective.Builder withId(int nextId) { | 126 | public NextObjective.Builder withId(int nextId) { |
108 | this.id = nextId; | 127 | this.id = nextId; |
... | @@ -143,7 +162,7 @@ public final class DefaultNextObjective implements NextObjective { | ... | @@ -143,7 +162,7 @@ public final class DefaultNextObjective implements NextObjective { |
143 | } | 162 | } |
144 | 163 | ||
145 | @Override | 164 | @Override |
146 | - public Builder fromApp(ApplicationId appId) { | 165 | + public NextObjective.Builder fromApp(ApplicationId appId) { |
147 | this.appId = appId; | 166 | this.appId = appId; |
148 | return this; | 167 | return this; |
149 | } | 168 | } |
... | @@ -160,14 +179,49 @@ public final class DefaultNextObjective implements NextObjective { | ... | @@ -160,14 +179,49 @@ public final class DefaultNextObjective implements NextObjective { |
160 | } | 179 | } |
161 | 180 | ||
162 | @Override | 181 | @Override |
163 | - public NextObjective build() { | 182 | + public NextObjective add() { |
183 | + List<TrafficTreatment> treatments = listBuilder.build(); | ||
184 | + checkNotNull(appId, "Must supply an application id"); | ||
185 | + checkNotNull(id, "id cannot be null"); | ||
186 | + checkNotNull(type, "The type cannot be null"); | ||
187 | + checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); | ||
188 | + | ||
189 | + return new DefaultNextObjective(id, treatments, appId, type, Operation.ADD); | ||
190 | + } | ||
191 | + | ||
192 | + @Override | ||
193 | + public NextObjective remove() { | ||
194 | + List<TrafficTreatment> treatments = listBuilder.build(); | ||
195 | + checkNotNull(appId, "Must supply an application id"); | ||
196 | + checkNotNull(id, "id cannot be null"); | ||
197 | + checkNotNull(type, "The type cannot be null"); | ||
198 | + checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); | ||
199 | + | ||
200 | + return new DefaultNextObjective(id, treatments, appId, type, Operation.REMOVE); | ||
201 | + } | ||
202 | + | ||
203 | + @Override | ||
204 | + public NextObjective add(ObjectiveContext context) { | ||
205 | + List<TrafficTreatment> treatments = listBuilder.build(); | ||
206 | + checkNotNull(appId, "Must supply an application id"); | ||
207 | + checkNotNull(id, "id cannot be null"); | ||
208 | + checkNotNull(type, "The type cannot be null"); | ||
209 | + checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); | ||
210 | + | ||
211 | + return new DefaultNextObjective(id, treatments, appId, | ||
212 | + context, type, Operation.ADD); | ||
213 | + } | ||
214 | + | ||
215 | + @Override | ||
216 | + public NextObjective remove(ObjectiveContext context) { | ||
164 | List<TrafficTreatment> treatments = listBuilder.build(); | 217 | List<TrafficTreatment> treatments = listBuilder.build(); |
165 | checkNotNull(appId, "Must supply an application id"); | 218 | checkNotNull(appId, "Must supply an application id"); |
166 | checkNotNull(id, "id cannot be null"); | 219 | checkNotNull(id, "id cannot be null"); |
167 | checkNotNull(type, "The type cannot be null"); | 220 | checkNotNull(type, "The type cannot be null"); |
168 | checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); | 221 | checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); |
169 | 222 | ||
170 | - return new DefaultNextObjective(id, treatments, appId, type); | 223 | + return new DefaultNextObjective(id, treatments, appId, |
224 | + context, type, Operation.REMOVE); | ||
171 | } | 225 | } |
172 | } | 226 | } |
173 | } | 227 | } | ... | ... |
... | @@ -114,6 +114,24 @@ public interface FilteringObjective extends Objective { | ... | @@ -114,6 +114,24 @@ public interface FilteringObjective extends Objective { |
114 | */ | 114 | */ |
115 | public FilteringObjective remove(); | 115 | public FilteringObjective remove(); |
116 | 116 | ||
117 | + /** | ||
118 | + * Builds the filtering objective that will be added. | ||
119 | + * The context will be used to notify the calling application. | ||
120 | + * | ||
121 | + * @param context an objective context | ||
122 | + * @return a filtering objective | ||
123 | + */ | ||
124 | + public FilteringObjective add(ObjectiveContext context); | ||
125 | + | ||
126 | + /** | ||
127 | + * Builds the filtering objective that will be removed. | ||
128 | + * The context will be used to notify the calling application. | ||
129 | + * | ||
130 | + * @param context an objective context | ||
131 | + * @return a filtering objective | ||
132 | + */ | ||
133 | + public FilteringObjective remove(ObjectiveContext context); | ||
134 | + | ||
117 | 135 | ||
118 | } | 136 | } |
119 | 137 | ... | ... |
... | @@ -17,9 +17,6 @@ package org.onosproject.net.flowobjective; | ... | @@ -17,9 +17,6 @@ package org.onosproject.net.flowobjective; |
17 | 17 | ||
18 | import org.onosproject.net.DeviceId; | 18 | import org.onosproject.net.DeviceId; |
19 | 19 | ||
20 | -import java.util.Collection; | ||
21 | -import java.util.concurrent.Future; | ||
22 | - | ||
23 | /** | 20 | /** |
24 | * Service for programming data plane flow rules in manner independent of | 21 | * Service for programming data plane flow rules in manner independent of |
25 | * specific device table pipeline configuration. | 22 | * specific device table pipeline configuration. |
... | @@ -30,27 +27,24 @@ public interface FlowObjectiveService { | ... | @@ -30,27 +27,24 @@ public interface FlowObjectiveService { |
30 | * Installs the filtering rules onto the specified device. | 27 | * Installs the filtering rules onto the specified device. |
31 | * | 28 | * |
32 | * @param deviceId device identifier | 29 | * @param deviceId device identifier |
33 | - * @param filteringObjectives the collection of filters | 30 | + * @param filteringObjective the filtering objective |
34 | - * @return a future indicating the success of the operation | ||
35 | */ | 31 | */ |
36 | - Future<Boolean> filter(DeviceId deviceId, Collection<FilteringObjective> filteringObjectives); | 32 | + void filter(DeviceId deviceId, FilteringObjective filteringObjective); |
37 | 33 | ||
38 | /** | 34 | /** |
39 | * Installs the forwarding rules onto the specified device. | 35 | * Installs the forwarding rules onto the specified device. |
40 | * | 36 | * |
41 | * @param deviceId device identifier | 37 | * @param deviceId device identifier |
42 | - * @param forwardingObjectives the collection of forwarding objectives | 38 | + * @param forwardingObjective the forwarding objective |
43 | - * @return a future indicating the success of the operation | ||
44 | */ | 39 | */ |
45 | - Future<Boolean> forward(DeviceId deviceId, Collection<ForwardingObjective> forwardingObjectives); | 40 | + void forward(DeviceId deviceId, ForwardingObjective forwardingObjective); |
46 | 41 | ||
47 | /** | 42 | /** |
48 | * Installs the next hop elements into the specified device. | 43 | * Installs the next hop elements into the specified device. |
49 | * | 44 | * |
50 | * @param deviceId device identifier | 45 | * @param deviceId device identifier |
51 | - * @param nextObjectives the collection of next objectives | 46 | + * @param nextObjective a next objective |
52 | - * @return a future indicating the success of the operation | ||
53 | */ | 47 | */ |
54 | - Future<Boolean> next(DeviceId deviceId, Collection<NextObjective> nextObjectives); | 48 | + void next(DeviceId deviceId, NextObjective nextObjective); |
55 | 49 | ||
56 | } | 50 | } | ... | ... |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.flowobjective; | ||
17 | + | ||
18 | +import org.onosproject.net.behaviour.NextGroup; | ||
19 | +import org.onosproject.store.Store; | ||
20 | + | ||
21 | +/** | ||
22 | + * The flow objective store. | ||
23 | + */ | ||
24 | +public interface FlowObjectiveStore | ||
25 | + extends Store<ObjectiveEvent, FlowObjectiveStoreDelegate> { | ||
26 | + | ||
27 | + /** | ||
28 | + * Adds a NextGroup to the store. | ||
29 | + * | ||
30 | + * @param nextId an integer | ||
31 | + * @param group a next group opaque object | ||
32 | + */ | ||
33 | + void putNextGroup(Integer nextId, NextGroup group); | ||
34 | + | ||
35 | + /** | ||
36 | + * Fetch a next group from the store. | ||
37 | + * @param nextId an integer | ||
38 | + * @return a next group | ||
39 | + */ | ||
40 | + NextGroup getNextGroup(Integer nextId); | ||
41 | +} |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.flowobjective; | ||
17 | + | ||
18 | +import org.onosproject.store.StoreDelegate; | ||
19 | + | ||
20 | +/** | ||
21 | + * Flow Objective store delegate abstraction. | ||
22 | + */ | ||
23 | +public interface FlowObjectiveStoreDelegate extends StoreDelegate<ObjectiveEvent> { | ||
24 | +} |
... | @@ -121,5 +121,23 @@ public interface ForwardingObjective extends Objective { | ... | @@ -121,5 +121,23 @@ public interface ForwardingObjective extends Objective { |
121 | * @return a forwarding objective. | 121 | * @return a forwarding objective. |
122 | */ | 122 | */ |
123 | public ForwardingObjective remove(); | 123 | public ForwardingObjective remove(); |
124 | + | ||
125 | + /** | ||
126 | + * Builds the forwarding objective that will be added. | ||
127 | + * The context will be used to notify the calling application. | ||
128 | + * | ||
129 | + * @param context an objective context | ||
130 | + * @return a forwarding objective | ||
131 | + */ | ||
132 | + public ForwardingObjective add(ObjectiveContext context); | ||
133 | + | ||
134 | + /** | ||
135 | + * Builds the forwarding objective that will be removed. | ||
136 | + * The context will be used to notify the calling application. | ||
137 | + * | ||
138 | + * @param context an objective context | ||
139 | + * @return a forwarding objective | ||
140 | + */ | ||
141 | + public ForwardingObjective remove(ObjectiveContext context); | ||
124 | } | 142 | } |
125 | } | 143 | } | ... | ... |
... | @@ -15,6 +15,7 @@ | ... | @@ -15,6 +15,7 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.flowobjective; | 16 | package org.onosproject.net.flowobjective; |
17 | 17 | ||
18 | +import org.onosproject.core.ApplicationId; | ||
18 | import org.onosproject.net.flow.TrafficTreatment; | 19 | import org.onosproject.net.flow.TrafficTreatment; |
19 | 20 | ||
20 | import java.util.Collection; | 21 | import java.util.Collection; |
... | @@ -95,12 +96,40 @@ public interface NextObjective extends Objective { | ... | @@ -95,12 +96,40 @@ public interface NextObjective extends Objective { |
95 | */ | 96 | */ |
96 | public Builder addTreatment(TrafficTreatment treatment); | 97 | public Builder addTreatment(TrafficTreatment treatment); |
97 | 98 | ||
99 | + @Override | ||
100 | + public Builder fromApp(ApplicationId appId); | ||
101 | + | ||
102 | + /** | ||
103 | + * Builds the next objective that will be added. | ||
104 | + * | ||
105 | + * @return a next objective | ||
106 | + */ | ||
107 | + public NextObjective add(); | ||
108 | + | ||
109 | + /** | ||
110 | + * Builds the next objective that will be removed. | ||
111 | + * | ||
112 | + * @return a next objective. | ||
113 | + */ | ||
114 | + public NextObjective remove(); | ||
115 | + | ||
116 | + /** | ||
117 | + * Builds the next objective that will be added. | ||
118 | + * The context will be used to notify the calling application. | ||
119 | + * | ||
120 | + * @param context an objective context | ||
121 | + * @return a next objective | ||
122 | + */ | ||
123 | + public NextObjective add(ObjectiveContext context); | ||
124 | + | ||
98 | /** | 125 | /** |
99 | - * Builds a next step. | 126 | + * Builds the next objective that will be removed. |
127 | + * The context will be used to notify the calling application. | ||
100 | * | 128 | * |
101 | - * @return a next step | 129 | + * @param context an objective context |
130 | + * @return a next objective | ||
102 | */ | 131 | */ |
103 | - public NextObjective build(); | 132 | + public NextObjective remove(ObjectiveContext context); |
104 | 133 | ||
105 | } | 134 | } |
106 | 135 | ... | ... |
... | @@ -17,6 +17,8 @@ package org.onosproject.net.flowobjective; | ... | @@ -17,6 +17,8 @@ package org.onosproject.net.flowobjective; |
17 | 17 | ||
18 | import org.onosproject.core.ApplicationId; | 18 | import org.onosproject.core.ApplicationId; |
19 | 19 | ||
20 | +import java.util.Optional; | ||
21 | + | ||
20 | /** | 22 | /** |
21 | * Base representation of an flow description. | 23 | * Base representation of an flow description. |
22 | */ | 24 | */ |
... | @@ -84,6 +86,14 @@ public interface Objective { | ... | @@ -84,6 +86,14 @@ public interface Objective { |
84 | Operation op(); | 86 | Operation op(); |
85 | 87 | ||
86 | /** | 88 | /** |
89 | + * Obtains an optional context. | ||
90 | + * | ||
91 | + * @return optional; which will be empty if there is no context. | ||
92 | + * Otherwise it will return the context. | ||
93 | + */ | ||
94 | + Optional<ObjectiveContext> context(); | ||
95 | + | ||
96 | + /** | ||
87 | * An objective builder. | 97 | * An objective builder. |
88 | */ | 98 | */ |
89 | public interface Builder { | 99 | public interface Builder { | ... | ... |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.flowobjective; | ||
17 | + | ||
18 | +/** | ||
19 | + * The context of a objective that will become the subject of | ||
20 | + * the notification. | ||
21 | + * | ||
22 | + * Implementations of this class must be serializable. | ||
23 | + */ | ||
24 | +public interface ObjectiveContext { | ||
25 | + | ||
26 | + default void onSuccess(Objective objective) {} | ||
27 | + | ||
28 | + default void onError(Objective objective, ObjectiveError error) {} | ||
29 | + | ||
30 | +} |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.flowobjective; | ||
17 | + | ||
18 | +/** | ||
19 | + * Represents the set of errors possible when processing an objective. | ||
20 | + */ | ||
21 | +public enum ObjectiveError { | ||
22 | + | ||
23 | + /** | ||
24 | + * The driver processing this objective does not know how to process it. | ||
25 | + */ | ||
26 | + UNSUPPORTED, | ||
27 | + | ||
28 | + /** | ||
29 | + * The flow installation for this objective failed. | ||
30 | + */ | ||
31 | + FLOWINSTALLATIONFAILED, | ||
32 | + | ||
33 | + /** | ||
34 | + * THe group installation for this objective failed. | ||
35 | + */ | ||
36 | + GROUPINSTALLATIONFAILED, | ||
37 | + | ||
38 | + /** | ||
39 | + * The group was reported as installed but is not missing. | ||
40 | + */ | ||
41 | + GROUPMISSING, | ||
42 | + | ||
43 | + /** | ||
44 | + * An unknown error occurred. | ||
45 | + */ | ||
46 | + UNKNOWN | ||
47 | +} |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.flowobjective; | ||
17 | + | ||
18 | +import org.onosproject.event.AbstractEvent; | ||
19 | + | ||
20 | +/** | ||
21 | + * Describes a objective event. | ||
22 | + */ | ||
23 | +public class ObjectiveEvent extends AbstractEvent<ObjectiveEvent.Type, Integer> { | ||
24 | + | ||
25 | + /** | ||
26 | + * Type of objective events. | ||
27 | + */ | ||
28 | + public enum Type { | ||
29 | + /** | ||
30 | + * Signifies that the objective has been added to the store. | ||
31 | + */ | ||
32 | + ADD, | ||
33 | + | ||
34 | + /** | ||
35 | + * Signifies that the objective has been removed. | ||
36 | + */ | ||
37 | + REMOVE | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Creates an event of the given type for the specified objective id. | ||
42 | + * | ||
43 | + * @param type the type of the event | ||
44 | + * @param objective the objective id the event is about | ||
45 | + */ | ||
46 | + public ObjectiveEvent(Type type, Integer objective) { | ||
47 | + super(type, objective); | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * Creates an event of the given type for the specified objective id at the given | ||
52 | + * time. | ||
53 | + * | ||
54 | + * @param type the type of the event | ||
55 | + * @param objective the objective id the event is about | ||
56 | + * @param time the time of the event | ||
57 | + */ | ||
58 | + public ObjectiveEvent(Type type, Integer objective, long time) { | ||
59 | + super(type, objective, time); | ||
60 | + } | ||
61 | +} | ||
62 | + |
... | @@ -17,7 +17,7 @@ package org.onosproject.net.flowobjective.impl; | ... | @@ -17,7 +17,7 @@ package org.onosproject.net.flowobjective.impl; |
17 | 17 | ||
18 | import com.google.common.collect.Lists; | 18 | import com.google.common.collect.Lists; |
19 | import com.google.common.collect.Maps; | 19 | import com.google.common.collect.Maps; |
20 | -import com.google.common.util.concurrent.Futures; | 20 | +import com.google.common.collect.Sets; |
21 | import org.apache.felix.scr.annotations.Activate; | 21 | import org.apache.felix.scr.annotations.Activate; |
22 | import org.apache.felix.scr.annotations.Component; | 22 | import org.apache.felix.scr.annotations.Component; |
23 | import org.apache.felix.scr.annotations.Deactivate; | 23 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -43,9 +43,12 @@ import org.onosproject.net.driver.DriverService; | ... | @@ -43,9 +43,12 @@ import org.onosproject.net.driver.DriverService; |
43 | import org.onosproject.net.flow.FlowRuleService; | 43 | import org.onosproject.net.flow.FlowRuleService; |
44 | import org.onosproject.net.flowobjective.FilteringObjective; | 44 | import org.onosproject.net.flowobjective.FilteringObjective; |
45 | import org.onosproject.net.flowobjective.FlowObjectiveService; | 45 | import org.onosproject.net.flowobjective.FlowObjectiveService; |
46 | +import org.onosproject.net.flowobjective.FlowObjectiveStore; | ||
47 | +import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate; | ||
46 | import org.onosproject.net.flowobjective.ForwardingObjective; | 48 | import org.onosproject.net.flowobjective.ForwardingObjective; |
47 | import org.onosproject.net.flowobjective.NextObjective; | 49 | import org.onosproject.net.flowobjective.NextObjective; |
48 | import org.onosproject.net.flowobjective.Objective; | 50 | import org.onosproject.net.flowobjective.Objective; |
51 | +import org.onosproject.net.flowobjective.ObjectiveEvent; | ||
49 | import org.onosproject.net.group.GroupService; | 52 | import org.onosproject.net.group.GroupService; |
50 | import org.slf4j.Logger; | 53 | import org.slf4j.Logger; |
51 | import org.slf4j.LoggerFactory; | 54 | import org.slf4j.LoggerFactory; |
... | @@ -53,14 +56,14 @@ import org.slf4j.LoggerFactory; | ... | @@ -53,14 +56,14 @@ import org.slf4j.LoggerFactory; |
53 | import java.util.Collection; | 56 | import java.util.Collection; |
54 | import java.util.Collections; | 57 | import java.util.Collections; |
55 | import java.util.Map; | 58 | import java.util.Map; |
56 | -import java.util.concurrent.Future; | 59 | +import java.util.Set; |
57 | 60 | ||
58 | import static com.google.common.base.Preconditions.checkState; | 61 | import static com.google.common.base.Preconditions.checkState; |
59 | 62 | ||
60 | /** | 63 | /** |
61 | * Provides implementation of the flow objective programming service. | 64 | * Provides implementation of the flow objective programming service. |
62 | */ | 65 | */ |
63 | -@Component(immediate = false) | 66 | +@Component(immediate = true) |
64 | @Service | 67 | @Service |
65 | public class FlowObjectiveManager implements FlowObjectiveService { | 68 | public class FlowObjectiveManager implements FlowObjectiveService { |
66 | 69 | ||
... | @@ -89,6 +92,10 @@ public class FlowObjectiveManager implements FlowObjectiveService { | ... | @@ -89,6 +92,10 @@ public class FlowObjectiveManager implements FlowObjectiveService { |
89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 92 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
90 | protected GroupService groupService; | 93 | protected GroupService groupService; |
91 | 94 | ||
95 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
96 | + protected FlowObjectiveStore flowObjectiveStore; | ||
97 | + | ||
98 | + private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate(); | ||
92 | 99 | ||
93 | private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap(); | 100 | private final Map<DeviceId, DriverHandler> driverHandlers = Maps.newConcurrentMap(); |
94 | private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap(); | 101 | private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap(); |
... | @@ -101,10 +108,16 @@ public class FlowObjectiveManager implements FlowObjectiveService { | ... | @@ -101,10 +108,16 @@ public class FlowObjectiveManager implements FlowObjectiveService { |
101 | 108 | ||
102 | private final Map<DeviceId, Collection<Objective>> pendingObjectives = | 109 | private final Map<DeviceId, Collection<Objective>> pendingObjectives = |
103 | Maps.newConcurrentMap(); | 110 | Maps.newConcurrentMap(); |
111 | + | ||
104 | private NodeId localNode; | 112 | private NodeId localNode; |
105 | 113 | ||
114 | + private Map<Integer, Set<PendingNext>> pendingForwards = | ||
115 | + Maps.newConcurrentMap(); | ||
116 | + | ||
117 | + | ||
106 | @Activate | 118 | @Activate |
107 | protected void activate() { | 119 | protected void activate() { |
120 | + flowObjectiveStore.setDelegate(delegate); | ||
108 | localNode = clusterService.getLocalNode().id(); | 121 | localNode = clusterService.getLocalNode().id(); |
109 | mastershipService.addListener(mastershipListener); | 122 | mastershipService.addListener(mastershipListener); |
110 | deviceService.addListener(deviceListener); | 123 | deviceService.addListener(deviceListener); |
... | @@ -114,46 +127,64 @@ public class FlowObjectiveManager implements FlowObjectiveService { | ... | @@ -114,46 +127,64 @@ public class FlowObjectiveManager implements FlowObjectiveService { |
114 | 127 | ||
115 | @Deactivate | 128 | @Deactivate |
116 | protected void deactivate() { | 129 | protected void deactivate() { |
130 | + flowObjectiveStore.unsetDelegate(delegate); | ||
117 | mastershipService.removeListener(mastershipListener); | 131 | mastershipService.removeListener(mastershipListener); |
118 | deviceService.removeListener(deviceListener); | 132 | deviceService.removeListener(deviceListener); |
119 | log.info("Stopped"); | 133 | log.info("Stopped"); |
120 | } | 134 | } |
121 | 135 | ||
122 | @Override | 136 | @Override |
123 | - public Future<Boolean> filter(DeviceId deviceId, | 137 | + public void filter(DeviceId deviceId, |
124 | - Collection<FilteringObjective> filteringObjectives) { | 138 | + FilteringObjective filteringObjective) { |
125 | if (deviceService.isAvailable(deviceId)) { | 139 | if (deviceService.isAvailable(deviceId)) { |
126 | - return getDevicePipeliner(deviceId).filter(filteringObjectives); | 140 | + getDevicePipeliner(deviceId).filter(filteringObjective); |
127 | } else { | 141 | } else { |
128 | - filteringObjectives.forEach(obj -> updatePendingMap(deviceId, obj)); | 142 | + updatePendingMap(deviceId, filteringObjective); |
129 | } | 143 | } |
130 | - return Futures.immediateFuture(true); | 144 | + |
131 | } | 145 | } |
132 | 146 | ||
147 | + @Override | ||
148 | + public void forward(DeviceId deviceId, | ||
149 | + ForwardingObjective forwardingObjective) { | ||
133 | 150 | ||
151 | + if (queueObjective(deviceId, forwardingObjective)) { | ||
152 | + return; | ||
153 | + } | ||
134 | 154 | ||
135 | - @Override | ||
136 | - public Future<Boolean> forward(DeviceId deviceId, | ||
137 | - Collection<ForwardingObjective> forwardingObjectives) { | ||
138 | if (deviceService.isAvailable(deviceId)) { | 155 | if (deviceService.isAvailable(deviceId)) { |
139 | - return getDevicePipeliner(deviceId).forward(forwardingObjectives); | 156 | + getDevicePipeliner(deviceId).forward(forwardingObjective); |
140 | } else { | 157 | } else { |
141 | - forwardingObjectives.forEach(obj -> updatePendingMap(deviceId, obj)); | 158 | + updatePendingMap(deviceId, forwardingObjective); |
142 | } | 159 | } |
143 | - return Futures.immediateFuture(true); | 160 | + |
144 | } | 161 | } |
145 | 162 | ||
146 | @Override | 163 | @Override |
147 | - public Future<Boolean> next(DeviceId deviceId, | 164 | + public void next(DeviceId deviceId, |
148 | - Collection<NextObjective> nextObjectives) { | 165 | + NextObjective nextObjective) { |
149 | if (deviceService.isAvailable(deviceId)) { | 166 | if (deviceService.isAvailable(deviceId)) { |
150 | - return getDevicePipeliner(deviceId).next(nextObjectives); | 167 | + getDevicePipeliner(deviceId).next(nextObjective); |
151 | } else { | 168 | } else { |
152 | - nextObjectives.forEach(obj -> updatePendingMap(deviceId, obj)); | 169 | + updatePendingMap(deviceId, nextObjective); |
170 | + } | ||
171 | + } | ||
172 | + | ||
173 | + private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) { | ||
174 | + if (fwd.nextId() != null && | ||
175 | + flowObjectiveStore.getNextGroup(fwd.nextId()) == null) { | ||
176 | + log.warn("Queuing forwarding objective."); | ||
177 | + if (pendingForwards.putIfAbsent(fwd.nextId(), | ||
178 | + Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) { | ||
179 | + Set<PendingNext> pending = pendingForwards.get(fwd.nextId()); | ||
180 | + pending.add(new PendingNext(deviceId, fwd)); | ||
181 | + } | ||
182 | + return true; | ||
153 | } | 183 | } |
154 | - return Futures.immediateFuture(true); | 184 | + return false; |
155 | } | 185 | } |
156 | 186 | ||
187 | + | ||
157 | private void updatePendingMap(DeviceId deviceId, Objective pending) { | 188 | private void updatePendingMap(DeviceId deviceId, Objective pending) { |
158 | if (pendingObjectives.putIfAbsent(deviceId, Lists.newArrayList(pending)) != null) { | 189 | if (pendingObjectives.putIfAbsent(deviceId, Lists.newArrayList(pending)) != null) { |
159 | Collection<Objective> objectives = pendingObjectives.get(deviceId); | 190 | Collection<Objective> objectives = pendingObjectives.get(deviceId); |
... | @@ -169,6 +200,33 @@ public class FlowObjectiveManager implements FlowObjectiveService { | ... | @@ -169,6 +200,33 @@ public class FlowObjectiveManager implements FlowObjectiveService { |
169 | return pipeliner; | 200 | return pipeliner; |
170 | } | 201 | } |
171 | 202 | ||
203 | + private void setupPipelineHandler(DeviceId deviceId) { | ||
204 | + if (localNode.equals(mastershipService.getMasterFor(deviceId))) { | ||
205 | + // Attempt to lookup the handler in the cache | ||
206 | + DriverHandler handler = driverHandlers.get(deviceId); | ||
207 | + if (handler == null) { | ||
208 | + try { | ||
209 | + // Otherwise create it and if it has pipeline behaviour, cache it | ||
210 | + handler = driverService.createHandler(deviceId); | ||
211 | + if (!handler.driver().hasBehaviour(Pipeliner.class)) { | ||
212 | + log.warn("Pipeline behaviour not supported for device {}", | ||
213 | + deviceId); | ||
214 | + return; | ||
215 | + } | ||
216 | + } catch (ItemNotFoundException e) { | ||
217 | + log.warn("No applicable driver for device {}", deviceId); | ||
218 | + return; | ||
219 | + } | ||
220 | + driverHandlers.put(deviceId, handler); | ||
221 | + } | ||
222 | + | ||
223 | + // Always (re)initialize the pipeline behaviour | ||
224 | + Pipeliner pipeliner = handler.behaviour(Pipeliner.class); | ||
225 | + pipeliner.init(deviceId, context); | ||
226 | + pipeliners.putIfAbsent(deviceId, pipeliner); | ||
227 | + log.info("Driver {} bound to device {}", handler.driver().name(), deviceId); | ||
228 | + } | ||
229 | + } | ||
172 | 230 | ||
173 | // Triggers driver setup when the local node becomes a device master. | 231 | // Triggers driver setup when the local node becomes a device master. |
174 | private class InnerMastershipListener implements MastershipListener { | 232 | private class InnerMastershipListener implements MastershipListener { |
... | @@ -221,52 +279,70 @@ public class FlowObjectiveManager implements FlowObjectiveService { | ... | @@ -221,52 +279,70 @@ public class FlowObjectiveManager implements FlowObjectiveService { |
221 | pendingObjectives.getOrDefault(deviceId, | 279 | pendingObjectives.getOrDefault(deviceId, |
222 | Collections.emptySet()).forEach(obj -> { | 280 | Collections.emptySet()).forEach(obj -> { |
223 | if (obj instanceof NextObjective) { | 281 | if (obj instanceof NextObjective) { |
224 | - getDevicePipeliner(deviceId) | 282 | + next(deviceId, (NextObjective) obj); |
225 | - .next(Collections.singletonList((NextObjective) obj)); | ||
226 | } else if (obj instanceof ForwardingObjective) { | 283 | } else if (obj instanceof ForwardingObjective) { |
227 | - getDevicePipeliner(deviceId) | 284 | + forward(deviceId, (ForwardingObjective) obj); |
228 | - .forward(Collections.singletonList((ForwardingObjective) obj)); | ||
229 | } else { | 285 | } else { |
230 | getDevicePipeliner(deviceId) | 286 | getDevicePipeliner(deviceId) |
231 | - .filter(Collections.singletonList((FilteringObjective) obj)); | 287 | + .filter((FilteringObjective) obj); |
232 | } | 288 | } |
233 | }); | 289 | }); |
234 | } | 290 | } |
235 | } | 291 | } |
236 | 292 | ||
237 | - private void setupPipelineHandler(DeviceId deviceId) { | ||
238 | - if (localNode.equals(mastershipService.getMasterFor(deviceId))) { | ||
239 | - // Attempt to lookup the handler in the cache | ||
240 | - DriverHandler handler = driverHandlers.get(deviceId); | ||
241 | - if (handler == null) { | ||
242 | - try { | ||
243 | - // Otherwise create it and if it has pipeline behaviour, cache it | ||
244 | - handler = driverService.createHandler(deviceId); | ||
245 | - if (!handler.driver().hasBehaviour(Pipeliner.class)) { | ||
246 | - log.warn("Pipeline behaviour not supported for device {}", | ||
247 | - deviceId); | ||
248 | - return; | ||
249 | - } | ||
250 | - } catch (ItemNotFoundException e) { | ||
251 | - log.warn("No applicable driver for device {}", deviceId); | ||
252 | - return; | ||
253 | - } | ||
254 | - driverHandlers.put(deviceId, handler); | ||
255 | - } | ||
256 | - | ||
257 | - // Always (re)initialize the pipeline behaviour | ||
258 | - Pipeliner pipeliner = handler.behaviour(Pipeliner.class); | ||
259 | - pipeliner.init(deviceId, context); | ||
260 | - pipeliners.putIfAbsent(deviceId, pipeliner); | ||
261 | - log.info("Driver {} bound to device {}", handler.driver().name(), deviceId); | ||
262 | - } | ||
263 | - } | ||
264 | - | ||
265 | // Processing context for initializing pipeline driver behaviours. | 293 | // Processing context for initializing pipeline driver behaviours. |
266 | private class InnerPipelineContext implements PipelinerContext { | 294 | private class InnerPipelineContext implements PipelinerContext { |
267 | @Override | 295 | @Override |
268 | public ServiceDirectory directory() { | 296 | public ServiceDirectory directory() { |
269 | return serviceDirectory; | 297 | return serviceDirectory; |
270 | } | 298 | } |
299 | + | ||
300 | + @Override | ||
301 | + public FlowObjectiveStore store() { | ||
302 | + return flowObjectiveStore; | ||
303 | + } | ||
304 | + | ||
305 | + | ||
306 | + } | ||
307 | + | ||
308 | + private class InternalStoreDelegate implements FlowObjectiveStoreDelegate { | ||
309 | + @Override | ||
310 | + public void notify(ObjectiveEvent event) { | ||
311 | + Set<PendingNext> pending = pendingForwards.remove(event.subject()); | ||
312 | + | ||
313 | + if (pending == null) { | ||
314 | + return; | ||
315 | + } | ||
316 | + | ||
317 | + log.info("Processing pending objectives {}", pending.size()); | ||
318 | + | ||
319 | + pending.forEach(p -> getDevicePipeliner(p.deviceId()) | ||
320 | + .forward(p.forwardingObjective())); | ||
321 | + | ||
322 | + } | ||
323 | + } | ||
324 | + | ||
325 | + /** | ||
326 | + * Data class used to hold a pending forwarding objective that could not | ||
327 | + * be processed because the associated next object was not present. | ||
328 | + */ | ||
329 | + private class PendingNext { | ||
330 | + private final DeviceId deviceId; | ||
331 | + private final ForwardingObjective fwd; | ||
332 | + | ||
333 | + public PendingNext(DeviceId deviceId, ForwardingObjective fwd) { | ||
334 | + this.deviceId = deviceId; | ||
335 | + this.fwd = fwd; | ||
336 | + } | ||
337 | + | ||
338 | + public DeviceId deviceId() { | ||
339 | + return deviceId; | ||
340 | + } | ||
341 | + | ||
342 | + public ForwardingObjective forwardingObjective() { | ||
343 | + return fwd; | ||
344 | + } | ||
345 | + | ||
346 | + | ||
271 | } | 347 | } |
272 | } | 348 | } | ... | ... |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.store.flowobjective.impl; | ||
17 | + | ||
18 | +import org.apache.felix.scr.annotations.Activate; | ||
19 | +import org.apache.felix.scr.annotations.Component; | ||
20 | +import org.apache.felix.scr.annotations.Deactivate; | ||
21 | +import org.apache.felix.scr.annotations.Reference; | ||
22 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
23 | +import org.apache.felix.scr.annotations.Service; | ||
24 | +import org.onlab.util.KryoNamespace; | ||
25 | +import org.onosproject.net.behaviour.DefaultNextGroup; | ||
26 | +import org.onosproject.net.behaviour.NextGroup; | ||
27 | +import org.onosproject.net.flowobjective.FlowObjectiveStore; | ||
28 | +import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate; | ||
29 | +import org.onosproject.net.flowobjective.ObjectiveEvent; | ||
30 | +import org.onosproject.store.AbstractStore; | ||
31 | +import org.onosproject.store.service.ConsistentMap; | ||
32 | +import org.onosproject.store.service.Serializer; | ||
33 | +import org.onosproject.store.service.StorageService; | ||
34 | +import org.onosproject.store.service.Versioned; | ||
35 | +import org.slf4j.Logger; | ||
36 | + | ||
37 | +import static org.slf4j.LoggerFactory.getLogger; | ||
38 | + | ||
39 | +/** | ||
40 | + * Manages the inventory of created next groups. | ||
41 | + */ | ||
42 | +@Component(immediate = true, enabled = true) | ||
43 | +@Service | ||
44 | +public class DistributedFlowObjectiveStore | ||
45 | + extends AbstractStore<ObjectiveEvent, FlowObjectiveStoreDelegate> | ||
46 | + implements FlowObjectiveStore { | ||
47 | + | ||
48 | + private final Logger log = getLogger(getClass()); | ||
49 | + | ||
50 | + private ConsistentMap<Integer, byte[]> nextGroups; | ||
51 | + | ||
52 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
53 | + protected StorageService storageService; | ||
54 | + | ||
55 | + @Activate | ||
56 | + public void activate() { | ||
57 | + nextGroups = storageService.<Integer, byte[]>consistentMapBuilder() | ||
58 | + .withName("flowobjective-groups") | ||
59 | + .withSerializer(Serializer.using( | ||
60 | + new KryoNamespace.Builder() | ||
61 | + .register(byte[].class) | ||
62 | + .build())) | ||
63 | + .build(); | ||
64 | + | ||
65 | + log.info("Started"); | ||
66 | + } | ||
67 | + | ||
68 | + | ||
69 | + @Deactivate | ||
70 | + public void deactivate() { | ||
71 | + log.info("Stopped"); | ||
72 | + } | ||
73 | + | ||
74 | + | ||
75 | + @Override | ||
76 | + public void putNextGroup(Integer nextId, NextGroup group) { | ||
77 | + nextGroups.putIfAbsent(nextId, group.data()); | ||
78 | + notifyDelegate(new ObjectiveEvent(ObjectiveEvent.Type.ADD, nextId)); | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + public NextGroup getNextGroup(Integer nextId) { | ||
83 | + Versioned<byte[]> versionGroup = nextGroups.get(nextId); | ||
84 | + if (versionGroup != null) { | ||
85 | + return new DefaultNextGroup(versionGroup.value()); | ||
86 | + } | ||
87 | + return null; | ||
88 | + } | ||
89 | +} |
... | @@ -167,10 +167,13 @@ public class DistributedPacketStore | ... | @@ -167,10 +167,13 @@ public class DistributedPacketStore |
167 | public PacketRequestTracker() { | 167 | public PacketRequestTracker() { |
168 | requests = storageService.<PacketRequest, Boolean>consistentMapBuilder() | 168 | requests = storageService.<PacketRequest, Boolean>consistentMapBuilder() |
169 | .withName("packet-requests") | 169 | .withName("packet-requests") |
170 | + .withSerializer(Serializer.using( | ||
171 | + new KryoNamespace.Builder().register(KryoNamespaces.API).build())) | ||
170 | .withSerializer(new Serializer() { | 172 | .withSerializer(new Serializer() { |
171 | KryoNamespace kryo = new KryoNamespace.Builder() | 173 | KryoNamespace kryo = new KryoNamespace.Builder() |
172 | .register(KryoNamespaces.API) | 174 | .register(KryoNamespaces.API) |
173 | .build(); | 175 | .build(); |
176 | + | ||
174 | @Override | 177 | @Override |
175 | public <T> byte[] encode(T object) { | 178 | public <T> byte[] encode(T object) { |
176 | return kryo.serialize(object); | 179 | return kryo.serialize(object); | ... | ... |
... | @@ -44,6 +44,12 @@ | ... | @@ -44,6 +44,12 @@ |
44 | </dependency> | 44 | </dependency> |
45 | 45 | ||
46 | <dependency> | 46 | <dependency> |
47 | + <groupId>org.onosproject</groupId> | ||
48 | + <artifactId>onos-core-serializers</artifactId> | ||
49 | + <version>1.2.0-SNAPSHOT</version> | ||
50 | + </dependency> | ||
51 | + | ||
52 | + <dependency> | ||
47 | <groupId>org.easymock</groupId> | 53 | <groupId>org.easymock</groupId> |
48 | <artifactId>easymock</artifactId> | 54 | <artifactId>easymock</artifactId> |
49 | <scope>test</scope> | 55 | <scope>test</scope> | ... | ... |
... | @@ -31,11 +31,9 @@ import org.onosproject.net.flow.TrafficSelector; | ... | @@ -31,11 +31,9 @@ import org.onosproject.net.flow.TrafficSelector; |
31 | import org.onosproject.net.flowobjective.FilteringObjective; | 31 | import org.onosproject.net.flowobjective.FilteringObjective; |
32 | import org.onosproject.net.flowobjective.ForwardingObjective; | 32 | import org.onosproject.net.flowobjective.ForwardingObjective; |
33 | import org.onosproject.net.flowobjective.NextObjective; | 33 | import org.onosproject.net.flowobjective.NextObjective; |
34 | +import org.onosproject.net.flowobjective.ObjectiveError; | ||
34 | import org.slf4j.Logger; | 35 | import org.slf4j.Logger; |
35 | 36 | ||
36 | -import java.util.Collection; | ||
37 | -import java.util.concurrent.Future; | ||
38 | - | ||
39 | import static org.slf4j.LoggerFactory.getLogger; | 37 | import static org.slf4j.LoggerFactory.getLogger; |
40 | 38 | ||
41 | /** | 39 | /** |
... | @@ -58,59 +56,62 @@ public class DefaultSingleTablePipeline extends AbstractHandlerBehaviour impleme | ... | @@ -58,59 +56,62 @@ public class DefaultSingleTablePipeline extends AbstractHandlerBehaviour impleme |
58 | } | 56 | } |
59 | 57 | ||
60 | @Override | 58 | @Override |
61 | - public Future<Boolean> filter(Collection<FilteringObjective> filters) { | 59 | + public void filter(FilteringObjective filter) { |
62 | throw new UnsupportedOperationException("Single table does not filter."); | 60 | throw new UnsupportedOperationException("Single table does not filter."); |
63 | } | 61 | } |
64 | 62 | ||
65 | @Override | 63 | @Override |
66 | - public Future<Boolean> forward(Collection<ForwardingObjective> forwardings) { | 64 | + public void forward(ForwardingObjective fwd) { |
67 | FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); | 65 | FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); |
68 | - forwardings.forEach(fwd -> { | ||
69 | - if (fwd.flag() != ForwardingObjective.Flag.VERSATILE) { | ||
70 | - throw new UnsupportedOperationException( | ||
71 | - "Only VERSATILE is supported."); | ||
72 | - } | ||
73 | 66 | ||
74 | - TrafficSelector selector = fwd.selector(); | 67 | + if (fwd.flag() != ForwardingObjective.Flag.VERSATILE) { |
68 | + throw new UnsupportedOperationException( | ||
69 | + "Only VERSATILE is supported."); | ||
70 | + } | ||
75 | 71 | ||
76 | - FlowRule rule = new DefaultFlowRule(deviceId, selector, | 72 | + TrafficSelector selector = fwd.selector(); |
77 | - fwd.treatment(), | ||
78 | - fwd.priority(), fwd.appId(), | ||
79 | - new DefaultGroupId(fwd.id()), | ||
80 | - fwd.timeout(), fwd.permanent()); | ||
81 | 73 | ||
82 | - switch (fwd.op()) { | 74 | + FlowRule rule = new DefaultFlowRule(deviceId, selector, |
75 | + fwd.treatment(), | ||
76 | + fwd.priority(), fwd.appId(), | ||
77 | + new DefaultGroupId(fwd.id()), | ||
78 | + fwd.timeout(), fwd.permanent()); | ||
83 | 79 | ||
84 | - case ADD: | 80 | + switch (fwd.op()) { |
85 | - flowBuilder.add(rule); | 81 | + |
86 | - break; | 82 | + case ADD: |
87 | - case REMOVE: | 83 | + flowBuilder.add(rule); |
88 | - flowBuilder.remove(rule); | 84 | + break; |
89 | - break; | 85 | + case REMOVE: |
90 | - default: | 86 | + flowBuilder.remove(rule); |
91 | - log.warn("Unknown operation {}", fwd.op()); | 87 | + break; |
92 | - } | 88 | + default: |
89 | + log.warn("Unknown operation {}", fwd.op()); | ||
90 | + } | ||
93 | 91 | ||
94 | - }); | ||
95 | 92 | ||
96 | SettableFuture<Boolean> future = SettableFuture.create(); | 93 | SettableFuture<Boolean> future = SettableFuture.create(); |
97 | 94 | ||
98 | flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { | 95 | flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { |
99 | @Override | 96 | @Override |
100 | public void onSuccess(FlowRuleOperations ops) { | 97 | public void onSuccess(FlowRuleOperations ops) { |
101 | - future.set(true); | 98 | + if (fwd.context().isPresent()) { |
99 | + fwd.context().get().onSuccess(fwd); | ||
100 | + } | ||
102 | } | 101 | } |
103 | 102 | ||
104 | @Override | 103 | @Override |
105 | public void onError(FlowRuleOperations ops) { | 104 | public void onError(FlowRuleOperations ops) { |
106 | - future.set(false); | 105 | + if (fwd.context().isPresent()) { |
106 | + fwd.context().get().onError(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); | ||
107 | + } | ||
107 | } | 108 | } |
108 | })); | 109 | })); |
109 | - return future; | 110 | + |
110 | } | 111 | } |
111 | 112 | ||
112 | @Override | 113 | @Override |
113 | - public Future<Boolean> next(Collection<NextObjective> nextObjectives) { | 114 | + public void next(NextObjective nextObjective) { |
114 | throw new UnsupportedOperationException("Single table does not next hop."); | 115 | throw new UnsupportedOperationException("Single table does not next hop."); |
115 | } | 116 | } |
116 | 117 | ... | ... |
... | @@ -15,15 +15,19 @@ | ... | @@ -15,15 +15,19 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.driver.pipeline; | 16 | package org.onosproject.driver.pipeline; |
17 | 17 | ||
18 | -import com.google.common.collect.Sets; | 18 | +import com.google.common.cache.Cache; |
19 | -import com.google.common.util.concurrent.SettableFuture; | 19 | +import com.google.common.cache.CacheBuilder; |
20 | +import com.google.common.cache.RemovalCause; | ||
21 | +import com.google.common.cache.RemovalNotification; | ||
20 | import org.onlab.osgi.ServiceDirectory; | 22 | import org.onlab.osgi.ServiceDirectory; |
21 | import org.onlab.packet.Ethernet; | 23 | import org.onlab.packet.Ethernet; |
22 | import org.onlab.packet.MacAddress; | 24 | import org.onlab.packet.MacAddress; |
23 | import org.onlab.packet.VlanId; | 25 | import org.onlab.packet.VlanId; |
26 | +import org.onlab.util.KryoNamespace; | ||
24 | import org.onosproject.core.ApplicationId; | 27 | import org.onosproject.core.ApplicationId; |
25 | import org.onosproject.core.CoreService; | 28 | import org.onosproject.core.CoreService; |
26 | import org.onosproject.net.DeviceId; | 29 | import org.onosproject.net.DeviceId; |
30 | +import org.onosproject.net.behaviour.NextGroup; | ||
27 | import org.onosproject.net.behaviour.Pipeliner; | 31 | import org.onosproject.net.behaviour.Pipeliner; |
28 | import org.onosproject.net.behaviour.PipelinerContext; | 32 | import org.onosproject.net.behaviour.PipelinerContext; |
29 | import org.onosproject.net.driver.AbstractHandlerBehaviour; | 33 | import org.onosproject.net.driver.AbstractHandlerBehaviour; |
... | @@ -39,18 +43,37 @@ import org.onosproject.net.flow.TrafficTreatment; | ... | @@ -39,18 +43,37 @@ import org.onosproject.net.flow.TrafficTreatment; |
39 | import org.onosproject.net.flow.criteria.Criteria; | 43 | import org.onosproject.net.flow.criteria.Criteria; |
40 | import org.onosproject.net.flow.criteria.Criterion; | 44 | import org.onosproject.net.flow.criteria.Criterion; |
41 | import org.onosproject.net.flowobjective.FilteringObjective; | 45 | import org.onosproject.net.flowobjective.FilteringObjective; |
46 | +import org.onosproject.net.flowobjective.FlowObjectiveStore; | ||
42 | import org.onosproject.net.flowobjective.ForwardingObjective; | 47 | import org.onosproject.net.flowobjective.ForwardingObjective; |
43 | import org.onosproject.net.flowobjective.NextObjective; | 48 | import org.onosproject.net.flowobjective.NextObjective; |
44 | import org.onosproject.net.flowobjective.Objective; | 49 | import org.onosproject.net.flowobjective.Objective; |
50 | +import org.onosproject.net.flowobjective.ObjectiveError; | ||
51 | +import org.onosproject.net.group.DefaultGroupBucket; | ||
52 | +import org.onosproject.net.group.DefaultGroupDescription; | ||
53 | +import org.onosproject.net.group.DefaultGroupKey; | ||
54 | +import org.onosproject.net.group.Group; | ||
55 | +import org.onosproject.net.group.GroupBucket; | ||
56 | +import org.onosproject.net.group.GroupBuckets; | ||
57 | +import org.onosproject.net.group.GroupDescription; | ||
58 | +import org.onosproject.net.group.GroupEvent; | ||
59 | +import org.onosproject.net.group.GroupKey; | ||
60 | +import org.onosproject.net.group.GroupListener; | ||
61 | +import org.onosproject.net.group.GroupService; | ||
45 | import org.slf4j.Logger; | 62 | import org.slf4j.Logger; |
46 | 63 | ||
47 | import java.util.Collection; | 64 | import java.util.Collection; |
48 | -import java.util.concurrent.Future; | 65 | +import java.util.Collections; |
49 | - | 66 | +import java.util.Set; |
67 | +import java.util.concurrent.Executors; | ||
68 | +import java.util.concurrent.ScheduledExecutorService; | ||
69 | +import java.util.concurrent.TimeUnit; | ||
70 | +import java.util.stream.Collectors; | ||
71 | + | ||
72 | +import static org.onlab.util.Tools.groupedThreads; | ||
50 | import static org.slf4j.LoggerFactory.getLogger; | 73 | import static org.slf4j.LoggerFactory.getLogger; |
51 | 74 | ||
52 | /** | 75 | /** |
53 | - * Corsa pipeline handler. | 76 | + * OpenvSwitch emulation of the Corsa pipeline handler. |
54 | */ | 77 | */ |
55 | public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner { | 78 | public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner { |
56 | 79 | ||
... | @@ -63,17 +86,45 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli | ... | @@ -63,17 +86,45 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli |
63 | private ServiceDirectory serviceDirectory; | 86 | private ServiceDirectory serviceDirectory; |
64 | private FlowRuleService flowRuleService; | 87 | private FlowRuleService flowRuleService; |
65 | private CoreService coreService; | 88 | private CoreService coreService; |
89 | + private GroupService groupService; | ||
90 | + private FlowObjectiveStore flowObjectiveStore; | ||
66 | private DeviceId deviceId; | 91 | private DeviceId deviceId; |
67 | private ApplicationId appId; | 92 | private ApplicationId appId; |
68 | 93 | ||
94 | + private KryoNamespace appKryo = new KryoNamespace.Builder() | ||
95 | + .register(GroupKey.class) | ||
96 | + .register(DefaultGroupKey.class) | ||
97 | + .register(CorsaGroup.class) | ||
98 | + .register(byte[].class) | ||
99 | + .build(); | ||
100 | + | ||
101 | + private Cache<GroupKey, NextObjective> pendingGroups; | ||
102 | + | ||
103 | + private ScheduledExecutorService groupChecker = | ||
104 | + Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", | ||
105 | + "ovs-corsa-%d")); | ||
106 | + | ||
69 | @Override | 107 | @Override |
70 | public void init(DeviceId deviceId, PipelinerContext context) { | 108 | public void init(DeviceId deviceId, PipelinerContext context) { |
71 | this.serviceDirectory = context.directory(); | 109 | this.serviceDirectory = context.directory(); |
72 | this.deviceId = deviceId; | 110 | this.deviceId = deviceId; |
73 | 111 | ||
112 | + pendingGroups = CacheBuilder.newBuilder() | ||
113 | + .expireAfterWrite(20, TimeUnit.SECONDS) | ||
114 | + .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> { | ||
115 | + if (notification.getCause() == RemovalCause.EXPIRED) { | ||
116 | + fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED); | ||
117 | + } | ||
118 | + }).build(); | ||
119 | + | ||
120 | + groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); | ||
74 | 121 | ||
75 | coreService = serviceDirectory.get(CoreService.class); | 122 | coreService = serviceDirectory.get(CoreService.class); |
76 | flowRuleService = serviceDirectory.get(FlowRuleService.class); | 123 | flowRuleService = serviceDirectory.get(FlowRuleService.class); |
124 | + groupService = serviceDirectory.get(GroupService.class); | ||
125 | + flowObjectiveStore = context.store(); | ||
126 | + | ||
127 | + groupService.addListener(new InnerGroupListener()); | ||
77 | 128 | ||
78 | appId = coreService.registerApplication( | 129 | appId = coreService.registerApplication( |
79 | "org.onosproject.driver.OVSCorsaPipeline"); | 130 | "org.onosproject.driver.OVSCorsaPipeline"); |
... | @@ -82,33 +133,159 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli | ... | @@ -82,33 +133,159 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli |
82 | } | 133 | } |
83 | 134 | ||
84 | @Override | 135 | @Override |
85 | - public Future<Boolean> filter(Collection<FilteringObjective> filteringObjectives) { | 136 | + public void filter(FilteringObjective filteringObjective) { |
86 | - Collection<Future<Boolean>> results = Sets.newHashSet(); | 137 | + if (filteringObjective.type() == FilteringObjective.Type.PERMIT) { |
87 | - filteringObjectives.stream() | 138 | + processFilter(filteringObjective, |
88 | - .filter(obj -> obj.type() == FilteringObjective.Type.PERMIT) | 139 | + filteringObjective.op() == Objective.Operation.ADD, |
89 | - .forEach(filtobj -> results.add(processFilter(filtobj, | 140 | + filteringObjective.appId()); |
90 | - filtobj.op() == Objective.Operation.ADD, | 141 | + } else { |
91 | - filtobj.appId() | 142 | + fail(filteringObjective, ObjectiveError.UNSUPPORTED); |
92 | - ))); | 143 | + } |
93 | - | 144 | + } |
94 | - //TODO: return something more helpful/sensible in the future (no pun intended) | 145 | + |
95 | - return results.iterator().next(); | 146 | + @Override |
147 | + public void forward(ForwardingObjective fwd) { | ||
148 | + Collection<FlowRule> rules; | ||
149 | + FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); | ||
150 | + | ||
151 | + rules = processForward(fwd); | ||
152 | + switch (fwd.op()) { | ||
153 | + case ADD: | ||
154 | + rules.stream() | ||
155 | + .filter(rule -> rule != null) | ||
156 | + .forEach(flowBuilder::add); | ||
157 | + break; | ||
158 | + case REMOVE: | ||
159 | + rules.stream() | ||
160 | + .filter(rule -> rule != null) | ||
161 | + .forEach(flowBuilder::remove); | ||
162 | + break; | ||
163 | + default: | ||
164 | + fail(fwd, ObjectiveError.UNKNOWN); | ||
165 | + log.warn("Unknown forwarding type {}", fwd.op()); | ||
166 | + } | ||
167 | + | ||
168 | + | ||
169 | + flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() { | ||
170 | + @Override | ||
171 | + public void onSuccess(FlowRuleOperations ops) { | ||
172 | + pass(fwd); | ||
173 | + } | ||
174 | + | ||
175 | + @Override | ||
176 | + public void onError(FlowRuleOperations ops) { | ||
177 | + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED); | ||
178 | + } | ||
179 | + })); | ||
180 | + | ||
181 | + } | ||
182 | + | ||
183 | + @Override | ||
184 | + public void next(NextObjective nextObjective) { | ||
185 | + switch (nextObjective.type()) { | ||
186 | + case SIMPLE: | ||
187 | + Collection<TrafficTreatment> treatments = nextObjective.next(); | ||
188 | + if (treatments.size() == 1) { | ||
189 | + TrafficTreatment treatment = treatments.iterator().next(); | ||
190 | + GroupBucket bucket = | ||
191 | + DefaultGroupBucket.createIndirectGroupBucket(treatment); | ||
192 | + final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id())); | ||
193 | + GroupDescription groupDescription | ||
194 | + = new DefaultGroupDescription(deviceId, | ||
195 | + GroupDescription.Type.INDIRECT, | ||
196 | + new GroupBuckets(Collections | ||
197 | + .singletonList(bucket)), | ||
198 | + key, | ||
199 | + nextObjective.appId()); | ||
200 | + groupService.addGroup(groupDescription); | ||
201 | + pendingGroups.put(key, nextObjective); | ||
202 | + } | ||
203 | + break; | ||
204 | + case HASHED: | ||
205 | + case BROADCAST: | ||
206 | + case FAILOVER: | ||
207 | + fail(nextObjective, ObjectiveError.UNSUPPORTED); | ||
208 | + log.warn("Unsupported next objective type {}", nextObjective.type()); | ||
209 | + break; | ||
210 | + default: | ||
211 | + fail(nextObjective, ObjectiveError.UNKNOWN); | ||
212 | + log.warn("Unknown next objective type {}", nextObjective.type()); | ||
213 | + } | ||
214 | + | ||
215 | + } | ||
216 | + | ||
217 | + private Collection<FlowRule> processForward(ForwardingObjective fwd) { | ||
218 | + switch (fwd.flag()) { | ||
219 | + case SPECIFIC: | ||
220 | + return processSpecific(fwd); | ||
221 | + case VERSATILE: | ||
222 | + return processVersatile(fwd); | ||
223 | + default: | ||
224 | + fail(fwd, ObjectiveError.UNKNOWN); | ||
225 | + log.warn("Unknown forwarding flag {}", fwd.flag()); | ||
226 | + } | ||
227 | + return Collections.emptySet(); | ||
228 | + } | ||
229 | + | ||
230 | + private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { | ||
231 | + fail(fwd, ObjectiveError.UNSUPPORTED); | ||
232 | + return Collections.emptySet(); | ||
233 | + } | ||
234 | + | ||
235 | + private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { | ||
236 | + log.warn("Processing specific"); | ||
237 | + TrafficSelector selector = fwd.selector(); | ||
238 | + Criteria.EthTypeCriterion ethType = | ||
239 | + (Criteria.EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); | ||
240 | + if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) { | ||
241 | + fail(fwd, ObjectiveError.UNSUPPORTED); | ||
242 | + return Collections.emptySet(); | ||
243 | + } | ||
244 | + | ||
245 | + TrafficSelector filteredSelector = | ||
246 | + DefaultTrafficSelector.builder() | ||
247 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
248 | + .matchIPDst( | ||
249 | + ((Criteria.IPCriterion) | ||
250 | + selector.getCriterion(Criterion.Type.IPV4_DST)).ip()) | ||
251 | + .build(); | ||
252 | + | ||
253 | + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); | ||
254 | + | ||
255 | + GroupKey key = appKryo.deserialize(next.data()); | ||
256 | + | ||
257 | + Group group = groupService.getGroup(deviceId, key); | ||
258 | + | ||
259 | + if (group == null) { | ||
260 | + log.warn("The group left!"); | ||
261 | + fail(fwd, ObjectiveError.GROUPMISSING); | ||
262 | + return Collections.emptySet(); | ||
263 | + } | ||
264 | + | ||
265 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
266 | + .group(group.id()) | ||
267 | + .build(); | ||
268 | + | ||
269 | + return Collections.singletonList( | ||
270 | + new DefaultFlowRule(deviceId, filteredSelector, treatment, | ||
271 | + fwd.priority(), fwd.appId(), 0, fwd.permanent(), | ||
272 | + FlowRule.Type.IP)); | ||
96 | 273 | ||
97 | } | 274 | } |
98 | 275 | ||
99 | - private Future<Boolean> processFilter(FilteringObjective filt, boolean install, | 276 | + private void processFilter(FilteringObjective filt, boolean install, |
100 | ApplicationId applicationId) { | 277 | ApplicationId applicationId) { |
101 | - SettableFuture<Boolean> result = SettableFuture.create(); | ||
102 | // This driver only processes filtering criteria defined with switch | 278 | // This driver only processes filtering criteria defined with switch |
103 | // ports as the key | 279 | // ports as the key |
104 | - Criteria.PortCriterion p = null; | 280 | + Criteria.PortCriterion p; |
105 | if (!filt.key().equals(Criteria.dummy()) && | 281 | if (!filt.key().equals(Criteria.dummy()) && |
106 | filt.key().type() == Criterion.Type.IN_PORT) { | 282 | filt.key().type() == Criterion.Type.IN_PORT) { |
107 | p = (Criteria.PortCriterion) filt.key(); | 283 | p = (Criteria.PortCriterion) filt.key(); |
108 | } else { | 284 | } else { |
109 | log.warn("No key defined in filtering objective from app: {}. Not" | 285 | log.warn("No key defined in filtering objective from app: {}. Not" |
110 | + "processing filtering objective", applicationId); | 286 | + "processing filtering objective", applicationId); |
111 | - return null; | 287 | + fail(filt, ObjectiveError.UNKNOWN); |
288 | + return; | ||
112 | } | 289 | } |
113 | // convert filtering conditions for switch-intfs into flowrules | 290 | // convert filtering conditions for switch-intfs into flowrules |
114 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); | 291 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); |
... | @@ -154,45 +331,45 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli | ... | @@ -154,45 +331,45 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli |
154 | } else { | 331 | } else { |
155 | log.warn("Driver does not currently process filtering condition" | 332 | log.warn("Driver does not currently process filtering condition" |
156 | + " of type: {}", c.type()); | 333 | + " of type: {}", c.type()); |
334 | + fail(filt, ObjectiveError.UNSUPPORTED); | ||
157 | } | 335 | } |
158 | } | 336 | } |
159 | // apply filtering flow rules | 337 | // apply filtering flow rules |
160 | flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { | 338 | flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { |
161 | @Override | 339 | @Override |
162 | public void onSuccess(FlowRuleOperations ops) { | 340 | public void onSuccess(FlowRuleOperations ops) { |
163 | - result.set(true); | 341 | + pass(filt); |
164 | log.info("Provisioned default table for bgp router"); | 342 | log.info("Provisioned default table for bgp router"); |
165 | } | 343 | } |
166 | 344 | ||
167 | @Override | 345 | @Override |
168 | public void onError(FlowRuleOperations ops) { | 346 | public void onError(FlowRuleOperations ops) { |
169 | - result.set(false); | 347 | + fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED); |
170 | log.info("Failed to provision default table for bgp router"); | 348 | log.info("Failed to provision default table for bgp router"); |
171 | } | 349 | } |
172 | })); | 350 | })); |
173 | - | ||
174 | - return result; | ||
175 | } | 351 | } |
176 | 352 | ||
177 | - @Override | 353 | + private void pass(Objective obj) { |
178 | - public Future<Boolean> forward(Collection<ForwardingObjective> forwardObjectives) { | 354 | + if (obj.context().isPresent()) { |
179 | - return null; | 355 | + obj.context().get().onSuccess(obj); |
356 | + } | ||
180 | } | 357 | } |
181 | 358 | ||
182 | - @Override | 359 | + private void fail(Objective obj, ObjectiveError error) { |
183 | - public Future<Boolean> next(Collection<NextObjective> nextObjectives) { | 360 | + if (obj.context().isPresent()) { |
184 | - return null; | 361 | + obj.context().get().onError(obj, error); |
362 | + } | ||
185 | } | 363 | } |
186 | 364 | ||
187 | private void pushDefaultRules() { | 365 | private void pushDefaultRules() { |
188 | - boolean install = true; | 366 | + processTableZero(true); |
189 | - processTableZero(install); | 367 | + processTableOne(true); |
190 | - processTableOne(install); | 368 | + processTableTwo(true); |
191 | - processTableTwo(install); | 369 | + processTableFour(true); |
192 | - processTableFour(install); | 370 | + processTableFive(true); |
193 | - processTableFive(install); | 371 | + processTableSix(true); |
194 | - processTableSix(install); | 372 | + processTableNine(true); |
195 | - processTableNine(install); | ||
196 | } | 373 | } |
197 | 374 | ||
198 | private void processTableZero(boolean install) { | 375 | private void processTableZero(boolean install) { |
... | @@ -447,4 +624,59 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli | ... | @@ -447,4 +624,59 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli |
447 | })); | 624 | })); |
448 | } | 625 | } |
449 | 626 | ||
627 | + private class InnerGroupListener implements GroupListener { | ||
628 | + @Override | ||
629 | + public void event(GroupEvent event) { | ||
630 | + if (event.type() == GroupEvent.Type.GROUP_ADDED) { | ||
631 | + GroupKey key = event.subject().appCookie(); | ||
632 | + | ||
633 | + NextObjective obj = pendingGroups.getIfPresent(key); | ||
634 | + if (obj != null) { | ||
635 | + flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key)); | ||
636 | + pass(obj); | ||
637 | + pendingGroups.invalidate(key); | ||
638 | + } | ||
639 | + } | ||
640 | + } | ||
641 | + } | ||
642 | + | ||
643 | + | ||
644 | + private class GroupChecker implements Runnable { | ||
645 | + | ||
646 | + @Override | ||
647 | + public void run() { | ||
648 | + Set<GroupKey> keys = pendingGroups.asMap().keySet().stream() | ||
649 | + .filter(key -> groupService.getGroup(deviceId, key) != null) | ||
650 | + .collect(Collectors.toSet()); | ||
651 | + | ||
652 | + keys.stream().forEach(key -> { | ||
653 | + NextObjective obj = pendingGroups.getIfPresent(key); | ||
654 | + if (obj == null) { | ||
655 | + return; | ||
656 | + } | ||
657 | + pass(obj); | ||
658 | + pendingGroups.invalidate(key); | ||
659 | + flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key)); | ||
660 | + }); | ||
661 | + } | ||
662 | + } | ||
663 | + | ||
664 | + private class CorsaGroup implements NextGroup { | ||
665 | + | ||
666 | + private final GroupKey key; | ||
667 | + | ||
668 | + public CorsaGroup(GroupKey key) { | ||
669 | + this.key = key; | ||
670 | + } | ||
671 | + | ||
672 | + public GroupKey key() { | ||
673 | + return key; | ||
674 | + } | ||
675 | + | ||
676 | + @Override | ||
677 | + public byte[] data() { | ||
678 | + return appKryo.serialize(key); | ||
679 | + } | ||
680 | + | ||
681 | + } | ||
450 | } | 682 | } | ... | ... |
... | @@ -19,7 +19,7 @@ | ... | @@ -19,7 +19,7 @@ |
19 | <behaviour api="org.onosproject.net.behaviour.Pipeliner" | 19 | <behaviour api="org.onosproject.net.behaviour.Pipeliner" |
20 | impl="org.onosproject.driver.pipeline.DefaultSingleTablePipeline"/> | 20 | impl="org.onosproject.driver.pipeline.DefaultSingleTablePipeline"/> |
21 | </driver> | 21 | </driver> |
22 | - <driver name="ovs-corsa" manufacturer="Nicira, Inc." hwVersion="Open vSwitch" swVersion="2.3.0"> | 22 | + <driver name="ovs-corsa" manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0"> |
23 | <behaviour api="org.onosproject.net.behaviour.Pipeliner" | 23 | <behaviour api="org.onosproject.net.behaviour.Pipeliner" |
24 | impl="org.onosproject.driver.pipeline.OVSCorsaPipeline"/> | 24 | impl="org.onosproject.driver.pipeline.OVSCorsaPipeline"/> |
25 | </driver> | 25 | </driver> | ... | ... |
providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
... | @@ -195,7 +195,6 @@ public class FlowModBuilderVer13 extends FlowModBuilder { | ... | @@ -195,7 +195,6 @@ public class FlowModBuilderVer13 extends FlowModBuilder { |
195 | for (Instruction i : treatments) { | 195 | for (Instruction i : treatments) { |
196 | switch (i.type()) { | 196 | switch (i.type()) { |
197 | case DROP: | 197 | case DROP: |
198 | - log.warn("Saw drop action; assigning drop action"); | ||
199 | return new LinkedList<>(); | 198 | return new LinkedList<>(); |
200 | case L0MODIFICATION: | 199 | case L0MODIFICATION: |
201 | actions.add(buildL0Modification(i)); | 200 | actions.add(buildL0Modification(i)); | ... | ... |
-
Please register or login to post a comment