Committed by
Gerrit Code Review
Implementation of new Flow Subsystem:
The subsystem no longer returns futures for tracking completion of work. Notifications are explicitely returned via a call back mechanism. Also, the subsystem is now asynchronous. Change-Id: I1a4cef931c24820f9ae9ed9a5398f163f05dfbc9 more flowservice improvements Change-Id: I5c9c1b6be4b2ebfa523b64f6f52e7634b7d3e05f more flowservice impl Change-Id: I05f6774460effb53ced8c36844bcda2f8f6c096f Manager to store functional (at least i believe it) Change-Id: I09b04989bd1004c98fe0bafed4c76714b9155d53 flow subsystem functional: need to fix unit tests Change-Id: I1667f25b91320f625a03e5e1d5e92823184d9de0 flow subsystem functional Change-Id: I429b3335c16d4fc16f5d55f233dd37c4d1d6111d finished refactor of flow subsystem Change-Id: I1899abc6ff6a974a2018d936cc555049c70a6804 fix for null flow provider to use new api Change-Id: If2fd9bd5baf74d9c61c5c8085cef8bc2d204cbdc
Showing
34 changed files
with
1228 additions
and
947 deletions
... | @@ -19,29 +19,30 @@ package org.onosproject.cli.net; | ... | @@ -19,29 +19,30 @@ package org.onosproject.cli.net; |
19 | import com.fasterxml.jackson.databind.ObjectMapper; | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | import com.fasterxml.jackson.databind.node.ArrayNode; | 20 | import com.fasterxml.jackson.databind.node.ArrayNode; |
21 | import com.fasterxml.jackson.databind.node.ObjectNode; | 21 | import com.fasterxml.jackson.databind.node.ObjectNode; |
22 | +import com.google.common.base.Stopwatch; | ||
22 | import com.google.common.collect.Lists; | 23 | import com.google.common.collect.Lists; |
23 | -import com.google.common.collect.Sets; | 24 | +import org.apache.commons.lang.math.RandomUtils; |
24 | import org.apache.karaf.shell.commands.Argument; | 25 | import org.apache.karaf.shell.commands.Argument; |
25 | import org.apache.karaf.shell.commands.Command; | 26 | import org.apache.karaf.shell.commands.Command; |
27 | +import org.onlab.packet.MacAddress; | ||
26 | import org.onosproject.cli.AbstractShellCommand; | 28 | import org.onosproject.cli.AbstractShellCommand; |
29 | +import org.onosproject.core.ApplicationId; | ||
30 | +import org.onosproject.core.CoreService; | ||
27 | import org.onosproject.net.Device; | 31 | import org.onosproject.net.Device; |
28 | import org.onosproject.net.PortNumber; | 32 | import org.onosproject.net.PortNumber; |
29 | import org.onosproject.net.device.DeviceService; | 33 | import org.onosproject.net.device.DeviceService; |
30 | -import org.onosproject.net.flow.CompletedBatchOperation; | ||
31 | import org.onosproject.net.flow.DefaultFlowRule; | 34 | import org.onosproject.net.flow.DefaultFlowRule; |
32 | import org.onosproject.net.flow.DefaultTrafficSelector; | 35 | import org.onosproject.net.flow.DefaultTrafficSelector; |
33 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 36 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
34 | -import org.onosproject.net.flow.FlowRuleBatchEntry; | 37 | +import org.onosproject.net.flow.FlowRuleOperations; |
35 | -import org.onosproject.net.flow.FlowRuleBatchOperation; | 38 | +import org.onosproject.net.flow.FlowRuleOperationsContext; |
36 | import org.onosproject.net.flow.FlowRuleService; | 39 | import org.onosproject.net.flow.FlowRuleService; |
37 | import org.onosproject.net.flow.TrafficSelector; | 40 | import org.onosproject.net.flow.TrafficSelector; |
38 | import org.onosproject.net.flow.TrafficTreatment; | 41 | import org.onosproject.net.flow.TrafficTreatment; |
39 | -import org.onlab.packet.MacAddress; | ||
40 | 42 | ||
41 | import java.util.ArrayList; | 43 | import java.util.ArrayList; |
42 | -import java.util.Set; | 44 | +import java.util.concurrent.CountDownLatch; |
43 | -import java.util.concurrent.ExecutionException; | 45 | +import java.util.concurrent.TimeUnit; |
44 | -import java.util.concurrent.Future; | ||
45 | 46 | ||
46 | /** | 47 | /** |
47 | * Installs many many flows. | 48 | * Installs many many flows. |
... | @@ -50,6 +51,8 @@ import java.util.concurrent.Future; | ... | @@ -50,6 +51,8 @@ import java.util.concurrent.Future; |
50 | description = "Installs a number of test flow rules - for testing only") | 51 | description = "Installs a number of test flow rules - for testing only") |
51 | public class AddFlowsCommand extends AbstractShellCommand { | 52 | public class AddFlowsCommand extends AbstractShellCommand { |
52 | 53 | ||
54 | + private CountDownLatch latch; | ||
55 | + | ||
53 | @Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device", | 56 | @Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device", |
54 | required = true, multiValued = false) | 57 | required = true, multiValued = false) |
55 | String flows = null; | 58 | String flows = null; |
... | @@ -63,6 +66,9 @@ public class AddFlowsCommand extends AbstractShellCommand { | ... | @@ -63,6 +66,9 @@ public class AddFlowsCommand extends AbstractShellCommand { |
63 | 66 | ||
64 | FlowRuleService flowService = get(FlowRuleService.class); | 67 | FlowRuleService flowService = get(FlowRuleService.class); |
65 | DeviceService deviceService = get(DeviceService.class); | 68 | DeviceService deviceService = get(DeviceService.class); |
69 | + CoreService coreService = get(CoreService.class); | ||
70 | + | ||
71 | + ApplicationId appId = coreService.registerApplication("onos.test.flow.installer"); | ||
66 | 72 | ||
67 | int flowsPerDevice = Integer.parseInt(flows); | 73 | int flowsPerDevice = Integer.parseInt(flows); |
68 | int num = Integer.parseInt(numOfRuns); | 74 | int num = Integer.parseInt(numOfRuns); |
... | @@ -70,49 +76,73 @@ public class AddFlowsCommand extends AbstractShellCommand { | ... | @@ -70,49 +76,73 @@ public class AddFlowsCommand extends AbstractShellCommand { |
70 | ArrayList<Long> results = Lists.newArrayList(); | 76 | ArrayList<Long> results = Lists.newArrayList(); |
71 | Iterable<Device> devices = deviceService.getDevices(); | 77 | Iterable<Device> devices = deviceService.getDevices(); |
72 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() | 78 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
73 | - .setOutput(PortNumber.portNumber(1)).build(); | 79 | + .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build(); |
74 | TrafficSelector.Builder sbuilder; | 80 | TrafficSelector.Builder sbuilder; |
75 | - Set<FlowRuleBatchEntry> rules = Sets.newHashSet(); | 81 | + FlowRuleOperations.Builder rules = FlowRuleOperations.builder(); |
76 | - Set<FlowRuleBatchEntry> remove = Sets.newHashSet(); | 82 | + FlowRuleOperations.Builder remove = FlowRuleOperations.builder(); |
83 | + | ||
77 | for (Device d : devices) { | 84 | for (Device d : devices) { |
78 | for (int i = 0; i < flowsPerDevice; i++) { | 85 | for (int i = 0; i < flowsPerDevice; i++) { |
79 | sbuilder = DefaultTrafficSelector.builder(); | 86 | sbuilder = DefaultTrafficSelector.builder(); |
80 | - sbuilder.matchEthSrc(MacAddress.valueOf(i)) | 87 | + |
81 | - .matchEthDst(MacAddress.valueOf(Integer.MAX_VALUE - i)); | 88 | + sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i)) |
82 | - rules.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.ADD, | 89 | + .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt())); |
83 | - new DefaultFlowRule(d.id(), sbuilder.build(), treatment, | 90 | + |
84 | - 100, (long) 0, 10, false))); | 91 | + |
85 | - remove.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.REMOVE, | 92 | + int randomPriority = RandomUtils.nextInt(); |
86 | - new DefaultFlowRule(d.id(), sbuilder.build(), treatment, | 93 | + rules.add(new DefaultFlowRule(d.id(), sbuilder.build(), treatment, |
87 | - 100, (long) 0, 10, false))); | 94 | + randomPriority, appId, 10, false)); |
95 | + remove.remove(new DefaultFlowRule(d.id(), sbuilder.build(), treatment, | ||
96 | + randomPriority, appId, 10, false)); | ||
88 | 97 | ||
89 | } | 98 | } |
90 | } | 99 | } |
91 | - boolean isSuccess = true; | 100 | + |
92 | for (int i = 0; i < num; i++) { | 101 | for (int i = 0; i < num; i++) { |
93 | - long startTime = System.currentTimeMillis(); | 102 | + |
94 | - Future<CompletedBatchOperation> op = flowService.applyBatch( | 103 | + latch = new CountDownLatch(2); |
95 | - new FlowRuleBatchOperation(rules)); | 104 | + flowService.apply(rules.build(new FlowRuleOperationsContext() { |
105 | + | ||
106 | + private final Stopwatch timer = Stopwatch.createStarted(); | ||
107 | + | ||
108 | + @Override | ||
109 | + public void onSuccess(FlowRuleOperations ops) { | ||
110 | + | ||
111 | + timer.stop(); | ||
112 | + results.add(timer.elapsed(TimeUnit.MILLISECONDS)); | ||
113 | + if (results.size() == num) { | ||
114 | + if (outputJson()) { | ||
115 | + print("%s", json(new ObjectMapper(), true, results)); | ||
116 | + } else { | ||
117 | + printTime(true, results); | ||
118 | + } | ||
119 | + } | ||
120 | + latch.countDown(); | ||
121 | + } | ||
122 | + })); | ||
123 | + | ||
124 | + | ||
125 | + flowService.apply(remove.build(new FlowRuleOperationsContext() { | ||
126 | + @Override | ||
127 | + public void onSuccess(FlowRuleOperations ops) { | ||
128 | + latch.countDown(); | ||
129 | + } | ||
130 | + })); | ||
96 | try { | 131 | try { |
97 | - isSuccess &= op.get().isSuccess(); | 132 | + latch.await(); |
98 | - } catch (InterruptedException | ExecutionException e) { | 133 | + } catch (InterruptedException e) { |
99 | e.printStackTrace(); | 134 | e.printStackTrace(); |
100 | } | 135 | } |
101 | - long endTime = System.currentTimeMillis(); | 136 | + |
102 | - results.add(endTime - startTime); | ||
103 | - flowService.applyBatch( | ||
104 | - new FlowRuleBatchOperation(remove)); | ||
105 | - } | ||
106 | - if (outputJson()) { | ||
107 | - print("%s", json(new ObjectMapper(), isSuccess, results)); | ||
108 | - } else { | ||
109 | - printTime(isSuccess, results); | ||
110 | } | 137 | } |
111 | 138 | ||
112 | 139 | ||
113 | 140 | ||
141 | + | ||
114 | } | 142 | } |
115 | 143 | ||
144 | + | ||
145 | + | ||
116 | private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) { | 146 | private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) { |
117 | ObjectNode result = mapper.createObjectNode(); | 147 | ObjectNode result = mapper.createObjectNode(); |
118 | result.put("Success", isSuccess); | 148 | result.put("Success", isSuccess); | ... | ... |
... | @@ -21,6 +21,7 @@ import java.util.Set; | ... | @@ -21,6 +21,7 @@ import java.util.Set; |
21 | 21 | ||
22 | import com.google.common.base.MoreObjects; | 22 | import com.google.common.base.MoreObjects; |
23 | import com.google.common.collect.ImmutableSet; | 23 | import com.google.common.collect.ImmutableSet; |
24 | +import org.onosproject.net.DeviceId; | ||
24 | 25 | ||
25 | /** | 26 | /** |
26 | * Representation of a completed flow rule batch operation. | 27 | * Representation of a completed flow rule batch operation. |
... | @@ -30,19 +31,22 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { | ... | @@ -30,19 +31,22 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { |
30 | private final boolean success; | 31 | private final boolean success; |
31 | private final Set<FlowRule> failures; | 32 | private final Set<FlowRule> failures; |
32 | private final Set<Long> failedIds; | 33 | private final Set<Long> failedIds; |
34 | + private final DeviceId deviceId; | ||
33 | 35 | ||
34 | /** | 36 | /** |
35 | * Creates a new batch completion result. | 37 | * Creates a new batch completion result. |
36 | * | 38 | * |
37 | - * @param success indicates whether the completion is successful. | 39 | + * @param success indicates whether the completion is successful |
38 | * @param failures set of any failures encountered | 40 | * @param failures set of any failures encountered |
39 | * @param failedIds (optional) set of failed operation ids | 41 | * @param failedIds (optional) set of failed operation ids |
42 | + * @param deviceId the device this operation completed for | ||
40 | */ | 43 | */ |
41 | public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures, | 44 | public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures, |
42 | - Set<Long> failedIds) { | 45 | + Set<Long> failedIds, DeviceId deviceId) { |
43 | this.success = success; | 46 | this.success = success; |
44 | this.failures = ImmutableSet.copyOf(failures); | 47 | this.failures = ImmutableSet.copyOf(failures); |
45 | this.failedIds = ImmutableSet.copyOf(failedIds); | 48 | this.failedIds = ImmutableSet.copyOf(failedIds); |
49 | + this.deviceId = deviceId; | ||
46 | } | 50 | } |
47 | 51 | ||
48 | /** | 52 | /** |
... | @@ -51,10 +55,12 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { | ... | @@ -51,10 +55,12 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { |
51 | * @param success indicates whether the completion is successful. | 55 | * @param success indicates whether the completion is successful. |
52 | * @param failures set of any failures encountered | 56 | * @param failures set of any failures encountered |
53 | */ | 57 | */ |
54 | - public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures) { | 58 | + public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures, |
59 | + DeviceId deviceId) { | ||
55 | this.success = success; | 60 | this.success = success; |
56 | this.failures = ImmutableSet.copyOf(failures); | 61 | this.failures = ImmutableSet.copyOf(failures); |
57 | this.failedIds = Collections.emptySet(); | 62 | this.failedIds = Collections.emptySet(); |
63 | + this.deviceId = deviceId; | ||
58 | } | 64 | } |
59 | 65 | ||
60 | 66 | ||
... | @@ -73,12 +79,17 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { | ... | @@ -73,12 +79,17 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> { |
73 | return failedIds; | 79 | return failedIds; |
74 | } | 80 | } |
75 | 81 | ||
82 | + public DeviceId deviceId() { | ||
83 | + return this.deviceId; | ||
84 | + } | ||
85 | + | ||
76 | @Override | 86 | @Override |
77 | public String toString() { | 87 | public String toString() { |
78 | return MoreObjects.toStringHelper(getClass()) | 88 | return MoreObjects.toStringHelper(getClass()) |
79 | .add("success?", success) | 89 | .add("success?", success) |
80 | .add("failedItems", failures) | 90 | .add("failedItems", failures) |
81 | .add("failedIds", failedIds) | 91 | .add("failedIds", failedIds) |
92 | + .add("deviceId", deviceId) | ||
82 | .toString(); | 93 | .toString(); |
83 | } | 94 | } |
84 | } | 95 | } | ... | ... |
... | @@ -16,12 +16,14 @@ | ... | @@ -16,12 +16,14 @@ |
16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
17 | 17 | ||
18 | import org.onosproject.event.AbstractEvent; | 18 | import org.onosproject.event.AbstractEvent; |
19 | +import org.onosproject.net.DeviceId; | ||
19 | 20 | ||
20 | /** | 21 | /** |
21 | * Describes flow rule batch event. | 22 | * Describes flow rule batch event. |
22 | */ | 23 | */ |
23 | public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> { | 24 | public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> { |
24 | 25 | ||
26 | + | ||
25 | /** | 27 | /** |
26 | * Type of flow rule events. | 28 | * Type of flow rule events. |
27 | */ | 29 | */ |
... | @@ -42,14 +44,17 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T | ... | @@ -42,14 +44,17 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T |
42 | } | 44 | } |
43 | 45 | ||
44 | private final CompletedBatchOperation result; | 46 | private final CompletedBatchOperation result; |
47 | + private final DeviceId deviceId; | ||
45 | 48 | ||
46 | /** | 49 | /** |
47 | * Constructs a new FlowRuleBatchEvent. | 50 | * Constructs a new FlowRuleBatchEvent. |
48 | - * @param request batch operation request. | 51 | + * |
52 | + * @param request batch operation request | ||
53 | + * @param deviceId the device this batch will be processed on | ||
49 | * @return event. | 54 | * @return event. |
50 | */ | 55 | */ |
51 | - public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request) { | 56 | + public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request, DeviceId deviceId) { |
52 | - FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, null); | 57 | + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, deviceId); |
53 | return event; | 58 | return event; |
54 | } | 59 | } |
55 | 60 | ||
... | @@ -73,13 +78,36 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T | ... | @@ -73,13 +78,36 @@ public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.T |
73 | } | 78 | } |
74 | 79 | ||
75 | /** | 80 | /** |
81 | + * Returns the deviceId for this batch. | ||
82 | + * @return device id | ||
83 | + */ | ||
84 | + public DeviceId deviceId() { | ||
85 | + return deviceId; | ||
86 | + } | ||
87 | + | ||
88 | + /** | ||
76 | * Creates an event of a given type and for the specified flow rule batch. | 89 | * Creates an event of a given type and for the specified flow rule batch. |
77 | * | 90 | * |
78 | * @param type flow rule batch event type | 91 | * @param type flow rule batch event type |
79 | - * @param batch event flow rule batch subject | 92 | + * @param request event flow rule batch subject |
93 | + * @param result the result of the batch operation | ||
80 | */ | 94 | */ |
81 | private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) { | 95 | private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) { |
82 | super(type, request); | 96 | super(type, request); |
83 | this.result = result; | 97 | this.result = result; |
98 | + this.deviceId = result.deviceId(); | ||
99 | + } | ||
100 | + | ||
101 | + /** | ||
102 | + * Creates an event of a given type and for the specified flow rule batch. | ||
103 | + * | ||
104 | + * @param type flow rule batch event type | ||
105 | + * @param request event flow rule batch subject | ||
106 | + * @param deviceId the device id for this batch | ||
107 | + */ | ||
108 | + private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, DeviceId deviceId) { | ||
109 | + super(type, request); | ||
110 | + this.result = null; | ||
111 | + this.deviceId = deviceId; | ||
84 | } | 112 | } |
85 | } | 113 | } | ... | ... |
... | @@ -15,12 +15,37 @@ | ... | @@ -15,12 +15,37 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
17 | 17 | ||
18 | +import org.onosproject.net.DeviceId; | ||
19 | + | ||
18 | import java.util.Collection; | 20 | import java.util.Collection; |
19 | 21 | ||
22 | +/** | ||
23 | + * Class used with the flow subsystem to process per device | ||
24 | + * batches. | ||
25 | + */ | ||
20 | public class FlowRuleBatchOperation | 26 | public class FlowRuleBatchOperation |
21 | extends BatchOperation<FlowRuleBatchEntry> { | 27 | extends BatchOperation<FlowRuleBatchEntry> { |
22 | 28 | ||
23 | - public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations) { | 29 | + /** |
30 | + * This id is used to cary to id of the original | ||
31 | + * FlowOperations and track where this batch operation | ||
32 | + * came from. The id is unique cluster wide. | ||
33 | + */ | ||
34 | + private final long id; | ||
35 | + private final DeviceId deviceId; | ||
36 | + | ||
37 | + public FlowRuleBatchOperation(Collection<FlowRuleBatchEntry> operations, | ||
38 | + DeviceId deviceId, long flowOperationId) { | ||
24 | super(operations); | 39 | super(operations); |
40 | + this.id = flowOperationId; | ||
41 | + this.deviceId = deviceId; | ||
42 | + } | ||
43 | + | ||
44 | + public DeviceId deviceId() { | ||
45 | + return this.deviceId; | ||
46 | + } | ||
47 | + | ||
48 | + public long id() { | ||
49 | + return id; | ||
25 | } | 50 | } |
26 | } | 51 | } | ... | ... |
... | @@ -15,59 +15,43 @@ | ... | @@ -15,59 +15,43 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
17 | 17 | ||
18 | +import com.google.common.collect.Lists; | ||
19 | +import org.onosproject.net.DeviceId; | ||
20 | + | ||
18 | import java.util.Collections; | 21 | import java.util.Collections; |
19 | import java.util.List; | 22 | import java.util.List; |
23 | +import java.util.Set; | ||
20 | 24 | ||
21 | -import com.google.common.base.Function; | 25 | +public class FlowRuleBatchRequest { |
22 | -import com.google.common.collect.FluentIterable; | ||
23 | - | ||
24 | - | ||
25 | 26 | ||
26 | -import com.google.common.collect.Lists; | 27 | + /** |
28 | + * This id is used to cary to id of the original | ||
29 | + * FlowOperations and track where this batch operation | ||
30 | + * came from. The id is unique cluster wide. | ||
31 | + */ | ||
32 | + private final long batchId; | ||
27 | 33 | ||
28 | -public class FlowRuleBatchRequest { | 34 | + private final Set<FlowRuleBatchEntry> ops; |
29 | 35 | ||
30 | - private final int batchId; | ||
31 | - private final List<FlowRuleBatchEntry> toAdd; | ||
32 | - private final List<FlowRuleBatchEntry> toRemove; | ||
33 | 36 | ||
34 | - public FlowRuleBatchRequest(int batchId, List<FlowRuleBatchEntry> toAdd, | 37 | + public FlowRuleBatchRequest(long batchId, Set<FlowRuleBatchEntry> ops) { |
35 | - List<FlowRuleBatchEntry> toRemove) { | ||
36 | this.batchId = batchId; | 38 | this.batchId = batchId; |
37 | - this.toAdd = Collections.unmodifiableList(toAdd); | 39 | + this.ops = Collections.unmodifiableSet(ops); |
38 | - this.toRemove = Collections.unmodifiableList(toRemove); | ||
39 | - } | ||
40 | 40 | ||
41 | - public List<FlowRule> toAdd() { | ||
42 | - return FluentIterable.from(toAdd).transform( | ||
43 | - new Function<FlowRuleBatchEntry, FlowRule>() { | ||
44 | 41 | ||
45 | - @Override | ||
46 | - public FlowRule apply(FlowRuleBatchEntry input) { | ||
47 | - return input.target(); | ||
48 | } | 42 | } |
49 | - }).toList(); | ||
50 | - } | ||
51 | - | ||
52 | - public List<FlowRule> toRemove() { | ||
53 | - return FluentIterable.from(toRemove).transform( | ||
54 | - new Function<FlowRuleBatchEntry, FlowRule>() { | ||
55 | 43 | ||
56 | - @Override | 44 | + public Set<FlowRuleBatchEntry> ops() { |
57 | - public FlowRule apply(FlowRuleBatchEntry input) { | 45 | + return ops; |
58 | - return input.target(); | ||
59 | - } | ||
60 | - }).toList(); | ||
61 | } | 46 | } |
62 | 47 | ||
63 | - public FlowRuleBatchOperation asBatchOperation() { | 48 | + public FlowRuleBatchOperation asBatchOperation(DeviceId deviceId) { |
64 | List<FlowRuleBatchEntry> entries = Lists.newArrayList(); | 49 | List<FlowRuleBatchEntry> entries = Lists.newArrayList(); |
65 | - entries.addAll(toAdd); | 50 | + entries.addAll(ops); |
66 | - entries.addAll(toRemove); | 51 | + return new FlowRuleBatchOperation(entries, deviceId, batchId); |
67 | - return new FlowRuleBatchOperation(entries); | ||
68 | } | 52 | } |
69 | 53 | ||
70 | - public int batchId() { | 54 | + public long batchId() { |
71 | return batchId; | 55 | return batchId; |
72 | } | 56 | } |
73 | } | 57 | } | ... | ... |
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.flow; | ||
17 | + | ||
18 | +import com.google.common.base.MoreObjects; | ||
19 | + | ||
20 | +/** | ||
21 | + * Representation of an operation on a flow rule table. | ||
22 | + */ | ||
23 | +public class FlowRuleOperation { | ||
24 | + | ||
25 | + /** | ||
26 | + * Type of flow table operations. | ||
27 | + */ | ||
28 | + public enum Type { | ||
29 | + ADD, | ||
30 | + MODIFY, | ||
31 | + REMOVE | ||
32 | + } | ||
33 | + | ||
34 | + private final FlowRule rule; | ||
35 | + private final Type type; | ||
36 | + | ||
37 | + public FlowRuleOperation(FlowRule rule, Type type) { | ||
38 | + this.rule = rule; | ||
39 | + this.type = type; | ||
40 | + } | ||
41 | + | ||
42 | + /** | ||
43 | + * Returns the type of operation. | ||
44 | + * | ||
45 | + * @return type | ||
46 | + */ | ||
47 | + public Type type() { | ||
48 | + return type; | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * Returns the flow rule. | ||
53 | + * | ||
54 | + * @return flow rule | ||
55 | + */ | ||
56 | + public FlowRule rule() { | ||
57 | + return rule; | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public String toString() { | ||
62 | + return MoreObjects.toStringHelper(this) | ||
63 | + .add("rule", rule) | ||
64 | + .add("type", type) | ||
65 | + .toString(); | ||
66 | + } | ||
67 | +} |
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.flow; | ||
17 | + | ||
18 | +import com.google.common.base.MoreObjects; | ||
19 | +import com.google.common.collect.ImmutableList; | ||
20 | +import com.google.common.collect.ImmutableSet; | ||
21 | +import com.google.common.collect.Lists; | ||
22 | + | ||
23 | +import java.util.List; | ||
24 | +import java.util.Set; | ||
25 | + | ||
26 | +import static org.onosproject.net.flow.FlowRuleOperation.Type.*; | ||
27 | + | ||
28 | +/** | ||
29 | + * A batch of flow rule operations that are broken into stages. | ||
30 | + * TODO move this up to parent's package | ||
31 | + */ | ||
32 | +public class FlowRuleOperations { | ||
33 | + | ||
34 | + private final List<Set<FlowRuleOperation>> stages; | ||
35 | + private final FlowRuleOperationsContext callback; // TODO consider Optional | ||
36 | + | ||
37 | + private FlowRuleOperations(List<Set<FlowRuleOperation>> stages, | ||
38 | + FlowRuleOperationsContext cb) { | ||
39 | + this.stages = stages; | ||
40 | + this.callback = cb; | ||
41 | + } | ||
42 | + | ||
43 | + // kryo-constructor | ||
44 | + protected FlowRuleOperations() { | ||
45 | + this.stages = Lists.newArrayList(); | ||
46 | + this.callback = null; | ||
47 | + } | ||
48 | + | ||
49 | + /** | ||
50 | + * Returns the flow rule operations as sets of stages that should be | ||
51 | + * executed sequentially. | ||
52 | + * | ||
53 | + * @return flow rule stages | ||
54 | + */ | ||
55 | + public List<Set<FlowRuleOperation>> stages() { | ||
56 | + return stages; | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Returns the callback for this batch of operations. | ||
61 | + * | ||
62 | + * @return callback | ||
63 | + */ | ||
64 | + public FlowRuleOperationsContext callback() { | ||
65 | + return callback; | ||
66 | + } | ||
67 | + | ||
68 | + /** | ||
69 | + * Returns a new builder. | ||
70 | + * | ||
71 | + * @return new builder | ||
72 | + */ | ||
73 | + public static Builder builder() { | ||
74 | + return new Builder(); | ||
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + public String toString() { | ||
79 | + return MoreObjects.toStringHelper(this) | ||
80 | + .add("stages", stages) | ||
81 | + .toString(); | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * A builder for constructing flow rule operations. | ||
86 | + */ | ||
87 | + public static final class Builder { | ||
88 | + | ||
89 | + private final ImmutableList.Builder<Set<FlowRuleOperation>> listBuilder = ImmutableList.builder(); | ||
90 | + private ImmutableSet.Builder<FlowRuleOperation> currentStage = ImmutableSet.builder(); | ||
91 | + | ||
92 | + // prevent use of the default constructor outside of this file; use the above method | ||
93 | + private Builder() {} | ||
94 | + | ||
95 | + /** | ||
96 | + * Appends a flow rule add to the current stage. | ||
97 | + * | ||
98 | + * @param flowRule flow rule | ||
99 | + * @return this | ||
100 | + */ | ||
101 | + public Builder add(FlowRule flowRule) { | ||
102 | + currentStage.add(new FlowRuleOperation(flowRule, ADD)); | ||
103 | + return this; | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * Appends a flow rule modify to the current stage. | ||
108 | + * | ||
109 | + * @param flowRule flow rule | ||
110 | + * @return this | ||
111 | + */ | ||
112 | + public Builder modify(FlowRule flowRule) { | ||
113 | + currentStage.add(new FlowRuleOperation(flowRule, MODIFY)); | ||
114 | + return this; | ||
115 | + } | ||
116 | + | ||
117 | + /** | ||
118 | + * Appends a flow rule remove to the current stage. | ||
119 | + * | ||
120 | + * @param flowRule flow rule | ||
121 | + * @return this | ||
122 | + */ | ||
123 | + // FIXME this is confusing, consider renaming | ||
124 | + public Builder remove(FlowRule flowRule) { | ||
125 | + currentStage.add(new FlowRuleOperation(flowRule, REMOVE)); | ||
126 | + return this; | ||
127 | + } | ||
128 | + | ||
129 | + /** | ||
130 | + * Closes the current stage. | ||
131 | + */ | ||
132 | + private void closeStage() { | ||
133 | + ImmutableSet<FlowRuleOperation> stage = currentStage.build(); | ||
134 | + if (!stage.isEmpty()) { | ||
135 | + listBuilder.add(stage); | ||
136 | + } | ||
137 | + } | ||
138 | + | ||
139 | + /** | ||
140 | + * Closes the current stage and starts a new one. | ||
141 | + * | ||
142 | + * @return this | ||
143 | + */ | ||
144 | + public Builder newStage() { | ||
145 | + closeStage(); | ||
146 | + currentStage = ImmutableSet.builder(); | ||
147 | + return this; | ||
148 | + } | ||
149 | + | ||
150 | + /** | ||
151 | + * Builds the immutable flow rule operations. | ||
152 | + * | ||
153 | + * @return flow rule operations | ||
154 | + */ | ||
155 | + public FlowRuleOperations build() { | ||
156 | + return build(null); | ||
157 | + } | ||
158 | + | ||
159 | + /** | ||
160 | + * Builds the immutable flow rule operations. | ||
161 | + * | ||
162 | + * @param cb the callback to call when this operation completes | ||
163 | + * @return flow rule operations | ||
164 | + */ | ||
165 | + public FlowRuleOperations build(FlowRuleOperationsContext cb) { | ||
166 | + closeStage(); | ||
167 | + return new FlowRuleOperations(listBuilder.build(), cb); | ||
168 | + } | ||
169 | + } | ||
170 | +} |
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.flow; | ||
17 | + | ||
18 | +/** | ||
19 | + * The context of a flow rule operations that will become the subject of | ||
20 | + * the notification. | ||
21 | + * | ||
22 | + * Implementations of this class must be serializable. | ||
23 | + */ | ||
24 | +public interface FlowRuleOperationsContext { | ||
25 | + // TODO we might also want to execute a method on behalf of the app | ||
26 | + default void onSuccess(FlowRuleOperations ops){} | ||
27 | + default void onError(FlowRuleOperations ops){} | ||
28 | +} |
... | @@ -18,8 +18,6 @@ package org.onosproject.net.flow; | ... | @@ -18,8 +18,6 @@ package org.onosproject.net.flow; |
18 | import org.onosproject.core.ApplicationId; | 18 | import org.onosproject.core.ApplicationId; |
19 | import org.onosproject.net.provider.Provider; | 19 | import org.onosproject.net.provider.Provider; |
20 | 20 | ||
21 | -import java.util.concurrent.Future; | ||
22 | - | ||
23 | /** | 21 | /** |
24 | * Abstraction of a flow rule provider. | 22 | * Abstraction of a flow rule provider. |
25 | */ | 23 | */ |
... | @@ -56,8 +54,7 @@ public interface FlowRuleProvider extends Provider { | ... | @@ -56,8 +54,7 @@ public interface FlowRuleProvider extends Provider { |
56 | * Installs a batch of flow rules. Each flowrule is associated to an | 54 | * Installs a batch of flow rules. Each flowrule is associated to an |
57 | * operation which results in either addition, removal or modification. | 55 | * operation which results in either addition, removal or modification. |
58 | * @param batch a batch of flow rules | 56 | * @param batch a batch of flow rules |
59 | - * @return a future indicating the status of this execution | ||
60 | */ | 57 | */ |
61 | - Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch); | 58 | + void executeBatch(FlowRuleBatchOperation batch); |
62 | 59 | ||
63 | } | 60 | } | ... | ... |
... | @@ -40,4 +40,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide | ... | @@ -40,4 +40,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide |
40 | */ | 40 | */ |
41 | void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries); | 41 | void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries); |
42 | 42 | ||
43 | + /** | ||
44 | + * Indicates to the core that the requested batch operation has | ||
45 | + * been completed. | ||
46 | + * | ||
47 | + * @param batchId the batch which was processed | ||
48 | + * @param operation the resulting outcome of the operation | ||
49 | + */ | ||
50 | + void batchOperationCompleted(long batchId, CompletedBatchOperation operation); | ||
51 | + | ||
43 | } | 52 | } | ... | ... |
... | @@ -15,11 +15,11 @@ | ... | @@ -15,11 +15,11 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
17 | 17 | ||
18 | -import java.util.concurrent.Future; | ||
19 | - | ||
20 | import org.onosproject.core.ApplicationId; | 18 | import org.onosproject.core.ApplicationId; |
21 | import org.onosproject.net.DeviceId; | 19 | import org.onosproject.net.DeviceId; |
22 | 20 | ||
21 | +import java.util.concurrent.Future; | ||
22 | + | ||
23 | /** | 23 | /** |
24 | * Service for injecting flow rules into the environment and for obtaining | 24 | * Service for injecting flow rules into the environment and for obtaining |
25 | * information about flow rules already in the environment. This implements | 25 | * information about flow rules already in the environment. This implements |
... | @@ -30,6 +30,11 @@ import org.onosproject.net.DeviceId; | ... | @@ -30,6 +30,11 @@ import org.onosproject.net.DeviceId; |
30 | public interface FlowRuleService { | 30 | public interface FlowRuleService { |
31 | 31 | ||
32 | /** | 32 | /** |
33 | + * The topic used for obtaining globally unique ids. | ||
34 | + */ | ||
35 | + static String FLOW_OP_TOPIC = "flow-ops-ids"; | ||
36 | + | ||
37 | + /** | ||
33 | * Returns the number of flow rules in the system. | 38 | * Returns the number of flow rules in the system. |
34 | * | 39 | * |
35 | * @return flow rule count | 40 | * @return flow rule count |
... | @@ -96,11 +101,20 @@ public interface FlowRuleService { | ... | @@ -96,11 +101,20 @@ public interface FlowRuleService { |
96 | * Applies a batch operation of FlowRules. | 101 | * Applies a batch operation of FlowRules. |
97 | * | 102 | * |
98 | * @param batch batch operation to apply | 103 | * @param batch batch operation to apply |
99 | - * @return future indicating the state of the batch operation | 104 | + * @return future indicating the state of the batch operation, due to the |
105 | + * deprecation of this api the future will immediately return | ||
100 | */ | 106 | */ |
107 | + @Deprecated | ||
101 | Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch); | 108 | Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch); |
102 | 109 | ||
103 | /** | 110 | /** |
111 | + * Applies a batch operation of FlowRules. | ||
112 | + * | ||
113 | + * @param ops batch operation to apply | ||
114 | + */ | ||
115 | + void apply(FlowRuleOperations ops); | ||
116 | + | ||
117 | + /** | ||
104 | * Adds the specified flow rule listener. | 118 | * Adds the specified flow rule listener. |
105 | * | 119 | * |
106 | * @param listener flow rule listener | 120 | * @param listener flow rule listener | ... | ... |
... | @@ -15,8 +15,6 @@ | ... | @@ -15,8 +15,6 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
17 | 17 | ||
18 | -import java.util.concurrent.Future; | ||
19 | - | ||
20 | import org.onosproject.net.DeviceId; | 18 | import org.onosproject.net.DeviceId; |
21 | import org.onosproject.store.Store; | 19 | import org.onosproject.store.Store; |
22 | 20 | ||
... | @@ -54,6 +52,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe | ... | @@ -54,6 +52,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe |
54 | * | 52 | * |
55 | * @param rule the flow rule to add | 53 | * @param rule the flow rule to add |
56 | */ | 54 | */ |
55 | + @Deprecated | ||
57 | void storeFlowRule(FlowRule rule); | 56 | void storeFlowRule(FlowRule rule); |
58 | 57 | ||
59 | /** | 58 | /** |
... | @@ -61,10 +60,9 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe | ... | @@ -61,10 +60,9 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe |
61 | * | 60 | * |
62 | * @param batchOperation batch of flow rules. | 61 | * @param batchOperation batch of flow rules. |
63 | * A batch can contain flow rules for a single device only. | 62 | * A batch can contain flow rules for a single device only. |
64 | - * @return Future response indicating success/failure of the batch operation | 63 | + * |
65 | - * all the way down to the device. | ||
66 | */ | 64 | */ |
67 | - Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation batchOperation); | 65 | + void storeBatch(FlowRuleBatchOperation batchOperation); |
68 | 66 | ||
69 | /** | 67 | /** |
70 | * Invoked on the completion of a storeBatch operation. | 68 | * Invoked on the completion of a storeBatch operation. | ... | ... |
... | @@ -46,10 +46,10 @@ public class FlowRuleBatchOperationTest { | ... | @@ -46,10 +46,10 @@ public class FlowRuleBatchOperationTest { |
46 | final LinkedList<FlowRuleBatchEntry> ops3 = new LinkedList<>(); | 46 | final LinkedList<FlowRuleBatchEntry> ops3 = new LinkedList<>(); |
47 | ops3.add(entry3); | 47 | ops3.add(entry3); |
48 | 48 | ||
49 | - final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1); | 49 | + final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1, null, 0); |
50 | - final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1); | 50 | + final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1, null, 0); |
51 | - final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2); | 51 | + final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2, null, 0); |
52 | - final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3); | 52 | + final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3, null, 0); |
53 | 53 | ||
54 | new EqualsTester() | 54 | new EqualsTester() |
55 | .addEqualityGroup(operation1, sameAsOperation1) | 55 | .addEqualityGroup(operation1, sameAsOperation1) | ... | ... |
... | @@ -15,17 +15,18 @@ | ... | @@ -15,17 +15,18 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
17 | 17 | ||
18 | -import java.util.LinkedList; | ||
19 | -import java.util.List; | ||
20 | - | ||
21 | import org.junit.Test; | 18 | import org.junit.Test; |
22 | import org.onosproject.net.intent.IntentTestsMocks; | 19 | import org.onosproject.net.intent.IntentTestsMocks; |
23 | 20 | ||
24 | -import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*; | 21 | +import java.util.HashSet; |
22 | +import java.util.List; | ||
23 | +import java.util.Set; | ||
25 | 24 | ||
26 | import static org.hamcrest.MatcherAssert.assertThat; | 25 | import static org.hamcrest.MatcherAssert.assertThat; |
27 | import static org.hamcrest.Matchers.hasSize; | 26 | import static org.hamcrest.Matchers.hasSize; |
28 | import static org.hamcrest.Matchers.is; | 27 | import static org.hamcrest.Matchers.is; |
28 | +import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.ADD; | ||
29 | +import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.REMOVE; | ||
29 | 30 | ||
30 | /** | 31 | /** |
31 | * Unit tests for the FlowRuleBatchRequest class. | 32 | * Unit tests for the FlowRuleBatchRequest class. |
... | @@ -40,22 +41,19 @@ public class FlowRuleBatchRequestTest { | ... | @@ -40,22 +41,19 @@ public class FlowRuleBatchRequestTest { |
40 | public void testConstruction() { | 41 | public void testConstruction() { |
41 | final FlowRule rule1 = new IntentTestsMocks.MockFlowRule(1); | 42 | final FlowRule rule1 = new IntentTestsMocks.MockFlowRule(1); |
42 | final FlowRule rule2 = new IntentTestsMocks.MockFlowRule(2); | 43 | final FlowRule rule2 = new IntentTestsMocks.MockFlowRule(2); |
43 | - final List<FlowRuleBatchEntry> toAdd = new LinkedList<>(); | 44 | + final Set<FlowRuleBatchEntry> batch = new HashSet<>(); |
44 | - toAdd.add(new FlowRuleBatchEntry(ADD, rule1)); | 45 | + batch.add(new FlowRuleBatchEntry(ADD, rule1)); |
45 | - final List<FlowRuleBatchEntry> toRemove = new LinkedList<>(); | 46 | + |
46 | - toRemove.add(new FlowRuleBatchEntry(REMOVE, rule2)); | 47 | + batch.add(new FlowRuleBatchEntry(REMOVE, rule2)); |
47 | 48 | ||
48 | 49 | ||
49 | final FlowRuleBatchRequest request = | 50 | final FlowRuleBatchRequest request = |
50 | - new FlowRuleBatchRequest(1, toAdd, toRemove); | 51 | + new FlowRuleBatchRequest(1, batch); |
51 | 52 | ||
52 | - assertThat(request.toAdd(), hasSize(1)); | 53 | + assertThat(request.ops(), hasSize(2)); |
53 | - assertThat(request.toAdd().get(0), is(rule1)); | 54 | + assertThat(request.batchId(), is(1L)); |
54 | - assertThat(request.toRemove(), hasSize(1)); | ||
55 | - assertThat(request.toRemove().get(0), is(rule2)); | ||
56 | - assertThat(request.batchId(), is(1)); | ||
57 | 55 | ||
58 | - final FlowRuleBatchOperation op = request.asBatchOperation(); | 56 | + final FlowRuleBatchOperation op = request.asBatchOperation(rule1.deviceId()); |
59 | assertThat(op.size(), is(2)); | 57 | assertThat(op.size(), is(2)); |
60 | 58 | ||
61 | final List<FlowRuleBatchEntry> ops = op.getOperations(); | 59 | final List<FlowRuleBatchEntry> ops = op.getOperations(); | ... | ... |
... | @@ -66,6 +66,11 @@ public class FlowRuleServiceAdapter implements FlowRuleService { | ... | @@ -66,6 +66,11 @@ public class FlowRuleServiceAdapter implements FlowRuleService { |
66 | } | 66 | } |
67 | 67 | ||
68 | @Override | 68 | @Override |
69 | + public void apply(FlowRuleOperations ops) { | ||
70 | + | ||
71 | + } | ||
72 | + | ||
73 | + @Override | ||
69 | public void addListener(FlowRuleListener listener) { | 74 | public void addListener(FlowRuleListener listener) { |
70 | 75 | ||
71 | } | 76 | } | ... | ... |
... | @@ -21,7 +21,7 @@ import com.google.common.collect.Lists; | ... | @@ -21,7 +21,7 @@ import com.google.common.collect.Lists; |
21 | import com.google.common.collect.Maps; | 21 | import com.google.common.collect.Maps; |
22 | import com.google.common.collect.Multimap; | 22 | import com.google.common.collect.Multimap; |
23 | import com.google.common.collect.Sets; | 23 | import com.google.common.collect.Sets; |
24 | - | 24 | +import com.google.common.util.concurrent.Futures; |
25 | import org.apache.felix.scr.annotations.Activate; | 25 | import org.apache.felix.scr.annotations.Activate; |
26 | import org.apache.felix.scr.annotations.Component; | 26 | import org.apache.felix.scr.annotations.Component; |
27 | import org.apache.felix.scr.annotations.Deactivate; | 27 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -29,22 +29,25 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -29,22 +29,25 @@ import org.apache.felix.scr.annotations.Reference; |
29 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 29 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
30 | import org.apache.felix.scr.annotations.Service; | 30 | import org.apache.felix.scr.annotations.Service; |
31 | import org.onosproject.core.ApplicationId; | 31 | import org.onosproject.core.ApplicationId; |
32 | +import org.onosproject.core.CoreService; | ||
33 | +import org.onosproject.core.IdGenerator; | ||
32 | import org.onosproject.event.AbstractListenerRegistry; | 34 | import org.onosproject.event.AbstractListenerRegistry; |
33 | import org.onosproject.event.EventDeliveryService; | 35 | import org.onosproject.event.EventDeliveryService; |
34 | import org.onosproject.net.Device; | 36 | import org.onosproject.net.Device; |
35 | import org.onosproject.net.DeviceId; | 37 | import org.onosproject.net.DeviceId; |
36 | import org.onosproject.net.device.DeviceService; | 38 | import org.onosproject.net.device.DeviceService; |
37 | import org.onosproject.net.flow.CompletedBatchOperation; | 39 | import org.onosproject.net.flow.CompletedBatchOperation; |
38 | -import org.onosproject.net.flow.DefaultFlowEntry; | ||
39 | import org.onosproject.net.flow.FlowEntry; | 40 | import org.onosproject.net.flow.FlowEntry; |
40 | import org.onosproject.net.flow.FlowRule; | 41 | import org.onosproject.net.flow.FlowRule; |
41 | import org.onosproject.net.flow.FlowRuleBatchEntry; | 42 | import org.onosproject.net.flow.FlowRuleBatchEntry; |
42 | -import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | ||
43 | import org.onosproject.net.flow.FlowRuleBatchEvent; | 43 | import org.onosproject.net.flow.FlowRuleBatchEvent; |
44 | import org.onosproject.net.flow.FlowRuleBatchOperation; | 44 | import org.onosproject.net.flow.FlowRuleBatchOperation; |
45 | import org.onosproject.net.flow.FlowRuleBatchRequest; | 45 | import org.onosproject.net.flow.FlowRuleBatchRequest; |
46 | import org.onosproject.net.flow.FlowRuleEvent; | 46 | import org.onosproject.net.flow.FlowRuleEvent; |
47 | import org.onosproject.net.flow.FlowRuleListener; | 47 | import org.onosproject.net.flow.FlowRuleListener; |
48 | +import org.onosproject.net.flow.FlowRuleOperation; | ||
49 | +import org.onosproject.net.flow.FlowRuleOperations; | ||
50 | +import org.onosproject.net.flow.FlowRuleOperationsContext; | ||
48 | import org.onosproject.net.flow.FlowRuleProvider; | 51 | import org.onosproject.net.flow.FlowRuleProvider; |
49 | import org.onosproject.net.flow.FlowRuleProviderRegistry; | 52 | import org.onosproject.net.flow.FlowRuleProviderRegistry; |
50 | import org.onosproject.net.flow.FlowRuleProviderService; | 53 | import org.onosproject.net.flow.FlowRuleProviderService; |
... | @@ -55,18 +58,16 @@ import org.onosproject.net.provider.AbstractProviderRegistry; | ... | @@ -55,18 +58,16 @@ import org.onosproject.net.provider.AbstractProviderRegistry; |
55 | import org.onosproject.net.provider.AbstractProviderService; | 58 | import org.onosproject.net.provider.AbstractProviderService; |
56 | import org.slf4j.Logger; | 59 | import org.slf4j.Logger; |
57 | 60 | ||
58 | -import java.util.HashSet; | 61 | +import java.util.Collections; |
59 | import java.util.List; | 62 | import java.util.List; |
60 | import java.util.Map; | 63 | import java.util.Map; |
61 | import java.util.Set; | 64 | import java.util.Set; |
62 | -import java.util.concurrent.CancellationException; | 65 | +import java.util.concurrent.ConcurrentHashMap; |
63 | -import java.util.concurrent.ExecutionException; | ||
64 | import java.util.concurrent.ExecutorService; | 66 | import java.util.concurrent.ExecutorService; |
65 | import java.util.concurrent.Executors; | 67 | import java.util.concurrent.Executors; |
66 | import java.util.concurrent.Future; | 68 | import java.util.concurrent.Future; |
67 | -import java.util.concurrent.TimeUnit; | 69 | +import java.util.concurrent.atomic.AtomicBoolean; |
68 | -import java.util.concurrent.TimeoutException; | 70 | + |
69 | -import java.util.concurrent.atomic.AtomicReference; | ||
70 | import static com.google.common.base.Preconditions.checkNotNull; | 71 | import static com.google.common.base.Preconditions.checkNotNull; |
71 | import static org.onlab.util.Tools.namedThreads; | 72 | import static org.onlab.util.Tools.namedThreads; |
72 | import static org.slf4j.LoggerFactory.getLogger; | 73 | import static org.slf4j.LoggerFactory.getLogger; |
... | @@ -90,7 +91,16 @@ public class FlowRuleManager | ... | @@ -90,7 +91,16 @@ public class FlowRuleManager |
90 | 91 | ||
91 | private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate(); | 92 | private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate(); |
92 | 93 | ||
93 | - private ExecutorService futureService; | 94 | + protected ExecutorService deviceInstallers = |
95 | + Executors.newCachedThreadPool(namedThreads("onos-device-installer-%d")); | ||
96 | + | ||
97 | + protected ExecutorService operationsService = | ||
98 | + Executors.newFixedThreadPool(32, namedThreads("onos-flowservice-operations-%d")); | ||
99 | + | ||
100 | + private IdGenerator idGenerator; | ||
101 | + | ||
102 | + private Map<Long, FlowOperationsProcessor> pendingFlowOperations = new | ||
103 | + ConcurrentHashMap<>(); | ||
94 | 104 | ||
95 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 105 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
96 | protected FlowRuleStore store; | 106 | protected FlowRuleStore store; |
... | @@ -101,10 +111,15 @@ public class FlowRuleManager | ... | @@ -101,10 +111,15 @@ public class FlowRuleManager |
101 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 111 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
102 | protected DeviceService deviceService; | 112 | protected DeviceService deviceService; |
103 | 113 | ||
114 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
115 | + protected CoreService coreService; | ||
116 | + | ||
104 | @Activate | 117 | @Activate |
105 | public void activate() { | 118 | public void activate() { |
106 | - futureService = | 119 | + |
107 | - Executors.newFixedThreadPool(32, namedThreads("onos-provider-future-listeners-%d")); | 120 | + idGenerator = coreService.getIdGenerator(FLOW_OP_TOPIC); |
121 | + | ||
122 | + | ||
108 | store.setDelegate(delegate); | 123 | store.setDelegate(delegate); |
109 | eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry); | 124 | eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry); |
110 | log.info("Started"); | 125 | log.info("Started"); |
... | @@ -112,8 +127,8 @@ public class FlowRuleManager | ... | @@ -112,8 +127,8 @@ public class FlowRuleManager |
112 | 127 | ||
113 | @Deactivate | 128 | @Deactivate |
114 | public void deactivate() { | 129 | public void deactivate() { |
115 | - futureService.shutdownNow(); | 130 | + deviceInstallers.shutdownNow(); |
116 | - | 131 | + operationsService.shutdownNow(); |
117 | store.unsetDelegate(delegate); | 132 | store.unsetDelegate(delegate); |
118 | eventDispatcher.removeSink(FlowRuleEvent.class); | 133 | eventDispatcher.removeSink(FlowRuleEvent.class); |
119 | log.info("Stopped"); | 134 | log.info("Stopped"); |
... | @@ -131,20 +146,20 @@ public class FlowRuleManager | ... | @@ -131,20 +146,20 @@ public class FlowRuleManager |
131 | 146 | ||
132 | @Override | 147 | @Override |
133 | public void applyFlowRules(FlowRule... flowRules) { | 148 | public void applyFlowRules(FlowRule... flowRules) { |
134 | - Set<FlowRuleBatchEntry> toAddBatchEntries = Sets.newHashSet(); | 149 | + FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); |
135 | for (int i = 0; i < flowRules.length; i++) { | 150 | for (int i = 0; i < flowRules.length; i++) { |
136 | - toAddBatchEntries.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, flowRules[i])); | 151 | + builder.add(flowRules[i]); |
137 | } | 152 | } |
138 | - applyBatch(new FlowRuleBatchOperation(toAddBatchEntries)); | 153 | + apply(builder.build()); |
139 | } | 154 | } |
140 | 155 | ||
141 | @Override | 156 | @Override |
142 | public void removeFlowRules(FlowRule... flowRules) { | 157 | public void removeFlowRules(FlowRule... flowRules) { |
143 | - Set<FlowRuleBatchEntry> toRemoveBatchEntries = Sets.newHashSet(); | 158 | + FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); |
144 | for (int i = 0; i < flowRules.length; i++) { | 159 | for (int i = 0; i < flowRules.length; i++) { |
145 | - toRemoveBatchEntries.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, flowRules[i])); | 160 | + builder.remove(flowRules[i]); |
146 | } | 161 | } |
147 | - applyBatch(new FlowRuleBatchOperation(toRemoveBatchEntries)); | 162 | + apply(builder.build()); |
148 | } | 163 | } |
149 | 164 | ||
150 | @Override | 165 | @Override |
... | @@ -180,23 +195,38 @@ public class FlowRuleManager | ... | @@ -180,23 +195,38 @@ public class FlowRuleManager |
180 | } | 195 | } |
181 | 196 | ||
182 | @Override | 197 | @Override |
183 | - public Future<CompletedBatchOperation> applyBatch( | 198 | + public Future<CompletedBatchOperation> applyBatch(FlowRuleBatchOperation batch) { |
184 | - FlowRuleBatchOperation batch) { | 199 | + |
185 | - Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches = | 200 | + |
186 | - ArrayListMultimap.create(); | 201 | + FlowRuleOperations.Builder fopsBuilder = FlowRuleOperations.builder(); |
187 | - List<Future<CompletedBatchOperation>> futures = Lists.newArrayList(); | 202 | + batch.getOperations().stream().forEach(op -> { |
188 | - for (FlowRuleBatchEntry fbe : batch.getOperations()) { | 203 | + switch (op.getOperator()) { |
189 | - final FlowRule f = fbe.target(); | 204 | + case ADD: |
190 | - perDeviceBatches.put(f.deviceId(), fbe); | 205 | + fopsBuilder.add(op.getTarget()); |
206 | + break; | ||
207 | + case REMOVE: | ||
208 | + fopsBuilder.remove(op.getTarget()); | ||
209 | + break; | ||
210 | + case MODIFY: | ||
211 | + fopsBuilder.modify(op.getTarget()); | ||
212 | + break; | ||
213 | + default: | ||
214 | + log.warn("Unknown flow operation operator: {}", op.getOperator()); | ||
215 | + | ||
191 | } | 216 | } |
217 | + } | ||
218 | + ); | ||
219 | + | ||
220 | + apply(fopsBuilder.build()); | ||
221 | + return Futures.immediateFuture( | ||
222 | + new CompletedBatchOperation(true, | ||
223 | + Collections.emptySet(), null)); | ||
192 | 224 | ||
193 | - for (DeviceId deviceId : perDeviceBatches.keySet()) { | ||
194 | - FlowRuleBatchOperation b = | ||
195 | - new FlowRuleBatchOperation(perDeviceBatches.get(deviceId)); | ||
196 | - Future<CompletedBatchOperation> future = store.storeBatch(b); | ||
197 | - futures.add(future); | ||
198 | } | 225 | } |
199 | - return new FlowRuleBatchFuture(futures, perDeviceBatches); | 226 | + |
227 | + @Override | ||
228 | + public void apply(FlowRuleOperations ops) { | ||
229 | + operationsService.submit(new FlowOperationsProcessor(ops)); | ||
200 | } | 230 | } |
201 | 231 | ||
202 | @Override | 232 | @Override |
... | @@ -373,13 +403,19 @@ public class FlowRuleManager | ... | @@ -373,13 +403,19 @@ public class FlowRuleManager |
373 | 403 | ||
374 | } | 404 | } |
375 | } | 405 | } |
406 | + | ||
407 | + @Override | ||
408 | + public void batchOperationCompleted(long batchId, CompletedBatchOperation operation) { | ||
409 | + store.batchOperationComplete(FlowRuleBatchEvent.completed( | ||
410 | + new FlowRuleBatchRequest(batchId, Collections.emptySet()), | ||
411 | + operation | ||
412 | + )); | ||
413 | + } | ||
376 | } | 414 | } |
377 | 415 | ||
378 | // Store delegate to re-post events emitted from the store. | 416 | // Store delegate to re-post events emitted from the store. |
379 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { | 417 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { |
380 | 418 | ||
381 | - // FIXME set appropriate default and make it configurable | ||
382 | - private static final int TIMEOUT_PER_OP = 500; // ms | ||
383 | 419 | ||
384 | // TODO: Right now we only dispatch events at individual flowEntry level. | 420 | // TODO: Right now we only dispatch events at individual flowEntry level. |
385 | // It may be more efficient for also dispatch events as a batch. | 421 | // It may be more efficient for also dispatch events as a batch. |
... | @@ -389,47 +425,55 @@ public class FlowRuleManager | ... | @@ -389,47 +425,55 @@ public class FlowRuleManager |
389 | switch (event.type()) { | 425 | switch (event.type()) { |
390 | case BATCH_OPERATION_REQUESTED: | 426 | case BATCH_OPERATION_REQUESTED: |
391 | // Request has been forwarded to MASTER Node, and was | 427 | // Request has been forwarded to MASTER Node, and was |
392 | - for (FlowRule entry : request.toAdd()) { | 428 | + request.ops().stream().forEach( |
393 | - eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, entry)); | 429 | + op -> { |
430 | + switch (op.getOperator()) { | ||
431 | + | ||
432 | + case ADD: | ||
433 | + eventDispatcher.post( | ||
434 | + new FlowRuleEvent( | ||
435 | + FlowRuleEvent.Type.RULE_ADD_REQUESTED, | ||
436 | + op.getTarget())); | ||
437 | + break; | ||
438 | + case REMOVE: | ||
439 | + eventDispatcher.post( | ||
440 | + new FlowRuleEvent( | ||
441 | + FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, | ||
442 | + op.getTarget())); | ||
443 | + break; | ||
444 | + case MODIFY: | ||
445 | + //TODO: do something here when the time comes. | ||
446 | + break; | ||
447 | + default: | ||
448 | + log.warn("Unknown flow operation operator: {}", op.getOperator()); | ||
394 | } | 449 | } |
395 | - for (FlowRule entry : request.toRemove()) { | ||
396 | - eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, entry)); | ||
397 | } | 450 | } |
398 | - // FIXME: what about op.equals(FlowRuleOperation.MODIFY) ? | 451 | + ); |
452 | + | ||
453 | + DeviceId deviceId = event.deviceId(); | ||
399 | 454 | ||
400 | - FlowRuleBatchOperation batchOperation = request.asBatchOperation(); | 455 | + FlowRuleBatchOperation batchOperation = |
456 | + request.asBatchOperation(deviceId); | ||
401 | 457 | ||
402 | FlowRuleProvider flowRuleProvider = | 458 | FlowRuleProvider flowRuleProvider = |
403 | - getProvider(batchOperation.getOperations().get(0).target().deviceId()); | 459 | + getProvider(deviceId); |
404 | - final Future<CompletedBatchOperation> result = | 460 | + |
405 | flowRuleProvider.executeBatch(batchOperation); | 461 | flowRuleProvider.executeBatch(batchOperation); |
406 | - futureService.submit(new Runnable() { | ||
407 | - @Override | ||
408 | - public void run() { | ||
409 | - CompletedBatchOperation res; | ||
410 | - try { | ||
411 | - res = result.get(TIMEOUT_PER_OP * batchOperation.size(), TimeUnit.MILLISECONDS); | ||
412 | - store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); | ||
413 | - } catch (TimeoutException | InterruptedException | ExecutionException e) { | ||
414 | - log.warn("Something went wrong with the batch operation {}", | ||
415 | - request.batchId(), e); | ||
416 | 462 | ||
417 | - Set<FlowRule> failures = new HashSet<>(batchOperation.size()); | ||
418 | - for (FlowRuleBatchEntry op : batchOperation.getOperations()) { | ||
419 | - failures.add(op.target()); | ||
420 | - } | ||
421 | - res = new CompletedBatchOperation(false, failures); | ||
422 | - store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); | ||
423 | - } | ||
424 | - } | ||
425 | - }); | ||
426 | break; | 463 | break; |
427 | 464 | ||
428 | case BATCH_OPERATION_COMPLETED: | 465 | case BATCH_OPERATION_COMPLETED: |
429 | - // MASTER Node has pushed the batch down to the Device | ||
430 | 466 | ||
431 | - // Note: RULE_ADDED will be posted | 467 | + FlowOperationsProcessor fops = pendingFlowOperations.remove( |
432 | - // when Flow was actually confirmed by stats reply. | 468 | + event.subject().batchId()); |
469 | + if (event.result().isSuccess()) { | ||
470 | + if (fops != null) { | ||
471 | + fops.satisfy(event.deviceId()); | ||
472 | + } | ||
473 | + } else { | ||
474 | + fops.fail(event.deviceId(), event.result().failedItems()); | ||
475 | + } | ||
476 | + | ||
433 | break; | 477 | break; |
434 | 478 | ||
435 | default: | 479 | default: |
... | @@ -438,141 +482,100 @@ public class FlowRuleManager | ... | @@ -438,141 +482,100 @@ public class FlowRuleManager |
438 | } | 482 | } |
439 | } | 483 | } |
440 | 484 | ||
441 | - private class FlowRuleBatchFuture implements Future<CompletedBatchOperation> { | 485 | + private class FlowOperationsProcessor implements Runnable { |
442 | 486 | ||
443 | - private final List<Future<CompletedBatchOperation>> futures; | 487 | + private final List<Set<FlowRuleOperation>> stages; |
444 | - private final Multimap<DeviceId, FlowRuleBatchEntry> batches; | 488 | + private final FlowRuleOperationsContext context; |
445 | - private final AtomicReference<BatchState> state; | 489 | + private final FlowRuleOperations fops; |
446 | - private CompletedBatchOperation overall; | 490 | + private final AtomicBoolean hasFailed = new AtomicBoolean(false); |
447 | 491 | ||
448 | - public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures, | 492 | + private Set<DeviceId> pendingDevices; |
449 | - Multimap<DeviceId, FlowRuleBatchEntry> batches) { | ||
450 | - this.futures = futures; | ||
451 | - this.batches = batches; | ||
452 | - this.state = new AtomicReference<>(BatchState.STARTED); | ||
453 | - } | ||
454 | - | ||
455 | - @Override | ||
456 | - public boolean cancel(boolean mayInterruptIfRunning) { | ||
457 | - if (state.get() == BatchState.FINISHED) { | ||
458 | - return false; | ||
459 | - } | ||
460 | - if (log.isDebugEnabled()) { | ||
461 | - log.debug("Cancelling FlowRuleBatchFuture", | ||
462 | - new RuntimeException("Just printing backtrace")); | ||
463 | - } | ||
464 | - if (!state.compareAndSet(BatchState.STARTED, BatchState.CANCELLED)) { | ||
465 | - return false; | ||
466 | - } | ||
467 | - cleanUpBatch(); | ||
468 | - for (Future<CompletedBatchOperation> f : futures) { | ||
469 | - f.cancel(mayInterruptIfRunning); | ||
470 | - } | ||
471 | - return true; | ||
472 | - } | ||
473 | 493 | ||
474 | - @Override | 494 | + public FlowOperationsProcessor(FlowRuleOperations ops) { |
475 | - public boolean isCancelled() { | ||
476 | - return state.get() == BatchState.CANCELLED; | ||
477 | - } | ||
478 | - | ||
479 | - @Override | ||
480 | - public boolean isDone() { | ||
481 | - return state.get() == BatchState.FINISHED; | ||
482 | - } | ||
483 | 495 | ||
496 | + this.stages = Lists.newArrayList(ops.stages()); | ||
497 | + this.context = ops.callback(); | ||
498 | + this.fops = ops; | ||
499 | + pendingDevices = Sets.newConcurrentHashSet(); | ||
484 | 500 | ||
485 | - @Override | ||
486 | - public CompletedBatchOperation get() throws InterruptedException, | ||
487 | - ExecutionException { | ||
488 | 501 | ||
489 | - if (isDone()) { | ||
490 | - return overall; | ||
491 | } | 502 | } |
492 | 503 | ||
493 | - boolean success = true; | 504 | + @Override |
494 | - Set<FlowRule> failed = Sets.newHashSet(); | 505 | + public void run() { |
495 | - Set<Long> failedIds = Sets.newHashSet(); | 506 | + if (stages.size() > 0) { |
496 | - CompletedBatchOperation completed; | 507 | + process(stages.remove(0)); |
497 | - for (Future<CompletedBatchOperation> future : futures) { | 508 | + } else if (!hasFailed.get() && context != null) { |
498 | - completed = future.get(); | 509 | + context.onSuccess(fops); |
499 | - success = validateBatchOperation(failed, failedIds, completed); | ||
500 | } | 510 | } |
501 | - | ||
502 | - return finalizeBatchOperation(success, failed, failedIds); | ||
503 | - | ||
504 | } | 511 | } |
505 | 512 | ||
506 | - @Override | 513 | + private void process(Set<FlowRuleOperation> ops) { |
507 | - public CompletedBatchOperation get(long timeout, TimeUnit unit) | 514 | + Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches = |
508 | - throws InterruptedException, ExecutionException, | 515 | + ArrayListMultimap.create(); |
509 | - TimeoutException { | ||
510 | 516 | ||
511 | - if (isDone()) { | 517 | + FlowRuleBatchEntry fbe; |
512 | - return overall; | 518 | + for (FlowRuleOperation flowRuleOperation : ops) { |
513 | - } | 519 | + switch (flowRuleOperation.type()) { |
514 | - boolean success = true; | 520 | + // FIXME: Brian needs imagination when creating class names. |
515 | - Set<FlowRule> failed = Sets.newHashSet(); | 521 | + case ADD: |
516 | - Set<Long> failedIds = Sets.newHashSet(); | 522 | + fbe = new FlowRuleBatchEntry( |
517 | - CompletedBatchOperation completed; | 523 | + FlowRuleBatchEntry.FlowRuleOperation.ADD, flowRuleOperation.rule()); |
518 | - for (Future<CompletedBatchOperation> future : futures) { | 524 | + break; |
519 | - completed = future.get(timeout, unit); | 525 | + case MODIFY: |
520 | - success = validateBatchOperation(failed, failedIds, completed); | 526 | + fbe = new FlowRuleBatchEntry( |
527 | + FlowRuleBatchEntry.FlowRuleOperation.MODIFY, flowRuleOperation.rule()); | ||
528 | + break; | ||
529 | + case REMOVE: | ||
530 | + fbe = new FlowRuleBatchEntry( | ||
531 | + FlowRuleBatchEntry.FlowRuleOperation.REMOVE, flowRuleOperation.rule()); | ||
532 | + break; | ||
533 | + default: | ||
534 | + throw new UnsupportedOperationException("Unknown flow rule type " + flowRuleOperation.type()); | ||
521 | } | 535 | } |
522 | - return finalizeBatchOperation(success, failed, failedIds); | 536 | + pendingDevices.add(flowRuleOperation.rule().deviceId()); |
537 | + perDeviceBatches.put(flowRuleOperation.rule().deviceId(), fbe); | ||
523 | } | 538 | } |
524 | 539 | ||
525 | - private boolean validateBatchOperation(Set<FlowRule> failed, | ||
526 | - Set<Long> failedIds, | ||
527 | - CompletedBatchOperation completed) { | ||
528 | 540 | ||
529 | - if (isCancelled()) { | 541 | + for (DeviceId deviceId : perDeviceBatches.keySet()) { |
530 | - throw new CancellationException(); | 542 | + Long id = idGenerator.getNewId(); |
543 | + final FlowRuleBatchOperation b = new FlowRuleBatchOperation(perDeviceBatches.get(deviceId), | ||
544 | + deviceId, id); | ||
545 | + pendingFlowOperations.put(id, this); | ||
546 | + deviceInstallers.submit(new Runnable() { | ||
547 | + @Override | ||
548 | + public void run() { | ||
549 | + store.storeBatch(b); | ||
531 | } | 550 | } |
532 | - if (!completed.isSuccess()) { | 551 | + }); |
533 | - log.warn("FlowRuleBatch failed: {}", completed); | ||
534 | - failed.addAll(completed.failedItems()); | ||
535 | - failedIds.addAll(completed.failedIds()); | ||
536 | - cleanUpBatch(); | ||
537 | - cancelAllSubBatches(); | ||
538 | - return false; | ||
539 | } | 552 | } |
540 | - return true; | ||
541 | } | 553 | } |
542 | 554 | ||
543 | - private void cancelAllSubBatches() { | 555 | + public void satisfy(DeviceId devId) { |
544 | - for (Future<CompletedBatchOperation> f : futures) { | 556 | + pendingDevices.remove(devId); |
545 | - f.cancel(true); | 557 | + if (pendingDevices.isEmpty()) { |
558 | + operationsService.submit(this); | ||
546 | } | 559 | } |
547 | } | 560 | } |
548 | 561 | ||
549 | - private CompletedBatchOperation finalizeBatchOperation(boolean success, | ||
550 | - Set<FlowRule> failed, | ||
551 | - Set<Long> failedIds) { | ||
552 | - synchronized (this) { | ||
553 | - if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) { | ||
554 | - if (state.get() == BatchState.FINISHED) { | ||
555 | - return overall; | ||
556 | - } | ||
557 | - throw new CancellationException(); | ||
558 | - } | ||
559 | - overall = new CompletedBatchOperation(success, failed, failedIds); | ||
560 | - return overall; | ||
561 | - } | ||
562 | - } | ||
563 | 562 | ||
564 | - private void cleanUpBatch() { | 563 | + |
565 | - log.debug("cleaning up batch"); | 564 | + public void fail(DeviceId devId, Set<? extends FlowRule> failures) { |
566 | - // TODO convert these into a batch? | 565 | + hasFailed.set(true); |
567 | - for (FlowRuleBatchEntry fbe : batches.values()) { | 566 | + pendingDevices.remove(devId); |
568 | - if (fbe.operator() == FlowRuleOperation.ADD || | 567 | + if (pendingDevices.isEmpty()) { |
569 | - fbe.operator() == FlowRuleOperation.MODIFY) { | 568 | + operationsService.submit(this); |
570 | - store.deleteFlowRule(fbe.target()); | ||
571 | - } else if (fbe.operator() == FlowRuleOperation.REMOVE) { | ||
572 | - store.removeFlowRule(new DefaultFlowEntry(fbe.target())); | ||
573 | - store.storeFlowRule(fbe.target()); | ||
574 | } | 569 | } |
570 | + | ||
571 | + if (context != null) { | ||
572 | + final FlowRuleOperations.Builder failedOpsBuilder = | ||
573 | + FlowRuleOperations.builder(); | ||
574 | + failures.stream().forEach(failedOpsBuilder::add); | ||
575 | + | ||
576 | + context.onError(failedOpsBuilder.build()); | ||
575 | } | 577 | } |
576 | } | 578 | } |
579 | + | ||
577 | } | 580 | } |
578 | } | 581 | } | ... | ... |
... | @@ -1151,6 +1151,7 @@ public class IntentManager | ... | @@ -1151,6 +1151,7 @@ public class IntentManager |
1151 | */ | 1151 | */ |
1152 | protected Future<CompletedBatchOperation> applyNextBatch(List<CompletedIntentUpdate> updates) { | 1152 | protected Future<CompletedBatchOperation> applyNextBatch(List<CompletedIntentUpdate> updates) { |
1153 | //TODO test this. (also, maybe save this batch) | 1153 | //TODO test this. (also, maybe save this batch) |
1154 | + | ||
1154 | FlowRuleBatchOperation batch = createFlowRuleBatchOperation(updates); | 1155 | FlowRuleBatchOperation batch = createFlowRuleBatchOperation(updates); |
1155 | if (batch.size() > 0) { | 1156 | if (batch.size() > 0) { |
1156 | //FIXME apply batch might throw an exception | 1157 | //FIXME apply batch might throw an exception |
... | @@ -1165,7 +1166,7 @@ public class IntentManager | ... | @@ -1165,7 +1166,7 @@ public class IntentManager |
1165 | } | 1166 | } |
1166 | 1167 | ||
1167 | private FlowRuleBatchOperation createFlowRuleBatchOperation(List<CompletedIntentUpdate> intentUpdates) { | 1168 | private FlowRuleBatchOperation createFlowRuleBatchOperation(List<CompletedIntentUpdate> intentUpdates) { |
1168 | - FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList()); | 1169 | + FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList(), null, 0); |
1169 | for (CompletedIntentUpdate update : intentUpdates) { | 1170 | for (CompletedIntentUpdate update : intentUpdates) { |
1170 | FlowRuleBatchOperation currentBatch = update.currentBatch(); | 1171 | FlowRuleBatchOperation currentBatch = update.currentBatch(); |
1171 | if (currentBatch != null) { | 1172 | if (currentBatch != null) { | ... | ... |
... | @@ -98,6 +98,7 @@ public class LinkCollectionIntentInstaller | ... | @@ -98,6 +98,7 @@ public class LinkCollectionIntentInstaller |
98 | outputPorts.put(egressPoint.deviceId(), egressPoint.port()); | 98 | outputPorts.put(egressPoint.deviceId(), egressPoint.port()); |
99 | } | 99 | } |
100 | 100 | ||
101 | + //FIXME change to new api | ||
101 | FlowRuleBatchOperation batchOperation = | 102 | FlowRuleBatchOperation batchOperation = |
102 | new FlowRuleBatchOperation(outputPorts | 103 | new FlowRuleBatchOperation(outputPorts |
103 | .keys() | 104 | .keys() |
... | @@ -105,7 +106,7 @@ public class LinkCollectionIntentInstaller | ... | @@ -105,7 +106,7 @@ public class LinkCollectionIntentInstaller |
105 | .map(deviceId -> createBatchEntry(operation, | 106 | .map(deviceId -> createBatchEntry(operation, |
106 | intent, deviceId, | 107 | intent, deviceId, |
107 | outputPorts.get(deviceId))) | 108 | outputPorts.get(deviceId))) |
108 | - .collect(Collectors.toList())); | 109 | + .collect(Collectors.toList()), null, 0); |
109 | 110 | ||
110 | return Collections.singletonList(batchOperation); | 111 | return Collections.singletonList(batchOperation); |
111 | } | 112 | } | ... | ... |
... | @@ -181,6 +181,7 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn | ... | @@ -181,6 +181,7 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn |
181 | true); | 181 | true); |
182 | rules.add(new FlowRuleBatchEntry(operation, rule)); | 182 | rules.add(new FlowRuleBatchEntry(operation, rule)); |
183 | 183 | ||
184 | - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 184 | + //FIXME change to new api |
185 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0)); | ||
185 | } | 186 | } |
186 | } | 187 | } | ... | ... |
... | @@ -108,7 +108,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -108,7 +108,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
108 | intent.id().fingerprint())); | 108 | intent.id().fingerprint())); |
109 | prev = link.dst(); | 109 | prev = link.dst(); |
110 | } | 110 | } |
111 | - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 111 | + //FIXME this should change to new api. |
112 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0)); | ||
112 | } | 113 | } |
113 | 114 | ||
114 | @Override | 115 | @Override |
... | @@ -138,7 +139,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -138,7 +139,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
138 | intent.id().fingerprint())); | 139 | intent.id().fingerprint())); |
139 | prev = link.dst(); | 140 | prev = link.dst(); |
140 | } | 141 | } |
141 | - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 142 | + // FIXME this should change to new api |
143 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0)); | ||
142 | } | 144 | } |
143 | 145 | ||
144 | @Override | 146 | @Override | ... | ... |
... | @@ -31,7 +31,7 @@ public class TestEventDispatcher extends DefaultEventSinkRegistry | ... | @@ -31,7 +31,7 @@ public class TestEventDispatcher extends DefaultEventSinkRegistry |
31 | 31 | ||
32 | @Override | 32 | @Override |
33 | @SuppressWarnings("unchecked") | 33 | @SuppressWarnings("unchecked") |
34 | - public void post(Event event) { | 34 | + public synchronized void post(Event event) { |
35 | EventSink sink = getSink(event.getClass()); | 35 | EventSink sink = getSink(event.getClass()); |
36 | checkState(sink != null, "No sink for event %s", event); | 36 | checkState(sink != null, "No sink for event %s", event); |
37 | sink.process(event); | 37 | sink.process(event); | ... | ... |
... | @@ -20,12 +20,15 @@ import com.google.common.collect.ImmutableMap; | ... | @@ -20,12 +20,15 @@ import com.google.common.collect.ImmutableMap; |
20 | import com.google.common.collect.Lists; | 20 | import com.google.common.collect.Lists; |
21 | import com.google.common.collect.Sets; | 21 | import com.google.common.collect.Sets; |
22 | import com.google.common.util.concurrent.ListenableFuture; | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | - | 23 | +import com.google.common.util.concurrent.MoreExecutors; |
24 | import org.junit.After; | 24 | import org.junit.After; |
25 | import org.junit.Before; | 25 | import org.junit.Before; |
26 | import org.junit.Test; | 26 | import org.junit.Test; |
27 | import org.onosproject.core.ApplicationId; | 27 | import org.onosproject.core.ApplicationId; |
28 | +import org.onosproject.core.CoreService; | ||
28 | import org.onosproject.core.DefaultApplicationId; | 29 | import org.onosproject.core.DefaultApplicationId; |
30 | +import org.onosproject.core.IdGenerator; | ||
31 | +import org.onosproject.core.Version; | ||
29 | import org.onosproject.event.impl.TestEventDispatcher; | 32 | import org.onosproject.event.impl.TestEventDispatcher; |
30 | import org.onosproject.net.DefaultDevice; | 33 | import org.onosproject.net.DefaultDevice; |
31 | import org.onosproject.net.Device; | 34 | import org.onosproject.net.Device; |
... | @@ -36,7 +39,6 @@ import org.onosproject.net.Port; | ... | @@ -36,7 +39,6 @@ import org.onosproject.net.Port; |
36 | import org.onosproject.net.PortNumber; | 39 | import org.onosproject.net.PortNumber; |
37 | import org.onosproject.net.device.DeviceListener; | 40 | import org.onosproject.net.device.DeviceListener; |
38 | import org.onosproject.net.device.DeviceServiceAdapter; | 41 | import org.onosproject.net.device.DeviceServiceAdapter; |
39 | -import org.onosproject.net.flow.BatchOperation; | ||
40 | import org.onosproject.net.flow.CompletedBatchOperation; | 42 | import org.onosproject.net.flow.CompletedBatchOperation; |
41 | import org.onosproject.net.flow.DefaultFlowEntry; | 43 | import org.onosproject.net.flow.DefaultFlowEntry; |
42 | import org.onosproject.net.flow.DefaultFlowRule; | 44 | import org.onosproject.net.flow.DefaultFlowRule; |
... | @@ -72,6 +74,7 @@ import java.util.concurrent.Executor; | ... | @@ -72,6 +74,7 @@ import java.util.concurrent.Executor; |
72 | import java.util.concurrent.Future; | 74 | import java.util.concurrent.Future; |
73 | import java.util.concurrent.TimeUnit; | 75 | import java.util.concurrent.TimeUnit; |
74 | import java.util.concurrent.TimeoutException; | 76 | import java.util.concurrent.TimeoutException; |
77 | +import java.util.concurrent.atomic.AtomicLong; | ||
75 | 78 | ||
76 | import static org.junit.Assert.*; | 79 | import static org.junit.Assert.*; |
77 | import static org.onosproject.net.flow.FlowRuleEvent.Type.*; | 80 | import static org.onosproject.net.flow.FlowRuleEvent.Type.*; |
... | @@ -97,12 +100,16 @@ public class FlowRuleManagerTest { | ... | @@ -97,12 +100,16 @@ public class FlowRuleManagerTest { |
97 | protected TestListener listener = new TestListener(); | 100 | protected TestListener listener = new TestListener(); |
98 | private ApplicationId appId; | 101 | private ApplicationId appId; |
99 | 102 | ||
103 | + | ||
100 | @Before | 104 | @Before |
101 | public void setUp() { | 105 | public void setUp() { |
102 | mgr = new FlowRuleManager(); | 106 | mgr = new FlowRuleManager(); |
103 | mgr.store = new SimpleFlowRuleStore(); | 107 | mgr.store = new SimpleFlowRuleStore(); |
104 | mgr.eventDispatcher = new TestEventDispatcher(); | 108 | mgr.eventDispatcher = new TestEventDispatcher(); |
105 | mgr.deviceService = new TestDeviceService(); | 109 | mgr.deviceService = new TestDeviceService(); |
110 | + mgr.coreService = new TestCoreService(); | ||
111 | + mgr.operationsService = MoreExecutors.newDirectExecutorService(); | ||
112 | + mgr.deviceInstallers = MoreExecutors.newDirectExecutorService(); | ||
106 | service = mgr; | 113 | service = mgr; |
107 | registry = mgr; | 114 | registry = mgr; |
108 | 115 | ||
... | @@ -246,14 +253,23 @@ public class FlowRuleManagerTest { | ... | @@ -246,14 +253,23 @@ public class FlowRuleManagerTest { |
246 | 253 | ||
247 | @Test | 254 | @Test |
248 | public void flowRemoved() { | 255 | public void flowRemoved() { |
256 | + | ||
249 | FlowRule f1 = addFlowRule(1); | 257 | FlowRule f1 = addFlowRule(1); |
250 | FlowRule f2 = addFlowRule(2); | 258 | FlowRule f2 = addFlowRule(2); |
251 | StoredFlowEntry fe1 = new DefaultFlowEntry(f1); | 259 | StoredFlowEntry fe1 = new DefaultFlowEntry(f1); |
252 | FlowEntry fe2 = new DefaultFlowEntry(f2); | 260 | FlowEntry fe2 = new DefaultFlowEntry(f2); |
261 | + | ||
262 | + | ||
253 | providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2)); | 263 | providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2)); |
254 | service.removeFlowRules(f1); | 264 | service.removeFlowRules(f1); |
265 | + | ||
255 | fe1.setState(FlowEntryState.REMOVED); | 266 | fe1.setState(FlowEntryState.REMOVED); |
267 | + | ||
268 | + | ||
269 | + | ||
256 | providerService.flowRemoved(fe1); | 270 | providerService.flowRemoved(fe1); |
271 | + | ||
272 | + | ||
257 | validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED, | 273 | validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED, |
258 | RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED); | 274 | RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED); |
259 | 275 | ||
... | @@ -263,11 +279,13 @@ public class FlowRuleManagerTest { | ... | @@ -263,11 +279,13 @@ public class FlowRuleManagerTest { |
263 | FlowRule f3 = flowRule(3, 3); | 279 | FlowRule f3 = flowRule(3, 3); |
264 | FlowEntry fe3 = new DefaultFlowEntry(f3); | 280 | FlowEntry fe3 = new DefaultFlowEntry(f3); |
265 | service.applyFlowRules(f3); | 281 | service.applyFlowRules(f3); |
282 | + | ||
266 | providerService.pushFlowMetrics(DID, Collections.singletonList(fe3)); | 283 | providerService.pushFlowMetrics(DID, Collections.singletonList(fe3)); |
267 | validateEvents(RULE_ADD_REQUESTED, RULE_ADDED); | 284 | validateEvents(RULE_ADD_REQUESTED, RULE_ADDED); |
268 | 285 | ||
269 | providerService.flowRemoved(fe3); | 286 | providerService.flowRemoved(fe3); |
270 | validateEvents(); | 287 | validateEvents(); |
288 | + | ||
271 | } | 289 | } |
272 | 290 | ||
273 | @Test | 291 | @Test |
... | @@ -281,7 +299,6 @@ public class FlowRuleManagerTest { | ... | @@ -281,7 +299,6 @@ public class FlowRuleManagerTest { |
281 | FlowEntry fe1 = new DefaultFlowEntry(f1); | 299 | FlowEntry fe1 = new DefaultFlowEntry(f1); |
282 | FlowEntry fe2 = new DefaultFlowEntry(f2); | 300 | FlowEntry fe2 = new DefaultFlowEntry(f2); |
283 | 301 | ||
284 | - | ||
285 | //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); | 302 | //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); |
286 | //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); | 303 | //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); |
287 | 304 | ||
... | @@ -388,7 +405,7 @@ public class FlowRuleManagerTest { | ... | @@ -388,7 +405,7 @@ public class FlowRuleManagerTest { |
388 | FlowRuleBatchEntry.FlowRuleOperation.ADD, f2); | 405 | FlowRuleBatchEntry.FlowRuleOperation.ADD, f2); |
389 | 406 | ||
390 | FlowRuleBatchOperation fbo = new FlowRuleBatchOperation( | 407 | FlowRuleBatchOperation fbo = new FlowRuleBatchOperation( |
391 | - Lists.newArrayList(fbe1, fbe2)); | 408 | + Lists.newArrayList(fbe1, fbe2), null, 0); |
392 | Future<CompletedBatchOperation> future = mgr.applyBatch(fbo); | 409 | Future<CompletedBatchOperation> future = mgr.applyBatch(fbo); |
393 | assertTrue("Entries in wrong state", | 410 | assertTrue("Entries in wrong state", |
394 | validateState(ImmutableMap.of( | 411 | validateState(ImmutableMap.of( |
... | @@ -406,53 +423,6 @@ public class FlowRuleManagerTest { | ... | @@ -406,53 +423,6 @@ public class FlowRuleManagerTest { |
406 | 423 | ||
407 | } | 424 | } |
408 | 425 | ||
409 | - @Test | ||
410 | - public void cancelBatch() { | ||
411 | - FlowRule f1 = flowRule(1, 1); | ||
412 | - FlowRule f2 = flowRule(2, 2); | ||
413 | - | ||
414 | - | ||
415 | - mgr.applyFlowRules(f1); | ||
416 | - | ||
417 | - assertTrue("Entries in wrong state", | ||
418 | - validateState(ImmutableMap.of( | ||
419 | - f1, FlowEntryState.PENDING_ADD))); | ||
420 | - | ||
421 | - FlowEntry fe1 = new DefaultFlowEntry(f1); | ||
422 | - providerService.pushFlowMetrics(DID, Collections.<FlowEntry>singletonList(fe1)); | ||
423 | - | ||
424 | - assertTrue("Entries in wrong state", | ||
425 | - validateState(ImmutableMap.of( | ||
426 | - f1, FlowEntryState.ADDED))); | ||
427 | - | ||
428 | - | ||
429 | - FlowRuleBatchEntry fbe1 = new FlowRuleBatchEntry( | ||
430 | - FlowRuleBatchEntry.FlowRuleOperation.REMOVE, f1); | ||
431 | - | ||
432 | - FlowRuleBatchEntry fbe2 = new FlowRuleBatchEntry( | ||
433 | - FlowRuleBatchEntry.FlowRuleOperation.ADD, f2); | ||
434 | - | ||
435 | - FlowRuleBatchOperation fbo = new FlowRuleBatchOperation( | ||
436 | - Lists.newArrayList(fbe1, fbe2)); | ||
437 | - Future<CompletedBatchOperation> future = mgr.applyBatch(fbo); | ||
438 | - | ||
439 | - future.cancel(true); | ||
440 | - | ||
441 | - assertTrue(flowCount() == 2); | ||
442 | - | ||
443 | - /* | ||
444 | - * Rule f1 should be re-added to the list and therefore be in a pending add | ||
445 | - * state. | ||
446 | - */ | ||
447 | - assertTrue("Entries in wrong state", | ||
448 | - validateState(ImmutableMap.of( | ||
449 | - f2, FlowEntryState.PENDING_REMOVE, | ||
450 | - f1, FlowEntryState.PENDING_ADD))); | ||
451 | - | ||
452 | - | ||
453 | - } | ||
454 | - | ||
455 | - | ||
456 | private static class TestListener implements FlowRuleListener { | 426 | private static class TestListener implements FlowRuleListener { |
457 | final List<FlowRuleEvent> events = new ArrayList<>(); | 427 | final List<FlowRuleEvent> events = new ArrayList<>(); |
458 | 428 | ||
... | @@ -528,9 +498,8 @@ public class FlowRuleManagerTest { | ... | @@ -528,9 +498,8 @@ public class FlowRuleManagerTest { |
528 | } | 498 | } |
529 | 499 | ||
530 | @Override | 500 | @Override |
531 | - public ListenableFuture<CompletedBatchOperation> executeBatch( | 501 | + public void executeBatch(FlowRuleBatchOperation batch) { |
532 | - BatchOperation<FlowRuleBatchEntry> batch) { | 502 | + // TODO: need to call batchOperationComplete |
533 | - return new TestInstallationFuture(); | ||
534 | } | 503 | } |
535 | 504 | ||
536 | private class TestInstallationFuture | 505 | private class TestInstallationFuture |
... | @@ -554,14 +523,14 @@ public class FlowRuleManagerTest { | ... | @@ -554,14 +523,14 @@ public class FlowRuleManagerTest { |
554 | @Override | 523 | @Override |
555 | public CompletedBatchOperation get() | 524 | public CompletedBatchOperation get() |
556 | throws InterruptedException, ExecutionException { | 525 | throws InterruptedException, ExecutionException { |
557 | - return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet()); | 526 | + return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null); |
558 | } | 527 | } |
559 | 528 | ||
560 | @Override | 529 | @Override |
561 | public CompletedBatchOperation get(long timeout, TimeUnit unit) | 530 | public CompletedBatchOperation get(long timeout, TimeUnit unit) |
562 | throws InterruptedException, | 531 | throws InterruptedException, |
563 | ExecutionException, TimeoutException { | 532 | ExecutionException, TimeoutException { |
564 | - return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet()); | 533 | + return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null); |
565 | } | 534 | } |
566 | 535 | ||
567 | @Override | 536 | @Override |
... | @@ -644,4 +613,37 @@ public class FlowRuleManagerTest { | ... | @@ -644,4 +613,37 @@ public class FlowRuleManagerTest { |
644 | } | 613 | } |
645 | } | 614 | } |
646 | 615 | ||
616 | + private class TestCoreService implements CoreService { | ||
617 | + @Override | ||
618 | + public Version version() { | ||
619 | + return null; | ||
620 | + } | ||
621 | + | ||
622 | + @Override | ||
623 | + public Set<ApplicationId> getAppIds() { | ||
624 | + return null; | ||
625 | + } | ||
626 | + | ||
627 | + @Override | ||
628 | + public ApplicationId getAppId(Short id) { | ||
629 | + return null; | ||
630 | + } | ||
631 | + | ||
632 | + @Override | ||
633 | + public ApplicationId registerApplication(String identifier) { | ||
634 | + return null; | ||
635 | + } | ||
636 | + | ||
637 | + @Override | ||
638 | + public IdGenerator getIdGenerator(String topic) { | ||
639 | + return new IdGenerator() { | ||
640 | + private AtomicLong counter = new AtomicLong(0); | ||
641 | + @Override | ||
642 | + public long getNewId() { | ||
643 | + return counter.getAndIncrement(); | ||
644 | + } | ||
645 | + }; | ||
646 | + } | ||
647 | + } | ||
648 | + | ||
647 | } | 649 | } | ... | ... |
... | @@ -201,7 +201,7 @@ public class IntentManagerTest { | ... | @@ -201,7 +201,7 @@ public class IntentManagerTest { |
201 | FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue()); | 201 | FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue()); |
202 | List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); | 202 | List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); |
203 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr)); | 203 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr)); |
204 | - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 204 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0)); |
205 | } | 205 | } |
206 | 206 | ||
207 | @Override | 207 | @Override |
... | @@ -209,7 +209,7 @@ public class IntentManagerTest { | ... | @@ -209,7 +209,7 @@ public class IntentManagerTest { |
209 | FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue()); | 209 | FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue()); |
210 | List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); | 210 | List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); |
211 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr)); | 211 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr)); |
212 | - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 212 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0)); |
213 | } | 213 | } |
214 | 214 | ||
215 | @Override | 215 | @Override |
... | @@ -219,7 +219,7 @@ public class IntentManagerTest { | ... | @@ -219,7 +219,7 @@ public class IntentManagerTest { |
219 | List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); | 219 | List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); |
220 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr)); | 220 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr)); |
221 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2)); | 221 | rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2)); |
222 | - return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 222 | + return Lists.newArrayList(new FlowRuleBatchOperation(rules, fr.deviceId(), 0)); |
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ... | ... |
... | @@ -27,6 +27,7 @@ import org.onosproject.net.flow.FlowRule; | ... | @@ -27,6 +27,7 @@ import org.onosproject.net.flow.FlowRule; |
27 | import org.onosproject.net.flow.FlowRuleBatchEntry; | 27 | import org.onosproject.net.flow.FlowRuleBatchEntry; |
28 | import org.onosproject.net.flow.FlowRuleBatchOperation; | 28 | import org.onosproject.net.flow.FlowRuleBatchOperation; |
29 | import org.onosproject.net.flow.FlowRuleListener; | 29 | import org.onosproject.net.flow.FlowRuleListener; |
30 | +import org.onosproject.net.flow.FlowRuleOperations; | ||
30 | import org.onosproject.net.flow.FlowRuleService; | 31 | import org.onosproject.net.flow.FlowRuleService; |
31 | 32 | ||
32 | import com.google.common.collect.ImmutableSet; | 33 | import com.google.common.collect.ImmutableSet; |
... | @@ -45,11 +46,11 @@ public class MockFlowRuleService implements FlowRuleService { | ... | @@ -45,11 +46,11 @@ public class MockFlowRuleService implements FlowRuleService { |
45 | 46 | ||
46 | public void setFuture(boolean success, long intentId) { | 47 | public void setFuture(boolean success, long intentId) { |
47 | if (success) { | 48 | if (success) { |
48 | - future = Futures.immediateFuture(new CompletedBatchOperation(true, Collections.emptySet())); | 49 | + future = Futures.immediateFuture(new CompletedBatchOperation(true, Collections.emptySet(), null)); |
49 | } else { | 50 | } else { |
50 | final Set<Long> failedIds = ImmutableSet.of(intentId); | 51 | final Set<Long> failedIds = ImmutableSet.of(intentId); |
51 | future = Futures.immediateFuture( | 52 | future = Futures.immediateFuture( |
52 | - new CompletedBatchOperation(false, flows, failedIds)); | 53 | + new CompletedBatchOperation(false, flows, failedIds, null)); |
53 | } | 54 | } |
54 | } | 55 | } |
55 | 56 | ||
... | @@ -74,6 +75,11 @@ public class MockFlowRuleService implements FlowRuleService { | ... | @@ -74,6 +75,11 @@ public class MockFlowRuleService implements FlowRuleService { |
74 | } | 75 | } |
75 | 76 | ||
76 | @Override | 77 | @Override |
78 | + public void apply(FlowRuleOperations ops) { | ||
79 | + | ||
80 | + } | ||
81 | + | ||
82 | + @Override | ||
77 | public int getFlowRuleCount() { | 83 | public int getFlowRuleCount() { |
78 | return flows.size(); | 84 | return flows.size(); |
79 | } | 85 | } | ... | ... |
... | @@ -15,33 +15,15 @@ | ... | @@ -15,33 +15,15 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.store.flow.impl; | 16 | package org.onosproject.store.flow.impl; |
17 | 17 | ||
18 | -import static com.google.common.base.Preconditions.checkNotNull; | 18 | +import com.google.common.cache.CacheBuilder; |
19 | -import static org.onlab.util.Tools.namedThreads; | 19 | +import com.google.common.cache.CacheLoader; |
20 | -import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 20 | +import com.google.common.cache.LoadingCache; |
21 | -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.APPLY_BATCH_FLOWS; | 21 | +import com.google.common.collect.ImmutableList; |
22 | -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.GET_DEVICE_FLOW_ENTRIES; | 22 | +import com.google.common.collect.Iterables; |
23 | -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.GET_FLOW_ENTRY; | 23 | +import com.google.common.collect.Maps; |
24 | -import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.REMOVE_FLOW_ENTRY; | 24 | +import com.google.common.collect.Sets; |
25 | -import static org.slf4j.LoggerFactory.getLogger; | 25 | +import com.google.common.util.concurrent.ListenableFuture; |
26 | - | 26 | +import com.hazelcast.core.IMap; |
27 | -import java.io.IOException; | ||
28 | -import java.util.ArrayList; | ||
29 | -import java.util.Arrays; | ||
30 | -import java.util.Collection; | ||
31 | -import java.util.Collections; | ||
32 | -import java.util.HashSet; | ||
33 | -import java.util.List; | ||
34 | -import java.util.Map.Entry; | ||
35 | -import java.util.Set; | ||
36 | -import java.util.concurrent.ExecutionException; | ||
37 | -import java.util.concurrent.ExecutorService; | ||
38 | -import java.util.concurrent.Executors; | ||
39 | -import java.util.concurrent.Future; | ||
40 | -import java.util.concurrent.TimeUnit; | ||
41 | -import java.util.concurrent.TimeoutException; | ||
42 | -import java.util.concurrent.atomic.AtomicInteger; | ||
43 | -import java.util.concurrent.locks.ReentrantReadWriteLock; | ||
44 | - | ||
45 | import org.apache.felix.scr.annotations.Activate; | 27 | import org.apache.felix.scr.annotations.Activate; |
46 | import org.apache.felix.scr.annotations.Component; | 28 | import org.apache.felix.scr.annotations.Component; |
47 | import org.apache.felix.scr.annotations.Deactivate; | 29 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -49,8 +31,11 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -49,8 +31,11 @@ import org.apache.felix.scr.annotations.Reference; |
49 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 31 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
50 | import org.apache.felix.scr.annotations.Service; | 32 | import org.apache.felix.scr.annotations.Service; |
51 | import org.onlab.util.KryoNamespace; | 33 | import org.onlab.util.KryoNamespace; |
34 | +import org.onlab.util.NewConcurrentHashMap; | ||
52 | import org.onosproject.cluster.ClusterService; | 35 | import org.onosproject.cluster.ClusterService; |
53 | import org.onosproject.cluster.NodeId; | 36 | import org.onosproject.cluster.NodeId; |
37 | +import org.onosproject.core.CoreService; | ||
38 | +import org.onosproject.core.IdGenerator; | ||
54 | import org.onosproject.net.Device; | 39 | import org.onosproject.net.Device; |
55 | import org.onosproject.net.DeviceId; | 40 | import org.onosproject.net.DeviceId; |
56 | import org.onosproject.net.device.DeviceService; | 41 | import org.onosproject.net.device.DeviceService; |
... | @@ -67,6 +52,7 @@ import org.onosproject.net.flow.FlowRuleBatchOperation; | ... | @@ -67,6 +52,7 @@ import org.onosproject.net.flow.FlowRuleBatchOperation; |
67 | import org.onosproject.net.flow.FlowRuleBatchRequest; | 52 | import org.onosproject.net.flow.FlowRuleBatchRequest; |
68 | import org.onosproject.net.flow.FlowRuleEvent; | 53 | import org.onosproject.net.flow.FlowRuleEvent; |
69 | import org.onosproject.net.flow.FlowRuleEvent.Type; | 54 | import org.onosproject.net.flow.FlowRuleEvent.Type; |
55 | +import org.onosproject.net.flow.FlowRuleService; | ||
70 | import org.onosproject.net.flow.FlowRuleStore; | 56 | import org.onosproject.net.flow.FlowRuleStore; |
71 | import org.onosproject.net.flow.FlowRuleStoreDelegate; | 57 | import org.onosproject.net.flow.FlowRuleStoreDelegate; |
72 | import org.onosproject.net.flow.StoredFlowEntry; | 58 | import org.onosproject.net.flow.StoredFlowEntry; |
... | @@ -79,27 +65,37 @@ import org.onosproject.store.flow.ReplicaInfoEventListener; | ... | @@ -79,27 +65,37 @@ import org.onosproject.store.flow.ReplicaInfoEventListener; |
79 | import org.onosproject.store.flow.ReplicaInfoService; | 65 | import org.onosproject.store.flow.ReplicaInfoService; |
80 | import org.onosproject.store.hz.AbstractHazelcastStore; | 66 | import org.onosproject.store.hz.AbstractHazelcastStore; |
81 | import org.onosproject.store.hz.SMap; | 67 | import org.onosproject.store.hz.SMap; |
82 | -import org.onosproject.store.serializers.DecodeTo; | ||
83 | import org.onosproject.store.serializers.KryoSerializer; | 68 | import org.onosproject.store.serializers.KryoSerializer; |
84 | import org.onosproject.store.serializers.StoreSerializer; | 69 | import org.onosproject.store.serializers.StoreSerializer; |
85 | import org.onosproject.store.serializers.impl.DistributedStoreSerializers; | 70 | import org.onosproject.store.serializers.impl.DistributedStoreSerializers; |
86 | import org.slf4j.Logger; | 71 | import org.slf4j.Logger; |
87 | 72 | ||
88 | -import com.google.common.cache.Cache; | 73 | +import java.io.IOException; |
89 | -import com.google.common.cache.CacheBuilder; | 74 | +import java.util.ArrayList; |
90 | -import com.google.common.cache.CacheLoader; | 75 | +import java.util.Arrays; |
91 | -import com.google.common.cache.LoadingCache; | 76 | +import java.util.Collections; |
92 | -import com.google.common.cache.RemovalListener; | 77 | +import java.util.HashSet; |
93 | -import com.google.common.cache.RemovalNotification; | 78 | +import java.util.List; |
94 | -import com.google.common.collect.ArrayListMultimap; | 79 | +import java.util.Map; |
95 | -import com.google.common.collect.ImmutableList; | 80 | +import java.util.Map.Entry; |
96 | -import com.google.common.collect.ImmutableSet; | 81 | +import java.util.Set; |
97 | -import com.google.common.collect.Iterables; | 82 | +import java.util.concurrent.ConcurrentHashMap; |
98 | -import com.google.common.collect.Multimap; | 83 | +import java.util.concurrent.ConcurrentMap; |
99 | -import com.google.common.util.concurrent.Futures; | 84 | +import java.util.concurrent.CopyOnWriteArraySet; |
100 | -import com.google.common.util.concurrent.ListenableFuture; | 85 | +import java.util.concurrent.ExecutionException; |
101 | -import com.google.common.util.concurrent.SettableFuture; | 86 | +import java.util.concurrent.ExecutorService; |
102 | -import com.hazelcast.core.IMap; | 87 | +import java.util.concurrent.Executors; |
88 | +import java.util.concurrent.Future; | ||
89 | +import java.util.concurrent.TimeUnit; | ||
90 | +import java.util.concurrent.TimeoutException; | ||
91 | +import java.util.stream.Collectors; | ||
92 | + | ||
93 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
94 | +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | ||
95 | +import static org.onlab.util.Tools.namedThreads; | ||
96 | +import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ||
97 | +import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.*; | ||
98 | +import static org.slf4j.LoggerFactory.getLogger; | ||
103 | 99 | ||
104 | /** | 100 | /** |
105 | * Manages inventory of flow rules using a distributed state management protocol. | 101 | * Manages inventory of flow rules using a distributed state management protocol. |
... | @@ -112,12 +108,10 @@ public class DistributedFlowRuleStore | ... | @@ -112,12 +108,10 @@ public class DistributedFlowRuleStore |
112 | 108 | ||
113 | private final Logger log = getLogger(getClass()); | 109 | private final Logger log = getLogger(getClass()); |
114 | 110 | ||
115 | - // primary data: | 111 | + private InternalFlowTable flowTable = new InternalFlowTable(); |
116 | - // read/write needs to be locked | 112 | + |
117 | - private final ReentrantReadWriteLock flowEntriesLock = new ReentrantReadWriteLock(); | 113 | + /*private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, Set<StoredFlowEntry>>> |
118 | - // store entries as a pile of rules, no info about device tables | 114 | + flowEntries = new ConcurrentHashMap<>();*/ |
119 | - private final Multimap<DeviceId, StoredFlowEntry> flowEntries | ||
120 | - = ArrayListMultimap.<DeviceId, StoredFlowEntry>create(); | ||
121 | 115 | ||
122 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 116 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
123 | protected ReplicaInfoService replicaInfoManager; | 117 | protected ReplicaInfoService replicaInfoManager; |
... | @@ -131,23 +125,15 @@ public class DistributedFlowRuleStore | ... | @@ -131,23 +125,15 @@ public class DistributedFlowRuleStore |
131 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 125 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
132 | protected DeviceService deviceService; | 126 | protected DeviceService deviceService; |
133 | 127 | ||
134 | - private final AtomicInteger localBatchIdGen = new AtomicInteger(); | 128 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
135 | - | 129 | + protected CoreService coreService; |
136 | - private int pendingFutureTimeoutMinutes = 5; | ||
137 | 130 | ||
138 | - private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = | 131 | + private Map<Long, NodeId> pendingResponses = Maps.newConcurrentMap(); |
139 | - CacheBuilder.newBuilder() | ||
140 | - .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES) | ||
141 | - .removalListener(new TimeoutFuture()) | ||
142 | - .build(); | ||
143 | 132 | ||
144 | // Cache of SMaps used for backup data. each SMap contain device flow table | 133 | // Cache of SMaps used for backup data. each SMap contain device flow table |
145 | private LoadingCache<DeviceId, SMap<FlowId, ImmutableList<StoredFlowEntry>>> smaps; | 134 | private LoadingCache<DeviceId, SMap<FlowId, ImmutableList<StoredFlowEntry>>> smaps; |
146 | 135 | ||
147 | 136 | ||
148 | - private final ExecutorService futureListeners = | ||
149 | - Executors.newCachedThreadPool(namedThreads("onos-flowstore-peer-responders")); | ||
150 | - | ||
151 | private final ExecutorService backupExecutors = | 137 | private final ExecutorService backupExecutors = |
152 | Executors.newSingleThreadExecutor(namedThreads("onos-async-backups")); | 138 | Executors.newSingleThreadExecutor(namedThreads("onos-async-backups")); |
153 | 139 | ||
... | @@ -169,6 +155,8 @@ public class DistributedFlowRuleStore | ... | @@ -169,6 +155,8 @@ public class DistributedFlowRuleStore |
169 | 155 | ||
170 | private ReplicaInfoEventListener replicaInfoEventListener; | 156 | private ReplicaInfoEventListener replicaInfoEventListener; |
171 | 157 | ||
158 | + private IdGenerator idGenerator; | ||
159 | + | ||
172 | @Override | 160 | @Override |
173 | @Activate | 161 | @Activate |
174 | public void activate() { | 162 | public void activate() { |
... | @@ -176,6 +164,8 @@ public class DistributedFlowRuleStore | ... | @@ -176,6 +164,8 @@ public class DistributedFlowRuleStore |
176 | super.serializer = SERIALIZER; | 164 | super.serializer = SERIALIZER; |
177 | super.theInstance = storeService.getHazelcastInstance(); | 165 | super.theInstance = storeService.getHazelcastInstance(); |
178 | 166 | ||
167 | + idGenerator = coreService.getIdGenerator(FlowRuleService.FLOW_OP_TOPIC); | ||
168 | + | ||
179 | // Cache to create SMap on demand | 169 | // Cache to create SMap on demand |
180 | smaps = CacheBuilder.newBuilder() | 170 | smaps = CacheBuilder.newBuilder() |
181 | .softValues() | 171 | .softValues() |
... | @@ -185,13 +175,22 @@ public class DistributedFlowRuleStore | ... | @@ -185,13 +175,22 @@ public class DistributedFlowRuleStore |
185 | 175 | ||
186 | clusterCommunicator.addSubscriber(APPLY_BATCH_FLOWS, new OnStoreBatch(local)); | 176 | clusterCommunicator.addSubscriber(APPLY_BATCH_FLOWS, new OnStoreBatch(local)); |
187 | 177 | ||
178 | + clusterCommunicator.addSubscriber(REMOTE_APPLY_COMPLETED, new ClusterMessageHandler() { | ||
179 | + @Override | ||
180 | + public void handle(ClusterMessage message) { | ||
181 | + FlowRuleBatchEvent event = SERIALIZER.decode(message.payload()); | ||
182 | + log.trace("received completed notification for {}", event); | ||
183 | + notifyDelegate(event); | ||
184 | + } | ||
185 | + }); | ||
186 | + | ||
188 | clusterCommunicator.addSubscriber(GET_FLOW_ENTRY, new ClusterMessageHandler() { | 187 | clusterCommunicator.addSubscriber(GET_FLOW_ENTRY, new ClusterMessageHandler() { |
189 | 188 | ||
190 | @Override | 189 | @Override |
191 | public void handle(ClusterMessage message) { | 190 | public void handle(ClusterMessage message) { |
192 | FlowRule rule = SERIALIZER.decode(message.payload()); | 191 | FlowRule rule = SERIALIZER.decode(message.payload()); |
193 | log.trace("received get flow entry request for {}", rule); | 192 | log.trace("received get flow entry request for {}", rule); |
194 | - FlowEntry flowEntry = getFlowEntryInternal(rule); | 193 | + FlowEntry flowEntry = flowTable.getFlowEntry(rule); //getFlowEntryInternal(rule); |
195 | try { | 194 | try { |
196 | message.respond(SERIALIZER.encode(flowEntry)); | 195 | message.respond(SERIALIZER.encode(flowEntry)); |
197 | } catch (IOException e) { | 196 | } catch (IOException e) { |
... | @@ -206,7 +205,7 @@ public class DistributedFlowRuleStore | ... | @@ -206,7 +205,7 @@ public class DistributedFlowRuleStore |
206 | public void handle(ClusterMessage message) { | 205 | public void handle(ClusterMessage message) { |
207 | DeviceId deviceId = SERIALIZER.decode(message.payload()); | 206 | DeviceId deviceId = SERIALIZER.decode(message.payload()); |
208 | log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); | 207 | log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); |
209 | - Set<FlowEntry> flowEntries = getFlowEntriesInternal(deviceId); | 208 | + Set<FlowEntry> flowEntries = flowTable.getFlowEntries(deviceId); |
210 | try { | 209 | try { |
211 | message.respond(SERIALIZER.encode(flowEntries)); | 210 | message.respond(SERIALIZER.encode(flowEntries)); |
212 | } catch (IOException e) { | 211 | } catch (IOException e) { |
... | @@ -272,7 +271,7 @@ public class DistributedFlowRuleStore | ... | @@ -272,7 +271,7 @@ public class DistributedFlowRuleStore |
272 | } | 271 | } |
273 | 272 | ||
274 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 273 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
275 | - return getFlowEntryInternal(rule); | 274 | + return flowTable.getFlowEntry(rule); |
276 | } | 275 | } |
277 | 276 | ||
278 | log.trace("Forwarding getFlowEntry to {}, which is the primary (master) for device {}", | 277 | log.trace("Forwarding getFlowEntry to {}, which is the primary (master) for device {}", |
... | @@ -292,19 +291,7 @@ public class DistributedFlowRuleStore | ... | @@ -292,19 +291,7 @@ public class DistributedFlowRuleStore |
292 | return null; | 291 | return null; |
293 | } | 292 | } |
294 | 293 | ||
295 | - private StoredFlowEntry getFlowEntryInternal(FlowRule rule) { | 294 | + |
296 | - flowEntriesLock.readLock().lock(); | ||
297 | - try { | ||
298 | - for (StoredFlowEntry f : flowEntries.get(rule.deviceId())) { | ||
299 | - if (f.equals(rule)) { | ||
300 | - return f; | ||
301 | - } | ||
302 | - } | ||
303 | - } finally { | ||
304 | - flowEntriesLock.readLock().unlock(); | ||
305 | - } | ||
306 | - return null; | ||
307 | - } | ||
308 | 295 | ||
309 | @Override | 296 | @Override |
310 | public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) { | 297 | public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) { |
... | @@ -317,7 +304,7 @@ public class DistributedFlowRuleStore | ... | @@ -317,7 +304,7 @@ public class DistributedFlowRuleStore |
317 | } | 304 | } |
318 | 305 | ||
319 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 306 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
320 | - return getFlowEntriesInternal(deviceId); | 307 | + return flowTable.getFlowEntries(deviceId); |
321 | } | 308 | } |
322 | 309 | ||
323 | log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}", | 310 | log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}", |
... | @@ -337,30 +324,26 @@ public class DistributedFlowRuleStore | ... | @@ -337,30 +324,26 @@ public class DistributedFlowRuleStore |
337 | return Collections.emptyList(); | 324 | return Collections.emptyList(); |
338 | } | 325 | } |
339 | 326 | ||
340 | - private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) { | 327 | + |
341 | - flowEntriesLock.readLock().lock(); | ||
342 | - try { | ||
343 | - Collection<? extends FlowEntry> rules = flowEntries.get(deviceId); | ||
344 | - if (rules == null) { | ||
345 | - return Collections.emptySet(); | ||
346 | - } | ||
347 | - return ImmutableSet.copyOf(rules); | ||
348 | - } finally { | ||
349 | - flowEntriesLock.readLock().unlock(); | ||
350 | - } | ||
351 | - } | ||
352 | 328 | ||
353 | @Override | 329 | @Override |
354 | public void storeFlowRule(FlowRule rule) { | 330 | public void storeFlowRule(FlowRule rule) { |
355 | - storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)))); | 331 | + storeBatch(new FlowRuleBatchOperation( |
332 | + Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)), | ||
333 | + rule.deviceId(), idGenerator.getNewId())); | ||
356 | } | 334 | } |
357 | 335 | ||
358 | @Override | 336 | @Override |
359 | - public Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation operation) { | 337 | + public void storeBatch(FlowRuleBatchOperation operation) { |
338 | + | ||
360 | 339 | ||
361 | if (operation.getOperations().isEmpty()) { | 340 | if (operation.getOperations().isEmpty()) { |
362 | - return Futures.immediateFuture(new CompletedBatchOperation(true, | 341 | + |
363 | - Collections.<FlowRule>emptySet())); | 342 | + notifyDelegate(FlowRuleBatchEvent.completed( |
343 | + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), | ||
344 | + new CompletedBatchOperation(true, Collections.emptySet(), | ||
345 | + operation.deviceId()))); | ||
346 | + return; | ||
364 | } | 347 | } |
365 | 348 | ||
366 | DeviceId deviceId = operation.getOperations().get(0).target().deviceId(); | 349 | DeviceId deviceId = operation.getOperations().get(0).target().deviceId(); |
... | @@ -369,14 +352,21 @@ public class DistributedFlowRuleStore | ... | @@ -369,14 +352,21 @@ public class DistributedFlowRuleStore |
369 | 352 | ||
370 | if (!replicaInfo.master().isPresent()) { | 353 | if (!replicaInfo.master().isPresent()) { |
371 | log.warn("Failed to storeBatch: No master for {}", deviceId); | 354 | log.warn("Failed to storeBatch: No master for {}", deviceId); |
372 | - // TODO: revisit if this should be "success" from Future point of view | 355 | + |
373 | - // with every FlowEntry failed | 356 | + Set<FlowRule> allFailures = operation.getOperations().stream() |
374 | - return Futures.immediateFailedFuture(new IOException("Failed to storeBatch: No master for " + deviceId)); | 357 | + .map(op -> op.getTarget()) |
358 | + .collect(Collectors.toSet()); | ||
359 | + | ||
360 | + notifyDelegate(FlowRuleBatchEvent.completed( | ||
361 | + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), | ||
362 | + new CompletedBatchOperation(false, allFailures, operation.deviceId()))); | ||
363 | + return; | ||
375 | } | 364 | } |
376 | 365 | ||
377 | final NodeId local = clusterService.getLocalNode().id(); | 366 | final NodeId local = clusterService.getLocalNode().id(); |
378 | if (replicaInfo.master().get().equals(local)) { | 367 | if (replicaInfo.master().get().equals(local)) { |
379 | - return storeBatchInternal(operation); | 368 | + storeBatchInternal(operation); |
369 | + return; | ||
380 | } | 370 | } |
381 | 371 | ||
382 | log.trace("Forwarding storeBatch to {}, which is the primary (master) for device {}", | 372 | log.trace("Forwarding storeBatch to {}, which is the primary (master) for device {}", |
... | @@ -387,92 +377,104 @@ public class DistributedFlowRuleStore | ... | @@ -387,92 +377,104 @@ public class DistributedFlowRuleStore |
387 | APPLY_BATCH_FLOWS, | 377 | APPLY_BATCH_FLOWS, |
388 | SERIALIZER.encode(operation)); | 378 | SERIALIZER.encode(operation)); |
389 | 379 | ||
380 | + //CompletedBatchOperation response; | ||
390 | try { | 381 | try { |
391 | ListenableFuture<byte[]> responseFuture = | 382 | ListenableFuture<byte[]> responseFuture = |
392 | clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); | 383 | clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); |
393 | - return Futures.transform(responseFuture, new DecodeTo<CompletedBatchOperation>(SERIALIZER)); | 384 | + /*response = |
394 | - } catch (IOException e) { | 385 | + Futures.transform(responseFuture, |
395 | - return Futures.immediateFailedFuture(e); | 386 | + new DecodeTo<CompletedBatchOperation>(SERIALIZER)) |
387 | + .get(500 * operation.size(), TimeUnit.MILLISECONDS); | ||
388 | + | ||
389 | + notifyDelegate(FlowRuleBatchEvent.completed( | ||
390 | + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), response));*/ | ||
391 | + | ||
392 | + } catch (IOException /*| InterruptedException | ExecutionException | TimeoutException*/ e) { | ||
393 | + log.warn("Failed to storeBatch: {}", e.getMessage()); | ||
394 | + | ||
395 | + Set<FlowRule> allFailures = operation.getOperations().stream() | ||
396 | + .map(op -> op.getTarget()) | ||
397 | + .collect(Collectors.toSet()); | ||
398 | + | ||
399 | + notifyDelegate(FlowRuleBatchEvent.completed( | ||
400 | + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), | ||
401 | + new CompletedBatchOperation(false, allFailures, deviceId))); | ||
402 | + return; | ||
396 | } | 403 | } |
404 | + | ||
397 | } | 405 | } |
398 | 406 | ||
399 | - private ListenableFuture<CompletedBatchOperation> | 407 | + private void storeBatchInternal(FlowRuleBatchOperation operation) { |
400 | - storeBatchInternal(FlowRuleBatchOperation operation) { | ||
401 | 408 | ||
402 | - final List<FlowRuleBatchEntry> toRemove = new ArrayList<>(); | 409 | + final DeviceId did = operation.deviceId(); |
403 | - final List<FlowRuleBatchEntry> toAdd = new ArrayList<>(); | 410 | + //final Collection<FlowEntry> ft = flowTable.getFlowEntries(did); |
404 | - DeviceId did = null; | 411 | + Set<FlowRuleBatchEntry> currentOps; |
405 | 412 | ||
406 | 413 | ||
407 | - flowEntriesLock.writeLock().lock(); | 414 | + currentOps = operation.getOperations().stream().map( |
408 | - try { | 415 | + op -> { |
409 | - for (FlowRuleBatchEntry batchEntry : operation.getOperations()) { | 416 | + StoredFlowEntry entry; |
410 | - FlowRule flowRule = batchEntry.target(); | 417 | + switch (op.getOperator()) { |
411 | - FlowRuleOperation op = batchEntry.operator(); | 418 | + case ADD: |
412 | - if (did == null) { | 419 | + entry = new DefaultFlowEntry(op.getTarget()); |
413 | - did = flowRule.deviceId(); | 420 | + // always add requested FlowRule |
414 | - } | 421 | + // Note: 2 equal FlowEntry may have different treatment |
415 | - if (op.equals(FlowRuleOperation.REMOVE)) { | 422 | + flowTable.remove(entry.deviceId(), entry); |
416 | - StoredFlowEntry entry = getFlowEntryInternal(flowRule); | 423 | + flowTable.add(entry); |
424 | + | ||
425 | + return op; | ||
426 | + case REMOVE: | ||
427 | + entry = flowTable.getFlowEntry(op.target()); | ||
417 | if (entry != null) { | 428 | if (entry != null) { |
418 | entry.setState(FlowEntryState.PENDING_REMOVE); | 429 | entry.setState(FlowEntryState.PENDING_REMOVE); |
419 | - toRemove.add(batchEntry); | 430 | + return op; |
420 | } | 431 | } |
421 | - } else if (op.equals(FlowRuleOperation.ADD)) { | 432 | + break; |
422 | - StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); | 433 | + case MODIFY: |
423 | - DeviceId deviceId = flowRule.deviceId(); | 434 | + //TODO: figure this out at some point |
424 | - Collection<StoredFlowEntry> ft = flowEntries.get(deviceId); | 435 | + break; |
425 | - | 436 | + default: |
426 | - // always add requested FlowRule | 437 | + log.warn("Unknown flow operation operator: {}", op.getOperator()); |
427 | - // Note: 2 equal FlowEntry may have different treatment | ||
428 | - ft.remove(flowEntry); | ||
429 | - ft.add(flowEntry); | ||
430 | - toAdd.add(batchEntry); | ||
431 | } | 438 | } |
439 | + return null; | ||
432 | } | 440 | } |
433 | - if (toAdd.isEmpty() && toRemove.isEmpty()) { | 441 | + ).filter(op -> op != null).collect(Collectors.toSet()); |
434 | - return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowRule>emptySet())); | 442 | + if (currentOps.isEmpty()) { |
443 | + batchOperationComplete(FlowRuleBatchEvent.completed( | ||
444 | + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), | ||
445 | + new CompletedBatchOperation(true, Collections.emptySet(), did))); | ||
446 | + return; | ||
435 | } | 447 | } |
448 | + updateBackup(did, currentOps); | ||
436 | 449 | ||
437 | - // create remote backup copies | ||
438 | - updateBackup(did, toAdd, toRemove); | ||
439 | - } finally { | ||
440 | - flowEntriesLock.writeLock().unlock(); | ||
441 | - } | ||
442 | 450 | ||
443 | - SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); | 451 | + notifyDelegate(FlowRuleBatchEvent.requested(new |
444 | - final int batchId = localBatchIdGen.incrementAndGet(); | 452 | + FlowRuleBatchRequest(operation.id(), currentOps), operation.deviceId())); |
445 | 453 | ||
446 | - pendingFutures.put(batchId, r); | ||
447 | - notifyDelegate(FlowRuleBatchEvent.requested(new FlowRuleBatchRequest(batchId, toAdd, toRemove))); | ||
448 | 454 | ||
449 | - return r; | ||
450 | } | 455 | } |
451 | 456 | ||
452 | - private void updateBackup(final DeviceId deviceId, | 457 | + private void updateBackup(DeviceId deviceId, final Set<FlowRuleBatchEntry> entries) { |
453 | - final List<FlowRuleBatchEntry> toAdd, | 458 | + Future<?> backup = backupExecutors.submit(new UpdateBackup(deviceId, entries)); |
454 | - final List<FlowRuleBatchEntry> list) { | ||
455 | - | ||
456 | - Future<?> submit = backupExecutors.submit(new UpdateBackup(deviceId, toAdd, list)); | ||
457 | 459 | ||
458 | if (syncBackup) { | 460 | if (syncBackup) { |
459 | // wait for backup to complete | 461 | // wait for backup to complete |
460 | try { | 462 | try { |
461 | - submit.get(); | 463 | + backup.get(); |
462 | } catch (InterruptedException | ExecutionException e) { | 464 | } catch (InterruptedException | ExecutionException e) { |
463 | log.error("Failed to create backups", e); | 465 | log.error("Failed to create backups", e); |
464 | } | 466 | } |
465 | } | 467 | } |
466 | } | 468 | } |
467 | 469 | ||
468 | - private void updateBackup(DeviceId deviceId, List<FlowRuleBatchEntry> toAdd) { | ||
469 | - | ||
470 | - updateBackup(deviceId, toAdd, Collections.<FlowRuleBatchEntry>emptyList()); | ||
471 | - } | ||
472 | - | ||
473 | @Override | 470 | @Override |
474 | public void deleteFlowRule(FlowRule rule) { | 471 | public void deleteFlowRule(FlowRule rule) { |
475 | - storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule)))); | 472 | + storeBatch( |
473 | + new FlowRuleBatchOperation( | ||
474 | + Arrays.asList( | ||
475 | + new FlowRuleBatchEntry( | ||
476 | + FlowRuleOperation.REMOVE, | ||
477 | + rule)), rule.deviceId(), idGenerator.getNewId())); | ||
476 | } | 478 | } |
477 | 479 | ||
478 | @Override | 480 | @Override |
... | @@ -491,10 +493,9 @@ public class DistributedFlowRuleStore | ... | @@ -491,10 +493,9 @@ public class DistributedFlowRuleStore |
491 | private FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { | 493 | private FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { |
492 | final DeviceId did = rule.deviceId(); | 494 | final DeviceId did = rule.deviceId(); |
493 | 495 | ||
494 | - flowEntriesLock.writeLock().lock(); | 496 | + |
495 | - try { | ||
496 | // check if this new rule is an update to an existing entry | 497 | // check if this new rule is an update to an existing entry |
497 | - StoredFlowEntry stored = getFlowEntryInternal(rule); | 498 | + StoredFlowEntry stored = flowTable.getFlowEntry(rule); |
498 | if (stored != null) { | 499 | if (stored != null) { |
499 | stored.setBytes(rule.bytes()); | 500 | stored.setBytes(rule.bytes()); |
500 | stored.setLife(rule.life()); | 501 | stored.setLife(rule.life()); |
... | @@ -503,7 +504,7 @@ public class DistributedFlowRuleStore | ... | @@ -503,7 +504,7 @@ public class DistributedFlowRuleStore |
503 | stored.setState(FlowEntryState.ADDED); | 504 | stored.setState(FlowEntryState.ADDED); |
504 | FlowRuleBatchEntry entry = | 505 | FlowRuleBatchEntry entry = |
505 | new FlowRuleBatchEntry(FlowRuleOperation.ADD, stored); | 506 | new FlowRuleBatchEntry(FlowRuleOperation.ADD, stored); |
506 | - updateBackup(did, Arrays.asList(entry)); | 507 | + updateBackup(did, Sets.newHashSet(entry)); |
507 | return new FlowRuleEvent(Type.RULE_ADDED, rule); | 508 | return new FlowRuleEvent(Type.RULE_ADDED, rule); |
508 | } | 509 | } |
509 | return new FlowRuleEvent(Type.RULE_UPDATED, rule); | 510 | return new FlowRuleEvent(Type.RULE_UPDATED, rule); |
... | @@ -511,10 +512,9 @@ public class DistributedFlowRuleStore | ... | @@ -511,10 +512,9 @@ public class DistributedFlowRuleStore |
511 | 512 | ||
512 | // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore | 513 | // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore |
513 | // TODO: also update backup if the behavior is correct. | 514 | // TODO: also update backup if the behavior is correct. |
514 | - flowEntries.put(did, new DefaultFlowEntry(rule)); | 515 | + flowTable.add(rule); |
515 | - } finally { | 516 | + |
516 | - flowEntriesLock.writeLock().unlock(); | 517 | + |
517 | - } | ||
518 | return null; | 518 | return null; |
519 | 519 | ||
520 | } | 520 | } |
... | @@ -555,38 +555,42 @@ public class DistributedFlowRuleStore | ... | @@ -555,38 +555,42 @@ public class DistributedFlowRuleStore |
555 | 555 | ||
556 | private FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) { | 556 | private FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) { |
557 | final DeviceId deviceId = rule.deviceId(); | 557 | final DeviceId deviceId = rule.deviceId(); |
558 | - flowEntriesLock.writeLock().lock(); | ||
559 | - try { | ||
560 | // This is where one could mark a rule as removed and still keep it in the store. | 558 | // This is where one could mark a rule as removed and still keep it in the store. |
561 | - final boolean removed = flowEntries.remove(deviceId, rule); | 559 | + final boolean removed = flowTable.remove(deviceId, rule); //flowEntries.remove(deviceId, rule); |
562 | FlowRuleBatchEntry entry = | 560 | FlowRuleBatchEntry entry = |
563 | new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule); | 561 | new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule); |
564 | - updateBackup(deviceId, Collections.<FlowRuleBatchEntry>emptyList(), Arrays.asList(entry)); | 562 | + updateBackup(deviceId, Sets.newHashSet(entry)); |
565 | if (removed) { | 563 | if (removed) { |
566 | return new FlowRuleEvent(RULE_REMOVED, rule); | 564 | return new FlowRuleEvent(RULE_REMOVED, rule); |
567 | } else { | 565 | } else { |
568 | return null; | 566 | return null; |
569 | } | 567 | } |
570 | - } finally { | 568 | + |
571 | - flowEntriesLock.writeLock().unlock(); | ||
572 | - } | ||
573 | } | 569 | } |
574 | 570 | ||
575 | @Override | 571 | @Override |
576 | public void batchOperationComplete(FlowRuleBatchEvent event) { | 572 | public void batchOperationComplete(FlowRuleBatchEvent event) { |
577 | - final Integer batchId = event.subject().batchId(); | 573 | + //FIXME: need a per device pending response |
578 | - SettableFuture<CompletedBatchOperation> future | 574 | + |
579 | - = pendingFutures.getIfPresent(batchId); | 575 | + NodeId nodeId = pendingResponses.remove(event.subject().batchId()); |
580 | - if (future != null) { | 576 | + if (nodeId == null) { |
581 | - future.set(event.result()); | ||
582 | - pendingFutures.invalidate(batchId); | ||
583 | - } | ||
584 | notifyDelegate(event); | 577 | notifyDelegate(event); |
578 | + } else { | ||
579 | + try { | ||
580 | + ClusterMessage message = new ClusterMessage( | ||
581 | + clusterService.getLocalNode().id(), | ||
582 | + REMOTE_APPLY_COMPLETED, | ||
583 | + SERIALIZER.encode(event)); | ||
584 | + clusterCommunicator.sendAndReceive(message, nodeId); | ||
585 | + } catch (IOException e) { | ||
586 | + log.warn("Failed to respond to peer for batch operation result"); | ||
587 | + } | ||
588 | + } | ||
585 | } | 589 | } |
586 | 590 | ||
587 | private void loadFromBackup(final DeviceId did) { | 591 | private void loadFromBackup(final DeviceId did) { |
588 | 592 | ||
589 | - flowEntriesLock.writeLock().lock(); | 593 | + |
590 | try { | 594 | try { |
591 | log.debug("Loading FlowRules for {} from backups", did); | 595 | log.debug("Loading FlowRules for {} from backups", did); |
592 | SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did); | 596 | SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did); |
... | @@ -595,38 +599,21 @@ public class DistributedFlowRuleStore | ... | @@ -595,38 +599,21 @@ public class DistributedFlowRuleStore |
595 | 599 | ||
596 | log.trace("loading {}", e.getValue()); | 600 | log.trace("loading {}", e.getValue()); |
597 | for (StoredFlowEntry entry : e.getValue()) { | 601 | for (StoredFlowEntry entry : e.getValue()) { |
598 | - flowEntries.remove(did, entry); | 602 | + flowTable.getFlowEntriesById(entry).remove(entry); |
599 | - flowEntries.put(did, entry); | 603 | + flowTable.getFlowEntriesById(entry).add(entry); |
604 | + | ||
605 | + | ||
600 | } | 606 | } |
601 | } | 607 | } |
602 | } catch (ExecutionException e) { | 608 | } catch (ExecutionException e) { |
603 | log.error("Failed to load backup flowtable for {}", did, e); | 609 | log.error("Failed to load backup flowtable for {}", did, e); |
604 | - } finally { | ||
605 | - flowEntriesLock.writeLock().unlock(); | ||
606 | } | 610 | } |
607 | } | 611 | } |
608 | 612 | ||
609 | private void removeFromPrimary(final DeviceId did) { | 613 | private void removeFromPrimary(final DeviceId did) { |
610 | - Collection<StoredFlowEntry> removed = null; | 614 | + flowTable.clearDevice(did); |
611 | - flowEntriesLock.writeLock().lock(); | ||
612 | - try { | ||
613 | - removed = flowEntries.removeAll(did); | ||
614 | - } finally { | ||
615 | - flowEntriesLock.writeLock().unlock(); | ||
616 | - } | ||
617 | - log.trace("removedFromPrimary {}", removed); | ||
618 | } | 615 | } |
619 | 616 | ||
620 | - private static final class TimeoutFuture | ||
621 | - implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> { | ||
622 | - @Override | ||
623 | - public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) { | ||
624 | - // wrapping in ExecutionException to support Future.get | ||
625 | - notification.getValue() | ||
626 | - .setException(new ExecutionException("Timed out", | ||
627 | - new TimeoutException())); | ||
628 | - } | ||
629 | - } | ||
630 | 617 | ||
631 | private final class OnStoreBatch implements ClusterMessageHandler { | 618 | private final class OnStoreBatch implements ClusterMessageHandler { |
632 | private final NodeId local; | 619 | private final NodeId local; |
... | @@ -640,7 +627,7 @@ public class DistributedFlowRuleStore | ... | @@ -640,7 +627,7 @@ public class DistributedFlowRuleStore |
640 | FlowRuleBatchOperation operation = SERIALIZER.decode(message.payload()); | 627 | FlowRuleBatchOperation operation = SERIALIZER.decode(message.payload()); |
641 | log.debug("received batch request {}", operation); | 628 | log.debug("received batch request {}", operation); |
642 | 629 | ||
643 | - final DeviceId deviceId = operation.getOperations().get(0).target().deviceId(); | 630 | + final DeviceId deviceId = operation.deviceId(); |
644 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); | 631 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); |
645 | if (!local.equals(replicaInfo.master().orNull())) { | 632 | if (!local.equals(replicaInfo.master().orNull())) { |
646 | 633 | ||
... | @@ -648,7 +635,7 @@ public class DistributedFlowRuleStore | ... | @@ -648,7 +635,7 @@ public class DistributedFlowRuleStore |
648 | for (FlowRuleBatchEntry op : operation.getOperations()) { | 635 | for (FlowRuleBatchEntry op : operation.getOperations()) { |
649 | failures.add(op.target()); | 636 | failures.add(op.target()); |
650 | } | 637 | } |
651 | - CompletedBatchOperation allFailed = new CompletedBatchOperation(false, failures); | 638 | + CompletedBatchOperation allFailed = new CompletedBatchOperation(false, failures, deviceId); |
652 | // This node is no longer the master, respond as all failed. | 639 | // This node is no longer the master, respond as all failed. |
653 | // TODO: we might want to wrap response in envelope | 640 | // TODO: we might want to wrap response in envelope |
654 | // to distinguish sw programming failure and hand over | 641 | // to distinguish sw programming failure and hand over |
... | @@ -661,31 +648,10 @@ public class DistributedFlowRuleStore | ... | @@ -661,31 +648,10 @@ public class DistributedFlowRuleStore |
661 | return; | 648 | return; |
662 | } | 649 | } |
663 | 650 | ||
664 | - final ListenableFuture<CompletedBatchOperation> f = storeBatchInternal(operation); | ||
665 | 651 | ||
666 | - f.addListener(new Runnable() { | 652 | + pendingResponses.put(operation.id(), message.sender()); |
653 | + storeBatchInternal(operation); | ||
667 | 654 | ||
668 | - @Override | ||
669 | - public void run() { | ||
670 | - CompletedBatchOperation result; | ||
671 | - try { | ||
672 | - result = f.get(); | ||
673 | - } catch (InterruptedException | ExecutionException e) { | ||
674 | - log.error("Batch operation failed", e); | ||
675 | - // create everything failed response | ||
676 | - Set<FlowRule> failures = new HashSet<>(operation.size()); | ||
677 | - for (FlowRuleBatchEntry op : operation.getOperations()) { | ||
678 | - failures.add(op.target()); | ||
679 | - } | ||
680 | - result = new CompletedBatchOperation(false, failures); | ||
681 | - } | ||
682 | - try { | ||
683 | - message.respond(SERIALIZER.encode(result)); | ||
684 | - } catch (IOException e) { | ||
685 | - log.error("Failed to respond back", e); | ||
686 | - } | ||
687 | - } | ||
688 | - }, futureListeners); | ||
689 | } | 655 | } |
690 | } | 656 | } |
691 | 657 | ||
... | @@ -731,39 +697,40 @@ public class DistributedFlowRuleStore | ... | @@ -731,39 +697,40 @@ public class DistributedFlowRuleStore |
731 | } | 697 | } |
732 | 698 | ||
733 | // Task to update FlowEntries in backup HZ store | 699 | // Task to update FlowEntries in backup HZ store |
734 | - // TODO: Should be refactored to contain only one list and not | ||
735 | - // toAdd and toRemove | ||
736 | private final class UpdateBackup implements Runnable { | 700 | private final class UpdateBackup implements Runnable { |
737 | 701 | ||
738 | private final DeviceId deviceId; | 702 | private final DeviceId deviceId; |
739 | - private final List<FlowRuleBatchEntry> toAdd; | 703 | + private final Set<FlowRuleBatchEntry> ops; |
740 | - private final List<FlowRuleBatchEntry> toRemove; | 704 | + |
741 | 705 | ||
742 | public UpdateBackup(DeviceId deviceId, | 706 | public UpdateBackup(DeviceId deviceId, |
743 | - List<FlowRuleBatchEntry> toAdd, | 707 | + Set<FlowRuleBatchEntry> ops) { |
744 | - List<FlowRuleBatchEntry> list) { | ||
745 | this.deviceId = checkNotNull(deviceId); | 708 | this.deviceId = checkNotNull(deviceId); |
746 | - this.toAdd = checkNotNull(toAdd); | 709 | + this.ops = checkNotNull(ops); |
747 | - this.toRemove = checkNotNull(list); | 710 | + |
748 | } | 711 | } |
749 | 712 | ||
750 | @Override | 713 | @Override |
751 | public void run() { | 714 | public void run() { |
752 | try { | 715 | try { |
753 | - log.trace("update backup {} +{} -{}", deviceId, toAdd, toRemove); | 716 | + log.trace("update backup {} {}", deviceId, ops |
717 | + ); | ||
754 | final SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(deviceId); | 718 | final SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(deviceId); |
755 | - // Following should be rewritten using async APIs | 719 | + |
756 | - for (FlowRuleBatchEntry bEntry : toAdd) { | 720 | + |
757 | - final FlowRule entry = bEntry.target(); | 721 | + ops.stream().forEach( |
722 | + op -> { | ||
723 | + final FlowRule entry = op.getTarget(); | ||
758 | final FlowId id = entry.id(); | 724 | final FlowId id = entry.id(); |
759 | ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id); | 725 | ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id); |
760 | List<StoredFlowEntry> list = new ArrayList<>(); | 726 | List<StoredFlowEntry> list = new ArrayList<>(); |
761 | if (original != null) { | 727 | if (original != null) { |
762 | list.addAll(original); | 728 | list.addAll(original); |
763 | } | 729 | } |
764 | - | 730 | + list.remove(op.getTarget()); |
765 | - list.remove(bEntry.target()); | 731 | + if (op.getOperator() == FlowRuleOperation.ADD) { |
766 | list.add((StoredFlowEntry) entry); | 732 | list.add((StoredFlowEntry) entry); |
733 | + } | ||
767 | 734 | ||
768 | ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list); | 735 | ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list); |
769 | boolean success; | 736 | boolean success; |
... | @@ -775,33 +742,100 @@ public class DistributedFlowRuleStore | ... | @@ -775,33 +742,100 @@ public class DistributedFlowRuleStore |
775 | if (!success) { | 742 | if (!success) { |
776 | log.error("Updating backup failed."); | 743 | log.error("Updating backup failed."); |
777 | } | 744 | } |
745 | + | ||
778 | } | 746 | } |
779 | - for (FlowRuleBatchEntry bEntry : toRemove) { | 747 | + ); |
780 | - final FlowRule entry = bEntry.target(); | 748 | + } catch (ExecutionException e) { |
781 | - final FlowId id = entry.id(); | 749 | + log.error("Failed to write to backups", e); |
782 | - ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id); | ||
783 | - List<StoredFlowEntry> list = new ArrayList<>(); | ||
784 | - if (original != null) { | ||
785 | - list.addAll(original); | ||
786 | } | 750 | } |
787 | 751 | ||
788 | - list.remove(bEntry.target()); | 752 | + } |
753 | + } | ||
789 | 754 | ||
790 | - ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list); | 755 | + private class InternalFlowTable { |
791 | - boolean success; | 756 | + |
792 | - if (original == null) { | 757 | + /* |
793 | - success = (backupFlowTable.putIfAbsent(id, newValue) == null); | 758 | + TODO: This needs to be cleaned up. Perhaps using the eventually consistent |
794 | - } else { | 759 | + map when it supports distributed to a sequence of instances. |
795 | - success = backupFlowTable.replace(id, original, newValue); | 760 | + */ |
761 | + | ||
762 | + | ||
763 | + private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, Set<StoredFlowEntry>>> | ||
764 | + flowEntries = new ConcurrentHashMap<>(); | ||
765 | + | ||
766 | + | ||
767 | + private NewConcurrentHashMap<FlowId, Set<StoredFlowEntry>> lazyEmptyFlowTable() { | ||
768 | + return NewConcurrentHashMap.<FlowId, Set<StoredFlowEntry>>ifNeeded(); | ||
796 | } | 769 | } |
797 | - if (!success) { | 770 | + |
798 | - log.error("Updating backup failed."); | 771 | + /** |
772 | + * Returns the flow table for specified device. | ||
773 | + * | ||
774 | + * @param deviceId identifier of the device | ||
775 | + * @return Map representing Flow Table of given device. | ||
776 | + */ | ||
777 | + private ConcurrentMap<FlowId, Set<StoredFlowEntry>> getFlowTable(DeviceId deviceId) { | ||
778 | + return createIfAbsentUnchecked(flowEntries, | ||
779 | + deviceId, lazyEmptyFlowTable()); | ||
799 | } | 780 | } |
781 | + | ||
782 | + private Set<StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId, FlowId flowId) { | ||
783 | + final ConcurrentMap<FlowId, Set<StoredFlowEntry>> flowTable = getFlowTable(deviceId); | ||
784 | + Set<StoredFlowEntry> r = flowTable.get(flowId); | ||
785 | + if (r == null) { | ||
786 | + final Set<StoredFlowEntry> concurrentlyAdded; | ||
787 | + r = new CopyOnWriteArraySet<>(); | ||
788 | + concurrentlyAdded = flowTable.putIfAbsent(flowId, r); | ||
789 | + if (concurrentlyAdded != null) { | ||
790 | + return concurrentlyAdded; | ||
800 | } | 791 | } |
801 | - } catch (ExecutionException e) { | 792 | + } |
802 | - log.error("Failed to write to backups", e); | 793 | + return r; |
803 | } | 794 | } |
804 | 795 | ||
796 | + private StoredFlowEntry getFlowEntryInternal(FlowRule rule) { | ||
797 | + for (StoredFlowEntry f : getFlowEntriesInternal(rule.deviceId(), rule.id())) { | ||
798 | + if (f.equals(rule)) { | ||
799 | + return f; | ||
800 | + } | ||
801 | + } | ||
802 | + return null; | ||
803 | + } | ||
804 | + | ||
805 | + private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) { | ||
806 | + return getFlowTable(deviceId).values().stream() | ||
807 | + .flatMap((list -> list.stream())).collect(Collectors.toSet()); | ||
808 | + | ||
805 | } | 809 | } |
810 | + | ||
811 | + | ||
812 | + public StoredFlowEntry getFlowEntry(FlowRule rule) { | ||
813 | + return getFlowEntryInternal(rule); | ||
806 | } | 814 | } |
815 | + | ||
816 | + public Set<FlowEntry> getFlowEntries(DeviceId deviceId) { | ||
817 | + return getFlowEntriesInternal(deviceId); | ||
818 | + } | ||
819 | + | ||
820 | + public Set<StoredFlowEntry> getFlowEntriesById(FlowEntry entry) { | ||
821 | + return getFlowEntriesInternal(entry.deviceId(), entry.id()); | ||
822 | + } | ||
823 | + | ||
824 | + public void add(FlowEntry rule) { | ||
825 | + ((CopyOnWriteArraySet) | ||
826 | + getFlowEntriesInternal(rule.deviceId(), rule.id())).add(rule); | ||
827 | + } | ||
828 | + | ||
829 | + public boolean remove(DeviceId deviceId, FlowEntry rule) { | ||
830 | + return ((CopyOnWriteArraySet) | ||
831 | + getFlowEntriesInternal(deviceId, rule.id())).remove(rule); | ||
832 | + //return flowEntries.remove(deviceId, rule); | ||
833 | + } | ||
834 | + | ||
835 | + public void clearDevice(DeviceId did) { | ||
836 | + flowEntries.remove(did); | ||
837 | + } | ||
838 | + } | ||
839 | + | ||
840 | + | ||
807 | } | 841 | } | ... | ... |
... | @@ -34,4 +34,7 @@ public final class FlowStoreMessageSubjects { | ... | @@ -34,4 +34,7 @@ public final class FlowStoreMessageSubjects { |
34 | 34 | ||
35 | public static final MessageSubject REMOVE_FLOW_ENTRY | 35 | public static final MessageSubject REMOVE_FLOW_ENTRY |
36 | = new MessageSubject("peer-forward-remove-flow-entry"); | 36 | = new MessageSubject("peer-forward-remove-flow-entry"); |
37 | + | ||
38 | + public static final MessageSubject REMOTE_APPLY_COMPLETED | ||
39 | + = new MessageSubject("peer-apply-completed"); | ||
37 | } | 40 | } | ... | ... |
... | @@ -59,15 +59,17 @@ import org.onosproject.net.PortNumber; | ... | @@ -59,15 +59,17 @@ import org.onosproject.net.PortNumber; |
59 | import org.onosproject.net.device.DefaultDeviceDescription; | 59 | import org.onosproject.net.device.DefaultDeviceDescription; |
60 | import org.onosproject.net.device.DefaultPortDescription; | 60 | import org.onosproject.net.device.DefaultPortDescription; |
61 | import org.onosproject.net.flow.CompletedBatchOperation; | 61 | import org.onosproject.net.flow.CompletedBatchOperation; |
62 | -import org.onosproject.net.flow.FlowRule; | ||
63 | import org.onosproject.net.flow.DefaultFlowEntry; | 62 | import org.onosproject.net.flow.DefaultFlowEntry; |
64 | import org.onosproject.net.flow.DefaultFlowRule; | 63 | import org.onosproject.net.flow.DefaultFlowRule; |
65 | import org.onosproject.net.flow.DefaultTrafficSelector; | 64 | import org.onosproject.net.flow.DefaultTrafficSelector; |
66 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 65 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
67 | import org.onosproject.net.flow.FlowEntry; | 66 | import org.onosproject.net.flow.FlowEntry; |
68 | import org.onosproject.net.flow.FlowId; | 67 | import org.onosproject.net.flow.FlowId; |
68 | +import org.onosproject.net.flow.FlowRule; | ||
69 | import org.onosproject.net.flow.FlowRuleBatchEntry; | 69 | import org.onosproject.net.flow.FlowRuleBatchEntry; |
70 | +import org.onosproject.net.flow.FlowRuleBatchEvent; | ||
70 | import org.onosproject.net.flow.FlowRuleBatchOperation; | 71 | import org.onosproject.net.flow.FlowRuleBatchOperation; |
72 | +import org.onosproject.net.flow.FlowRuleBatchRequest; | ||
71 | import org.onosproject.net.flow.StoredFlowEntry; | 73 | import org.onosproject.net.flow.StoredFlowEntry; |
72 | import org.onosproject.net.flow.criteria.Criteria; | 74 | import org.onosproject.net.flow.criteria.Criteria; |
73 | import org.onosproject.net.flow.criteria.Criterion; | 75 | import org.onosproject.net.flow.criteria.Criterion; |
... | @@ -162,6 +164,7 @@ public final class KryoNamespaces { | ... | @@ -162,6 +164,7 @@ public final class KryoNamespaces { |
162 | .register(Collections.emptySet().getClass()) | 164 | .register(Collections.emptySet().getClass()) |
163 | .register(Optional.class) | 165 | .register(Optional.class) |
164 | .register(Collections.emptyList().getClass()) | 166 | .register(Collections.emptyList().getClass()) |
167 | + .register(Collections.unmodifiableSet(Collections.emptySet()).getClass()) | ||
165 | .build(); | 168 | .build(); |
166 | 169 | ||
167 | /** | 170 | /** |
... | @@ -255,6 +258,9 @@ public final class KryoNamespaces { | ... | @@ -255,6 +258,9 @@ public final class KryoNamespaces { |
255 | L3ModificationInstruction.L3SubType.class, | 258 | L3ModificationInstruction.L3SubType.class, |
256 | L3ModificationInstruction.ModIPInstruction.class, | 259 | L3ModificationInstruction.ModIPInstruction.class, |
257 | RoleInfo.class, | 260 | RoleInfo.class, |
261 | + FlowRuleBatchEvent.class, | ||
262 | + FlowRuleBatchEvent.Type.class, | ||
263 | + FlowRuleBatchRequest.class, | ||
258 | FlowRuleBatchOperation.class, | 264 | FlowRuleBatchOperation.class, |
259 | CompletedBatchOperation.class, | 265 | CompletedBatchOperation.class, |
260 | FlowRuleBatchEntry.class, | 266 | FlowRuleBatchEntry.class, | ... | ... |
... | @@ -21,13 +21,13 @@ import com.google.common.cache.CacheBuilder; | ... | @@ -21,13 +21,13 @@ import com.google.common.cache.CacheBuilder; |
21 | import com.google.common.cache.RemovalListener; | 21 | import com.google.common.cache.RemovalListener; |
22 | import com.google.common.cache.RemovalNotification; | 22 | import com.google.common.cache.RemovalNotification; |
23 | import com.google.common.collect.FluentIterable; | 23 | import com.google.common.collect.FluentIterable; |
24 | -import com.google.common.util.concurrent.Futures; | 24 | +import com.google.common.collect.Sets; |
25 | import com.google.common.util.concurrent.SettableFuture; | 25 | import com.google.common.util.concurrent.SettableFuture; |
26 | - | ||
27 | import org.apache.felix.scr.annotations.Activate; | 26 | import org.apache.felix.scr.annotations.Activate; |
28 | import org.apache.felix.scr.annotations.Component; | 27 | import org.apache.felix.scr.annotations.Component; |
29 | import org.apache.felix.scr.annotations.Deactivate; | 28 | import org.apache.felix.scr.annotations.Deactivate; |
30 | import org.apache.felix.scr.annotations.Service; | 29 | import org.apache.felix.scr.annotations.Service; |
30 | +import org.onlab.util.NewConcurrentHashMap; | ||
31 | import org.onosproject.net.DeviceId; | 31 | import org.onosproject.net.DeviceId; |
32 | import org.onosproject.net.flow.CompletedBatchOperation; | 32 | import org.onosproject.net.flow.CompletedBatchOperation; |
33 | import org.onosproject.net.flow.DefaultFlowEntry; | 33 | import org.onosproject.net.flow.DefaultFlowEntry; |
... | @@ -46,7 +46,6 @@ import org.onosproject.net.flow.FlowRuleStore; | ... | @@ -46,7 +46,6 @@ import org.onosproject.net.flow.FlowRuleStore; |
46 | import org.onosproject.net.flow.FlowRuleStoreDelegate; | 46 | import org.onosproject.net.flow.FlowRuleStoreDelegate; |
47 | import org.onosproject.net.flow.StoredFlowEntry; | 47 | import org.onosproject.net.flow.StoredFlowEntry; |
48 | import org.onosproject.store.AbstractStore; | 48 | import org.onosproject.store.AbstractStore; |
49 | -import org.onlab.util.NewConcurrentHashMap; | ||
50 | import org.slf4j.Logger; | 49 | import org.slf4j.Logger; |
51 | 50 | ||
52 | import java.util.ArrayList; | 51 | import java.util.ArrayList; |
... | @@ -56,7 +55,6 @@ import java.util.concurrent.ConcurrentHashMap; | ... | @@ -56,7 +55,6 @@ import java.util.concurrent.ConcurrentHashMap; |
56 | import java.util.concurrent.ConcurrentMap; | 55 | import java.util.concurrent.ConcurrentMap; |
57 | import java.util.concurrent.CopyOnWriteArrayList; | 56 | import java.util.concurrent.CopyOnWriteArrayList; |
58 | import java.util.concurrent.ExecutionException; | 57 | import java.util.concurrent.ExecutionException; |
59 | -import java.util.concurrent.Future; | ||
60 | import java.util.concurrent.TimeUnit; | 58 | import java.util.concurrent.TimeUnit; |
61 | import java.util.concurrent.TimeoutException; | 59 | import java.util.concurrent.TimeoutException; |
62 | import java.util.concurrent.atomic.AtomicInteger; | 60 | import java.util.concurrent.atomic.AtomicInteger; |
... | @@ -261,13 +259,14 @@ public class SimpleFlowRuleStore | ... | @@ -261,13 +259,14 @@ public class SimpleFlowRuleStore |
261 | } | 259 | } |
262 | 260 | ||
263 | @Override | 261 | @Override |
264 | - public Future<CompletedBatchOperation> storeBatch( | 262 | + public void storeBatch( |
265 | - FlowRuleBatchOperation batchOperation) { | 263 | + FlowRuleBatchOperation operation) { |
266 | List<FlowRuleBatchEntry> toAdd = new ArrayList<>(); | 264 | List<FlowRuleBatchEntry> toAdd = new ArrayList<>(); |
267 | List<FlowRuleBatchEntry> toRemove = new ArrayList<>(); | 265 | List<FlowRuleBatchEntry> toRemove = new ArrayList<>(); |
268 | - for (FlowRuleBatchEntry entry : batchOperation.getOperations()) { | 266 | + |
269 | - final FlowRule flowRule = entry.target(); | 267 | + for (FlowRuleBatchEntry entry : operation.getOperations()) { |
270 | - if (entry.operator().equals(FlowRuleOperation.ADD)) { | 268 | + final FlowRule flowRule = entry.getTarget(); |
269 | + if (entry.getOperator().equals(FlowRuleOperation.ADD)) { | ||
271 | if (!getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) { | 270 | if (!getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) { |
272 | storeFlowRule(flowRule); | 271 | storeFlowRule(flowRule); |
273 | toAdd.add(entry); | 272 | toAdd.add(entry); |
... | @@ -283,21 +282,27 @@ public class SimpleFlowRuleStore | ... | @@ -283,21 +282,27 @@ public class SimpleFlowRuleStore |
283 | } | 282 | } |
284 | 283 | ||
285 | if (toAdd.isEmpty() && toRemove.isEmpty()) { | 284 | if (toAdd.isEmpty() && toRemove.isEmpty()) { |
286 | - return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowRule>emptySet())); | 285 | + notifyDelegate(FlowRuleBatchEvent.completed( |
286 | + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), | ||
287 | + new CompletedBatchOperation(true, Collections.emptySet(), | ||
288 | + operation.deviceId()))); | ||
289 | + return; | ||
287 | } | 290 | } |
288 | 291 | ||
289 | SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); | 292 | SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); |
290 | final int batchId = localBatchIdGen.incrementAndGet(); | 293 | final int batchId = localBatchIdGen.incrementAndGet(); |
291 | 294 | ||
292 | pendingFutures.put(batchId, r); | 295 | pendingFutures.put(batchId, r); |
293 | - notifyDelegate(FlowRuleBatchEvent.requested(new FlowRuleBatchRequest(batchId, toAdd, toRemove))); | ||
294 | 296 | ||
295 | - return r; | 297 | + toAdd.addAll(toRemove); |
298 | + notifyDelegate(FlowRuleBatchEvent.requested( | ||
299 | + new FlowRuleBatchRequest(batchId, Sets.newHashSet(toAdd)), operation.deviceId())); | ||
300 | + | ||
296 | } | 301 | } |
297 | 302 | ||
298 | @Override | 303 | @Override |
299 | public void batchOperationComplete(FlowRuleBatchEvent event) { | 304 | public void batchOperationComplete(FlowRuleBatchEvent event) { |
300 | - final Integer batchId = event.subject().batchId(); | 305 | + final Long batchId = event.subject().batchId(); |
301 | SettableFuture<CompletedBatchOperation> future | 306 | SettableFuture<CompletedBatchOperation> future |
302 | = pendingFutures.getIfPresent(batchId); | 307 | = pendingFutures.getIfPresent(batchId); |
303 | if (future != null) { | 308 | if (future != null) { | ... | ... |
providers/null/device/src/main/java/org/onosproject/provider/nil/device/impl/NullDeviceProvider.java
... | @@ -116,7 +116,7 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid | ... | @@ -116,7 +116,7 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid |
116 | @Activate | 116 | @Activate |
117 | public void activate(ComponentContext context) { | 117 | public void activate(ComponentContext context) { |
118 | providerService = providerRegistry.register(this); | 118 | providerService = providerRegistry.register(this); |
119 | - if (modified(context)) { | 119 | + if (!modified(context)) { |
120 | deviceBuilder.submit(new DeviceCreator(true)); | 120 | deviceBuilder.submit(new DeviceCreator(true)); |
121 | } | 121 | } |
122 | log.info("Started"); | 122 | log.info("Started"); |
... | @@ -173,6 +173,9 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid | ... | @@ -173,6 +173,9 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid |
173 | chgd |= true; | 173 | chgd |= true; |
174 | } | 174 | } |
175 | log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts); | 175 | log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts); |
176 | + if (chgd) { | ||
177 | + deviceBuilder.submit(new DeviceCreator(true)); | ||
178 | + } | ||
176 | return chgd; | 179 | return chgd; |
177 | } | 180 | } |
178 | 181 | ... | ... |
... | @@ -15,9 +15,7 @@ | ... | @@ -15,9 +15,7 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.provider.nil.flow.impl; | 16 | package org.onosproject.provider.nil.flow.impl; |
17 | 17 | ||
18 | -import com.google.common.collect.HashMultimap; | 18 | +import com.google.common.collect.Sets; |
19 | -import com.google.common.collect.Multimap; | ||
20 | -import com.google.common.util.concurrent.Futures; | ||
21 | import org.apache.felix.scr.annotations.Activate; | 19 | import org.apache.felix.scr.annotations.Activate; |
22 | import org.apache.felix.scr.annotations.Component; | 20 | import org.apache.felix.scr.annotations.Component; |
23 | import org.apache.felix.scr.annotations.Deactivate; | 21 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -29,12 +27,12 @@ import org.jboss.netty.util.TimerTask; | ... | @@ -29,12 +27,12 @@ import org.jboss.netty.util.TimerTask; |
29 | import org.onlab.util.Timer; | 27 | import org.onlab.util.Timer; |
30 | import org.onosproject.core.ApplicationId; | 28 | import org.onosproject.core.ApplicationId; |
31 | import org.onosproject.net.DeviceId; | 29 | import org.onosproject.net.DeviceId; |
32 | -import org.onosproject.net.flow.BatchOperation; | ||
33 | import org.onosproject.net.flow.CompletedBatchOperation; | 30 | import org.onosproject.net.flow.CompletedBatchOperation; |
34 | import org.onosproject.net.flow.DefaultFlowEntry; | 31 | import org.onosproject.net.flow.DefaultFlowEntry; |
35 | import org.onosproject.net.flow.FlowEntry; | 32 | import org.onosproject.net.flow.FlowEntry; |
36 | import org.onosproject.net.flow.FlowRule; | 33 | import org.onosproject.net.flow.FlowRule; |
37 | import org.onosproject.net.flow.FlowRuleBatchEntry; | 34 | import org.onosproject.net.flow.FlowRuleBatchEntry; |
35 | +import org.onosproject.net.flow.FlowRuleBatchOperation; | ||
38 | import org.onosproject.net.flow.FlowRuleProvider; | 36 | import org.onosproject.net.flow.FlowRuleProvider; |
39 | import org.onosproject.net.flow.FlowRuleProviderRegistry; | 37 | import org.onosproject.net.flow.FlowRuleProviderRegistry; |
40 | import org.onosproject.net.flow.FlowRuleProviderService; | 38 | import org.onosproject.net.flow.FlowRuleProviderService; |
... | @@ -43,7 +41,9 @@ import org.onosproject.net.provider.ProviderId; | ... | @@ -43,7 +41,9 @@ import org.onosproject.net.provider.ProviderId; |
43 | import org.slf4j.Logger; | 41 | import org.slf4j.Logger; |
44 | 42 | ||
45 | import java.util.Collections; | 43 | import java.util.Collections; |
46 | -import java.util.concurrent.Future; | 44 | +import java.util.Set; |
45 | +import java.util.concurrent.ConcurrentHashMap; | ||
46 | +import java.util.concurrent.ConcurrentMap; | ||
47 | import java.util.concurrent.TimeUnit; | 47 | import java.util.concurrent.TimeUnit; |
48 | 48 | ||
49 | import static org.slf4j.LoggerFactory.getLogger; | 49 | import static org.slf4j.LoggerFactory.getLogger; |
... | @@ -59,7 +59,7 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -59,7 +59,7 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr |
59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
60 | protected FlowRuleProviderRegistry providerRegistry; | 60 | protected FlowRuleProviderRegistry providerRegistry; |
61 | 61 | ||
62 | - private Multimap<DeviceId, FlowEntry> flowTable = HashMultimap.create(); | 62 | + private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>(); |
63 | 63 | ||
64 | private FlowRuleProviderService providerService; | 64 | private FlowRuleProviderService providerService; |
65 | 65 | ||
... | @@ -88,18 +88,10 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -88,18 +88,10 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr |
88 | } | 88 | } |
89 | 89 | ||
90 | @Override | 90 | @Override |
91 | - public void applyFlowRule(FlowRule... flowRules) { | 91 | + public void applyFlowRule(FlowRule... flowRules) {} |
92 | - for (int i = 0; i < flowRules.length; i++) { | ||
93 | - flowTable.put(flowRules[i].deviceId(), new DefaultFlowEntry(flowRules[i])); | ||
94 | - } | ||
95 | - } | ||
96 | 92 | ||
97 | @Override | 93 | @Override |
98 | - public void removeFlowRule(FlowRule... flowRules) { | 94 | + public void removeFlowRule(FlowRule... flowRules) {} |
99 | - for (int i = 0; i < flowRules.length; i++) { | ||
100 | - flowTable.remove(flowRules[i].deviceId(), flowRules[i]); | ||
101 | - } | ||
102 | - } | ||
103 | 95 | ||
104 | @Override | 96 | @Override |
105 | public void removeRulesById(ApplicationId id, FlowRule... flowRules) { | 97 | public void removeRulesById(ApplicationId id, FlowRule... flowRules) { |
... | @@ -107,26 +99,32 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -107,26 +99,32 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr |
107 | } | 99 | } |
108 | 100 | ||
109 | @Override | 101 | @Override |
110 | - public Future<CompletedBatchOperation> executeBatch( | 102 | + public void executeBatch( |
111 | - BatchOperation<FlowRuleBatchEntry> batch) { | 103 | + FlowRuleBatchOperation batch) { |
104 | + Set<FlowEntry> flowRules = flowTable.getOrDefault(batch.deviceId(), Sets.newConcurrentHashSet()); | ||
112 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { | 105 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { |
113 | switch (fbe.operator()) { | 106 | switch (fbe.operator()) { |
114 | case ADD: | 107 | case ADD: |
115 | - applyFlowRule(fbe.target()); | 108 | + flowRules.add(new DefaultFlowEntry(fbe.target())); |
116 | break; | 109 | break; |
117 | case REMOVE: | 110 | case REMOVE: |
118 | - removeFlowRule(fbe.target()); | 111 | + flowRules.remove(new DefaultFlowEntry(fbe.target())); |
119 | break; | 112 | break; |
120 | case MODIFY: | 113 | case MODIFY: |
121 | - removeFlowRule(fbe.target()); | 114 | + FlowEntry entry = new DefaultFlowEntry(fbe.target()); |
122 | - applyFlowRule(fbe.target()); | 115 | + flowRules.remove(entry); |
116 | + flowRules.add(entry); | ||
123 | break; | 117 | break; |
124 | default: | 118 | default: |
125 | log.error("Unknown flow operation: {}", fbe); | 119 | log.error("Unknown flow operation: {}", fbe); |
126 | } | 120 | } |
127 | } | 121 | } |
128 | - return Futures.immediateFuture( | 122 | + flowTable.put(batch.deviceId(), flowRules); |
129 | - new CompletedBatchOperation(true, Collections.emptySet())); | 123 | + providerService.batchOperationCompleted(batch.id(), |
124 | + new CompletedBatchOperation( | ||
125 | + true, | ||
126 | + Collections.emptySet(), | ||
127 | + batch.deviceId())); | ||
130 | } | 128 | } |
131 | 129 | ||
132 | private class StatisticTask implements TimerTask { | 130 | private class StatisticTask implements TimerTask { |
... | @@ -134,10 +132,11 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -134,10 +132,11 @@ public class NullFlowRuleProvider extends AbstractProvider implements FlowRulePr |
134 | @Override | 132 | @Override |
135 | public void run(Timeout to) throws Exception { | 133 | public void run(Timeout to) throws Exception { |
136 | for (DeviceId devId : flowTable.keySet()) { | 134 | for (DeviceId devId : flowTable.keySet()) { |
137 | - providerService.pushFlowMetrics(devId, flowTable.get(devId)); | 135 | + providerService.pushFlowMetrics(devId, |
136 | + flowTable.getOrDefault(devId, Collections.emptySet())); | ||
138 | } | 137 | } |
139 | - | ||
140 | timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS); | 138 | timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS); |
139 | + | ||
141 | } | 140 | } |
142 | } | 141 | } |
143 | } | 142 | } | ... | ... |
... | @@ -35,6 +35,7 @@ import org.onosproject.net.flow.FlowRule; | ... | @@ -35,6 +35,7 @@ import org.onosproject.net.flow.FlowRule; |
35 | import org.onosproject.net.flow.TrafficSelector; | 35 | import org.onosproject.net.flow.TrafficSelector; |
36 | import org.onosproject.net.flow.TrafficTreatment; | 36 | import org.onosproject.net.flow.TrafficTreatment; |
37 | import org.onosproject.openflow.controller.Dpid; | 37 | import org.onosproject.openflow.controller.Dpid; |
38 | +import org.projectfloodlight.openflow.protocol.OFFlowMod; | ||
38 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; | 39 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; |
39 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; | 40 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; |
40 | import org.projectfloodlight.openflow.protocol.OFInstructionType; | 41 | import org.projectfloodlight.openflow.protocol.OFInstructionType; |
... | @@ -74,13 +75,16 @@ public class FlowEntryBuilder { | ... | @@ -74,13 +75,16 @@ public class FlowEntryBuilder { |
74 | 75 | ||
75 | private final OFFlowStatsEntry stat; | 76 | private final OFFlowStatsEntry stat; |
76 | private final OFFlowRemoved removed; | 77 | private final OFFlowRemoved removed; |
78 | + private final OFFlowMod flowMod; | ||
77 | 79 | ||
78 | private final Match match; | 80 | private final Match match; |
79 | private final List<OFAction> actions; | 81 | private final List<OFAction> actions; |
80 | 82 | ||
81 | private final Dpid dpid; | 83 | private final Dpid dpid; |
82 | 84 | ||
83 | - private final boolean addedRule; | 85 | + public enum FlowType { STAT, REMOVED, MOD } |
86 | + | ||
87 | + private final FlowType type; | ||
84 | 88 | ||
85 | 89 | ||
86 | public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) { | 90 | public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) { |
... | @@ -89,7 +93,8 @@ public class FlowEntryBuilder { | ... | @@ -89,7 +93,8 @@ public class FlowEntryBuilder { |
89 | this.actions = getActions(entry); | 93 | this.actions = getActions(entry); |
90 | this.dpid = dpid; | 94 | this.dpid = dpid; |
91 | this.removed = null; | 95 | this.removed = null; |
92 | - this.addedRule = true; | 96 | + this.flowMod = null; |
97 | + this.type = FlowType.STAT; | ||
93 | } | 98 | } |
94 | 99 | ||
95 | public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) { | 100 | public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) { |
... | @@ -99,26 +104,48 @@ public class FlowEntryBuilder { | ... | @@ -99,26 +104,48 @@ public class FlowEntryBuilder { |
99 | this.dpid = dpid; | 104 | this.dpid = dpid; |
100 | this.actions = null; | 105 | this.actions = null; |
101 | this.stat = null; | 106 | this.stat = null; |
102 | - this.addedRule = false; | 107 | + this.flowMod = null; |
108 | + this.type = FlowType.REMOVED; | ||
109 | + | ||
110 | + } | ||
103 | 111 | ||
112 | + public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) { | ||
113 | + this.match = fm.getMatch(); | ||
114 | + this.dpid = dpid; | ||
115 | + this.actions = fm.getActions(); | ||
116 | + this.type = FlowType.MOD; | ||
117 | + this.flowMod = fm; | ||
118 | + this.stat = null; | ||
119 | + this.removed = null; | ||
104 | } | 120 | } |
105 | 121 | ||
106 | - public FlowEntry build() { | 122 | + public FlowEntry build(FlowEntryState... state) { |
107 | - if (addedRule) { | 123 | + FlowRule rule; |
108 | - FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), | 124 | + switch (this.type) { |
125 | + case STAT: | ||
126 | + rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), | ||
109 | buildSelector(), buildTreatment(), stat.getPriority(), | 127 | buildSelector(), buildTreatment(), stat.getPriority(), |
110 | stat.getCookie().getValue(), stat.getIdleTimeout(), false); | 128 | stat.getCookie().getValue(), stat.getIdleTimeout(), false); |
111 | return new DefaultFlowEntry(rule, FlowEntryState.ADDED, | 129 | return new DefaultFlowEntry(rule, FlowEntryState.ADDED, |
112 | stat.getDurationSec(), stat.getPacketCount().getValue(), | 130 | stat.getDurationSec(), stat.getPacketCount().getValue(), |
113 | stat.getByteCount().getValue()); | 131 | stat.getByteCount().getValue()); |
114 | - | 132 | + case REMOVED: |
115 | - } else { | 133 | + rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), |
116 | - FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), | ||
117 | buildSelector(), null, removed.getPriority(), | 134 | buildSelector(), null, removed.getPriority(), |
118 | removed.getCookie().getValue(), removed.getIdleTimeout(), false); | 135 | removed.getCookie().getValue(), removed.getIdleTimeout(), false); |
119 | return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(), | 136 | return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(), |
120 | removed.getPacketCount().getValue(), removed.getByteCount().getValue()); | 137 | removed.getPacketCount().getValue(), removed.getByteCount().getValue()); |
138 | + case MOD: | ||
139 | + FlowEntryState flowState = state.length > 0 ? state[0] : FlowEntryState.FAILED; | ||
140 | + rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), | ||
141 | + buildSelector(), buildTreatment(), flowMod.getPriority(), | ||
142 | + flowMod.getCookie().getValue(), flowMod.getIdleTimeout(), false); | ||
143 | + return new DefaultFlowEntry(rule, flowState, 0, 0, 0); | ||
144 | + default: | ||
145 | + log.error("Unknown flow type : {}", this.type); | ||
146 | + return null; | ||
121 | } | 147 | } |
148 | + | ||
122 | } | 149 | } |
123 | 150 | ||
124 | private List<OFAction> getActions(OFFlowStatsEntry entry) { | 151 | private List<OFAction> getActions(OFFlowStatsEntry entry) { | ... | ... |
... | @@ -15,25 +15,13 @@ | ... | @@ -15,25 +15,13 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.provider.of.flow.impl; | 16 | package org.onosproject.provider.of.flow.impl; |
17 | 17 | ||
18 | -import static com.google.common.base.Preconditions.checkState; | ||
19 | -import static org.slf4j.LoggerFactory.getLogger; | ||
20 | - | ||
21 | -import java.util.Collections; | ||
22 | -import java.util.HashMap; | ||
23 | -import java.util.List; | ||
24 | -import java.util.Map; | ||
25 | -import java.util.Optional; | ||
26 | -import java.util.Set; | ||
27 | -import java.util.concurrent.ConcurrentHashMap; | ||
28 | -import java.util.concurrent.CountDownLatch; | ||
29 | -import java.util.concurrent.ExecutionException; | ||
30 | -import java.util.concurrent.Future; | ||
31 | -import java.util.concurrent.TimeUnit; | ||
32 | -import java.util.concurrent.TimeoutException; | ||
33 | -import java.util.concurrent.atomic.AtomicBoolean; | ||
34 | -import java.util.concurrent.atomic.AtomicLong; | ||
35 | -import java.util.stream.Collectors; | ||
36 | 18 | ||
19 | +import com.google.common.cache.Cache; | ||
20 | +import com.google.common.cache.CacheBuilder; | ||
21 | +import com.google.common.cache.RemovalCause; | ||
22 | +import com.google.common.cache.RemovalNotification; | ||
23 | +import com.google.common.collect.Maps; | ||
24 | +import com.google.common.collect.Sets; | ||
37 | import org.apache.felix.scr.annotations.Activate; | 25 | import org.apache.felix.scr.annotations.Activate; |
38 | import org.apache.felix.scr.annotations.Component; | 26 | import org.apache.felix.scr.annotations.Component; |
39 | import org.apache.felix.scr.annotations.Deactivate; | 27 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -41,19 +29,16 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -41,19 +29,16 @@ import org.apache.felix.scr.annotations.Reference; |
41 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 29 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
42 | import org.onosproject.core.ApplicationId; | 30 | import org.onosproject.core.ApplicationId; |
43 | import org.onosproject.net.DeviceId; | 31 | import org.onosproject.net.DeviceId; |
44 | -import org.onosproject.net.flow.BatchOperation; | ||
45 | import org.onosproject.net.flow.CompletedBatchOperation; | 32 | import org.onosproject.net.flow.CompletedBatchOperation; |
46 | -import org.onosproject.net.flow.DefaultFlowEntry; | ||
47 | import org.onosproject.net.flow.FlowEntry; | 33 | import org.onosproject.net.flow.FlowEntry; |
48 | import org.onosproject.net.flow.FlowRule; | 34 | import org.onosproject.net.flow.FlowRule; |
49 | import org.onosproject.net.flow.FlowRuleBatchEntry; | 35 | import org.onosproject.net.flow.FlowRuleBatchEntry; |
50 | -import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation; | 36 | +import org.onosproject.net.flow.FlowRuleBatchOperation; |
51 | import org.onosproject.net.flow.FlowRuleProvider; | 37 | import org.onosproject.net.flow.FlowRuleProvider; |
52 | import org.onosproject.net.flow.FlowRuleProviderRegistry; | 38 | import org.onosproject.net.flow.FlowRuleProviderRegistry; |
53 | import org.onosproject.net.flow.FlowRuleProviderService; | 39 | import org.onosproject.net.flow.FlowRuleProviderService; |
54 | import org.onosproject.net.provider.AbstractProvider; | 40 | import org.onosproject.net.provider.AbstractProvider; |
55 | import org.onosproject.net.provider.ProviderId; | 41 | import org.onosproject.net.provider.ProviderId; |
56 | -import org.onosproject.net.topology.TopologyService; | ||
57 | import org.onosproject.openflow.controller.Dpid; | 42 | import org.onosproject.openflow.controller.Dpid; |
58 | import org.onosproject.openflow.controller.OpenFlowController; | 43 | import org.onosproject.openflow.controller.OpenFlowController; |
59 | import org.onosproject.openflow.controller.OpenFlowEventListener; | 44 | import org.onosproject.openflow.controller.OpenFlowEventListener; |
... | @@ -63,6 +48,7 @@ import org.onosproject.openflow.controller.RoleState; | ... | @@ -63,6 +48,7 @@ import org.onosproject.openflow.controller.RoleState; |
63 | import org.projectfloodlight.openflow.protocol.OFActionType; | 48 | import org.projectfloodlight.openflow.protocol.OFActionType; |
64 | import org.projectfloodlight.openflow.protocol.OFBarrierRequest; | 49 | import org.projectfloodlight.openflow.protocol.OFBarrierRequest; |
65 | import org.projectfloodlight.openflow.protocol.OFErrorMsg; | 50 | import org.projectfloodlight.openflow.protocol.OFErrorMsg; |
51 | +import org.projectfloodlight.openflow.protocol.OFErrorType; | ||
66 | import org.projectfloodlight.openflow.protocol.OFFlowMod; | 52 | import org.projectfloodlight.openflow.protocol.OFFlowMod; |
67 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; | 53 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; |
68 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; | 54 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; |
... | @@ -75,21 +61,22 @@ import org.projectfloodlight.openflow.protocol.OFStatsType; | ... | @@ -75,21 +61,22 @@ import org.projectfloodlight.openflow.protocol.OFStatsType; |
75 | import org.projectfloodlight.openflow.protocol.OFVersion; | 61 | import org.projectfloodlight.openflow.protocol.OFVersion; |
76 | import org.projectfloodlight.openflow.protocol.action.OFAction; | 62 | import org.projectfloodlight.openflow.protocol.action.OFAction; |
77 | import org.projectfloodlight.openflow.protocol.action.OFActionOutput; | 63 | import org.projectfloodlight.openflow.protocol.action.OFActionOutput; |
78 | -import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg; | ||
79 | -import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg; | ||
80 | -import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg; | ||
81 | -import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg; | ||
82 | import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; | 64 | import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg; |
83 | import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; | 65 | import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; |
84 | import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; | 66 | import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; |
85 | import org.projectfloodlight.openflow.types.OFPort; | 67 | import org.projectfloodlight.openflow.types.OFPort; |
86 | import org.slf4j.Logger; | 68 | import org.slf4j.Logger; |
87 | 69 | ||
88 | -import com.google.common.base.MoreObjects; | 70 | +import java.util.Collections; |
89 | -import com.google.common.collect.ArrayListMultimap; | 71 | +import java.util.List; |
90 | -import com.google.common.collect.Maps; | 72 | +import java.util.Map; |
91 | -import com.google.common.collect.Multimap; | 73 | +import java.util.Optional; |
92 | -import com.google.common.collect.Sets; | 74 | +import java.util.Set; |
75 | +import java.util.concurrent.TimeUnit; | ||
76 | +import java.util.stream.Collectors; | ||
77 | + | ||
78 | +import static org.slf4j.LoggerFactory.getLogger; | ||
79 | + | ||
93 | 80 | ||
94 | /** | 81 | /** |
95 | * Provider which uses an OpenFlow controller to detect network | 82 | * Provider which uses an OpenFlow controller to detect network |
... | @@ -98,8 +85,6 @@ import com.google.common.collect.Sets; | ... | @@ -98,8 +85,6 @@ import com.google.common.collect.Sets; |
98 | @Component(immediate = true) | 85 | @Component(immediate = true) |
99 | public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider { | 86 | public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider { |
100 | 87 | ||
101 | - enum BatchState { STARTED, FINISHED, CANCELLED } | ||
102 | - | ||
103 | private static final int LOWEST_PRIORITY = 0; | 88 | private static final int LOWEST_PRIORITY = 0; |
104 | 89 | ||
105 | private final Logger log = getLogger(getClass()); | 90 | private final Logger log = getLogger(getClass()); |
... | @@ -110,22 +95,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -110,22 +95,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
110 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 95 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
111 | protected OpenFlowController controller; | 96 | protected OpenFlowController controller; |
112 | 97 | ||
113 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
114 | - protected TopologyService topologyService; | ||
115 | 98 | ||
116 | private FlowRuleProviderService providerService; | 99 | private FlowRuleProviderService providerService; |
117 | 100 | ||
118 | private final InternalFlowProvider listener = new InternalFlowProvider(); | 101 | private final InternalFlowProvider listener = new InternalFlowProvider(); |
119 | 102 | ||
120 | - // FIXME: This should be an expiring map to ensure futures that don't have | 103 | + private Cache<Long, InternalCacheEntry> pendingBatches; |
121 | - // a future eventually get garbage collected. | ||
122 | - private final Map<Long, InstallationFuture> pendingFutures = new ConcurrentHashMap<>(); | ||
123 | - | ||
124 | - private final Map<Long, InstallationFuture> pendingFMs = new ConcurrentHashMap<>(); | ||
125 | 104 | ||
126 | private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap(); | 105 | private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap(); |
127 | 106 | ||
128 | - private final AtomicLong xidCounter = new AtomicLong(1); | ||
129 | 107 | ||
130 | /** | 108 | /** |
131 | * Creates an OpenFlow host provider. | 109 | * Creates an OpenFlow host provider. |
... | @@ -140,6 +118,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -140,6 +118,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
140 | controller.addListener(listener); | 118 | controller.addListener(listener); |
141 | controller.addEventListener(listener); | 119 | controller.addEventListener(listener); |
142 | 120 | ||
121 | + pendingBatches = CacheBuilder.newBuilder() | ||
122 | + .expireAfterWrite(10, TimeUnit.SECONDS) | ||
123 | + .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> { | ||
124 | + if (notification.getCause() == RemovalCause.EXPIRED) { | ||
125 | + providerService.batchOperationCompleted(notification.getKey(), | ||
126 | + notification.getValue().failedCompletion()); | ||
127 | + } | ||
128 | + }).build(); | ||
129 | + | ||
130 | + | ||
143 | for (OpenFlowSwitch sw : controller.getSwitches()) { | 131 | for (OpenFlowSwitch sw : controller.getSwitches()) { |
144 | FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL); | 132 | FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL); |
145 | fsc.start(); | 133 | fsc.start(); |
... | @@ -160,8 +148,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -160,8 +148,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
160 | 148 | ||
161 | @Override | 149 | @Override |
162 | public void applyFlowRule(FlowRule... flowRules) { | 150 | public void applyFlowRule(FlowRule... flowRules) { |
163 | - for (int i = 0; i < flowRules.length; i++) { | 151 | + for (FlowRule flowRule : flowRules) { |
164 | - applyRule(flowRules[i]); | 152 | + applyRule(flowRule); |
165 | } | 153 | } |
166 | } | 154 | } |
167 | 155 | ||
... | @@ -179,8 +167,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -179,8 +167,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
179 | 167 | ||
180 | @Override | 168 | @Override |
181 | public void removeFlowRule(FlowRule... flowRules) { | 169 | public void removeFlowRule(FlowRule... flowRules) { |
182 | - for (int i = 0; i < flowRules.length; i++) { | 170 | + for (FlowRule flowRule : flowRules) { |
183 | - removeRule(flowRules[i]); | 171 | + removeRule(flowRule); |
184 | } | 172 | } |
185 | 173 | ||
186 | } | 174 | } |
... | @@ -203,36 +191,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -203,36 +191,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
203 | } | 191 | } |
204 | 192 | ||
205 | @Override | 193 | @Override |
206 | - public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { | ||
207 | - final Set<Dpid> sws = Sets.newConcurrentHashSet(); | ||
208 | - final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>(); | ||
209 | 194 | ||
210 | - /* | 195 | + public void executeBatch(FlowRuleBatchOperation batch) { |
211 | - * Use identity hash map for reference equality as we could have equal | 196 | + |
212 | - * flow mods for different switches. | 197 | + pendingBatches.put(batch.id(), new InternalCacheEntry(batch)); |
213 | - */ | 198 | + |
214 | - Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap(); | 199 | + |
215 | - Map<OFFlowMod, OpenFlowSwitch.TableType> modTypes = Maps.newIdentityHashMap(); | 200 | + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(batch.deviceId().uri())); |
201 | + OFFlowMod mod; | ||
202 | + | ||
216 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { | 203 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { |
217 | - FlowRule flowRule = fbe.target(); | 204 | + |
218 | - final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri()); | ||
219 | - OpenFlowSwitch sw = controller.getSwitch(dpid); | ||
220 | - if (sw == null) { | ||
221 | - /* | ||
222 | - * if a switch we are supposed to install to is gone then | ||
223 | - * cancel (ie. rollback) the work that has been done so far | ||
224 | - * and return the associated future. | ||
225 | - */ | ||
226 | - InstallationFuture failed = new InstallationFuture(sws, fmXids); | ||
227 | - failed.cancel(true); | ||
228 | - return failed; | ||
229 | - } | ||
230 | - sws.add(dpid); | ||
231 | - final Long flowModXid = xidCounter.getAndIncrement(); | ||
232 | FlowModBuilder builder = | 205 | FlowModBuilder builder = |
233 | - FlowModBuilder.builder(flowRule, sw.factory(), | 206 | + FlowModBuilder.builder(fbe.target(), sw.factory(), |
234 | - Optional.of(flowModXid)); | 207 | + Optional.of(batch.id())); |
235 | - OFFlowMod mod = null; | ||
236 | switch (fbe.operator()) { | 208 | switch (fbe.operator()) { |
237 | case ADD: | 209 | case ADD: |
238 | mod = builder.buildFlowAdd(); | 210 | mod = builder.buildFlowAdd(); |
... | @@ -244,34 +216,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -244,34 +216,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
244 | mod = builder.buildFlowMod(); | 216 | mod = builder.buildFlowMod(); |
245 | break; | 217 | break; |
246 | default: | 218 | default: |
247 | - log.error("Unsupported batch operation {}", fbe.operator()); | 219 | + log.error("Unsupported batch operation {}; skipping flowmod {}", |
248 | - } | 220 | + fbe.operator(), fbe); |
249 | - if (mod != null) { | 221 | + continue; |
250 | - mods.put(mod, sw); | ||
251 | - modTypes.put(mod, getTableType(flowRule.type())); | ||
252 | - fmXids.put(flowModXid, fbe); | ||
253 | - } else { | ||
254 | - log.error("Conversion of flowrule {} failed.", flowRule); | ||
255 | } | 222 | } |
256 | - } | ||
257 | - InstallationFuture installation = new InstallationFuture(sws, fmXids); | ||
258 | - for (Long xid : fmXids.keySet()) { | ||
259 | - pendingFMs.put(xid, installation); | ||
260 | - } | ||
261 | - | ||
262 | - pendingFutures.put(installation.xid(), installation); | ||
263 | - for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) { | ||
264 | - OpenFlowSwitch sw = entry.getValue(); | ||
265 | - OFFlowMod mod = entry.getKey(); | ||
266 | - OpenFlowSwitch.TableType tableType = modTypes.get(mod); | ||
267 | - if (tableType == OpenFlowSwitch.TableType.NONE) { | ||
268 | sw.sendMsg(mod); | 223 | sw.sendMsg(mod); |
269 | - } else { | ||
270 | - sw.sendMsg(mod, tableType); | ||
271 | } | 224 | } |
272 | - } | 225 | + OFBarrierRequest.Builder builder = sw.factory() |
273 | - installation.verify(); | 226 | + .buildBarrierRequest() |
274 | - return installation; | 227 | + .setXid(batch.id()); |
228 | + sw.sendMsg(builder.build()); | ||
275 | } | 229 | } |
276 | 230 | ||
277 | private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) { | 231 | private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) { |
... | @@ -287,12 +241,11 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -287,12 +241,11 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
287 | } | 241 | } |
288 | } | 242 | } |
289 | 243 | ||
290 | - private class InternalFlowProvider | ||
291 | - implements OpenFlowSwitchListener, OpenFlowEventListener { | ||
292 | 244 | ||
293 | 245 | ||
294 | - private final Multimap<DeviceId, FlowEntry> completeEntries = | 246 | + |
295 | - ArrayListMultimap.create(); | 247 | + private class InternalFlowProvider |
248 | + implements OpenFlowSwitchListener, OpenFlowEventListener { | ||
296 | 249 | ||
297 | @Override | 250 | @Override |
298 | public void switchAdded(Dpid dpid) { | 251 | public void switchAdded(Dpid dpid) { |
... | @@ -320,7 +273,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -320,7 +273,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
320 | 273 | ||
321 | @Override | 274 | @Override |
322 | public void handleMessage(Dpid dpid, OFMessage msg) { | 275 | public void handleMessage(Dpid dpid, OFMessage msg) { |
323 | - InstallationFuture future = null; | ||
324 | switch (msg.getType()) { | 276 | switch (msg.getType()) { |
325 | case FLOW_REMOVED: | 277 | case FLOW_REMOVED: |
326 | OFFlowRemoved removed = (OFFlowRemoved) msg; | 278 | OFFlowRemoved removed = (OFFlowRemoved) msg; |
... | @@ -334,22 +286,42 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -334,22 +286,42 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
334 | } | 286 | } |
335 | break; | 287 | break; |
336 | case BARRIER_REPLY: | 288 | case BARRIER_REPLY: |
337 | - future = pendingFutures.get(msg.getXid()); | 289 | + try { |
338 | - if (future != null) { | 290 | + InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid()); |
339 | - future.satisfyRequirement(dpid); | 291 | + if (entry != null) { |
292 | + providerService.batchOperationCompleted(msg.getXid(), entry.completed()); | ||
340 | } else { | 293 | } else { |
341 | log.warn("Received unknown Barrier Reply: {}", msg.getXid()); | 294 | log.warn("Received unknown Barrier Reply: {}", msg.getXid()); |
342 | } | 295 | } |
296 | + } finally { | ||
297 | + pendingBatches.invalidate(msg.getXid()); | ||
298 | + } | ||
343 | break; | 299 | break; |
344 | case ERROR: | 300 | case ERROR: |
345 | log.warn("received Error message {} from {}", msg, dpid); | 301 | log.warn("received Error message {} from {}", msg, dpid); |
346 | - future = pendingFMs.get(msg.getXid()); | 302 | + |
347 | - if (future != null) { | 303 | + OFErrorMsg error = (OFErrorMsg) msg; |
348 | - future.fail((OFErrorMsg) msg, dpid); | 304 | + if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) { |
305 | + OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error; | ||
306 | + if (fmFailed.getData().getParsedMessage().isPresent()) { | ||
307 | + OFMessage m = fmFailed.getData().getParsedMessage().get(); | ||
308 | + OFFlowMod fm = (OFFlowMod) m; | ||
309 | + InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid()); | ||
310 | + if (entry != null) { | ||
311 | + entry.appendFailure(new FlowEntryBuilder(dpid, fm).build()); | ||
349 | } else { | 312 | } else { |
350 | - log.warn("Received unknown Error Reply: {} {}", msg.getXid(), msg); | 313 | + log.error("No matching batch for this error: {}", error); |
351 | } | 314 | } |
352 | - break; | 315 | + } else { |
316 | + //FIXME: Potentially add flowtracking to avoid this message. | ||
317 | + log.error("Flow installation failed but switch didn't" + | ||
318 | + " tell us which one."); | ||
319 | + } | ||
320 | + } else { | ||
321 | + log.warn("Received error {}", error); | ||
322 | + } | ||
323 | + | ||
324 | + | ||
353 | default: | 325 | default: |
354 | log.debug("Unhandled message type: {}", msg.getType()); | 326 | log.debug("Unhandled message type: {}", msg.getType()); |
355 | } | 327 | } |
... | @@ -402,198 +374,50 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -402,198 +374,50 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
402 | 374 | ||
403 | } | 375 | } |
404 | 376 | ||
405 | - private class InstallationFuture implements Future<CompletedBatchOperation> { | 377 | + /** |
406 | - | 378 | + * The internal cache entry holding the original request as well |
407 | - // barrier xid | 379 | + * as accumulating the any failures along the way. |
408 | - private final Long xid; | 380 | + * |
409 | - // waiting for barrier reply from... | 381 | + * If this entry is evicted from the cache then the entire operation |
410 | - private final Set<Dpid> sws; | 382 | + * is considered failed. Otherwise, only the failures reported by the device |
411 | - private final AtomicBoolean ok = new AtomicBoolean(true); | 383 | + * will be propagated up. |
412 | - // FlowMod xid -> | 384 | + */ |
413 | - private final Map<Long, FlowRuleBatchEntry> fms; | 385 | + private class InternalCacheEntry { |
414 | - | ||
415 | - | ||
416 | - private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet(); | ||
417 | - // Failed batch operation id | ||
418 | - private Long failedId; | ||
419 | - | ||
420 | - private final CountDownLatch countDownLatch; | ||
421 | - private BatchState state; | ||
422 | - | ||
423 | - public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) { | ||
424 | - this.xid = xidCounter.getAndIncrement(); | ||
425 | - this.state = BatchState.STARTED; | ||
426 | - this.sws = sws; | ||
427 | - this.fms = fmXids; | ||
428 | - countDownLatch = new CountDownLatch(sws.size()); | ||
429 | - } | ||
430 | - | ||
431 | - public Long xid() { | ||
432 | - return xid; | ||
433 | - } | ||
434 | - | ||
435 | - public void fail(OFErrorMsg msg, Dpid dpid) { | ||
436 | - | ||
437 | - ok.set(false); | ||
438 | - FlowEntry fe = null; | ||
439 | - FlowRuleBatchEntry fbe = fms.get(msg.getXid()); | ||
440 | - failedId = fbe.id(); | ||
441 | - FlowRule offending = fbe.target(); | ||
442 | - //TODO handle specific error msgs | ||
443 | - switch (msg.getErrType()) { | ||
444 | - case BAD_ACTION: | ||
445 | - OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg; | ||
446 | - fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(), | ||
447 | - bad.getCode().ordinal()); | ||
448 | - break; | ||
449 | - case BAD_INSTRUCTION: | ||
450 | - OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg; | ||
451 | - fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(), | ||
452 | - badins.getCode().ordinal()); | ||
453 | - break; | ||
454 | - case BAD_MATCH: | ||
455 | - OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg; | ||
456 | - fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(), | ||
457 | - badMatch.getCode().ordinal()); | ||
458 | - break; | ||
459 | - case BAD_REQUEST: | ||
460 | - OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg; | ||
461 | - fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(), | ||
462 | - badReq.getCode().ordinal()); | ||
463 | - break; | ||
464 | - case FLOW_MOD_FAILED: | ||
465 | - OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg; | ||
466 | - fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(), | ||
467 | - fmFail.getCode().ordinal()); | ||
468 | - break; | ||
469 | - case EXPERIMENTER: | ||
470 | - case GROUP_MOD_FAILED: | ||
471 | - case HELLO_FAILED: | ||
472 | - case METER_MOD_FAILED: | ||
473 | - case PORT_MOD_FAILED: | ||
474 | - case QUEUE_OP_FAILED: | ||
475 | - case ROLE_REQUEST_FAILED: | ||
476 | - case SWITCH_CONFIG_FAILED: | ||
477 | - case TABLE_FEATURES_FAILED: | ||
478 | - case TABLE_MOD_FAILED: | ||
479 | - fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0); | ||
480 | - break; | ||
481 | - default: | ||
482 | - log.error("Unknown error type {}", msg.getErrType()); | ||
483 | - | ||
484 | - } | ||
485 | - offendingFlowMods.add(fe); | ||
486 | - | ||
487 | - removeRequirement(dpid); | ||
488 | - } | ||
489 | - | ||
490 | - | ||
491 | - public void satisfyRequirement(Dpid dpid) { | ||
492 | - log.debug("Satisfaction from switch {}", dpid); | ||
493 | - removeRequirement(dpid); | ||
494 | - } | ||
495 | - | ||
496 | - | ||
497 | - public void verify() { | ||
498 | - checkState(!sws.isEmpty()); | ||
499 | - for (Dpid dpid : sws) { | ||
500 | - OpenFlowSwitch sw = controller.getSwitch(dpid); | ||
501 | - OFBarrierRequest.Builder builder = sw.factory() | ||
502 | - .buildBarrierRequest() | ||
503 | - .setXid(xid); | ||
504 | - sw.sendMsg(builder.build()); | ||
505 | - } | ||
506 | - } | ||
507 | - | ||
508 | - @Override | ||
509 | - public boolean cancel(boolean mayInterruptIfRunning) { | ||
510 | - if (isDone()) { | ||
511 | - return false; | ||
512 | - } | ||
513 | - ok.set(false); | ||
514 | - this.state = BatchState.CANCELLED; | ||
515 | - cleanUp(); | ||
516 | - for (FlowRuleBatchEntry fbe : fms.values()) { | ||
517 | - if (fbe.operator() == FlowRuleOperation.ADD || | ||
518 | - fbe.operator() == FlowRuleOperation.MODIFY) { | ||
519 | - removeFlowRule(fbe.target()); | ||
520 | - } else if (fbe.operator() == FlowRuleOperation.REMOVE) { | ||
521 | - applyRule(fbe.target()); | ||
522 | - } | ||
523 | - | ||
524 | - } | ||
525 | - return true; | ||
526 | - } | ||
527 | - | ||
528 | - @Override | ||
529 | - public boolean isCancelled() { | ||
530 | - return this.state == BatchState.CANCELLED; | ||
531 | - } | ||
532 | 386 | ||
533 | - @Override | 387 | + private final FlowRuleBatchOperation operation; |
534 | - public boolean isDone() { | 388 | + private final Set<FlowRule> failures = Sets.newConcurrentHashSet(); |
535 | - return this.state == BatchState.FINISHED || isCancelled(); | ||
536 | - } | ||
537 | 389 | ||
538 | - @Override | 390 | + public InternalCacheEntry(FlowRuleBatchOperation operation) { |
539 | - public CompletedBatchOperation get() throws InterruptedException, ExecutionException { | 391 | + this.operation = operation; |
540 | - countDownLatch.await(); | ||
541 | - this.state = BatchState.FINISHED; | ||
542 | - Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet(); | ||
543 | - CompletedBatchOperation result = | ||
544 | - new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds); | ||
545 | - //FIXME do cleanup here (moved by BOC) | ||
546 | - cleanUp(); | ||
547 | - return result; | ||
548 | } | 392 | } |
549 | 393 | ||
550 | - @Override | 394 | + /** |
551 | - public CompletedBatchOperation get(long timeout, TimeUnit unit) | 395 | + * Appends a failed rule to the set of failed items. |
552 | - throws InterruptedException, ExecutionException, | 396 | + * @param rule the failed rule |
553 | - TimeoutException { | 397 | + */ |
554 | - if (countDownLatch.await(timeout, unit)) { | 398 | + public void appendFailure(FlowRule rule) { |
555 | - this.state = BatchState.FINISHED; | 399 | + failures.add(rule); |
556 | - Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet(); | ||
557 | - CompletedBatchOperation result = | ||
558 | - new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds); | ||
559 | - // FIXME do cleanup here (moved by BOC) | ||
560 | - cleanUp(); | ||
561 | - return result; | ||
562 | - } | ||
563 | - throw new TimeoutException(this.toString()); | ||
564 | } | 400 | } |
565 | 401 | ||
566 | - private void cleanUp() { | 402 | + /** |
567 | - if (isDone() || isCancelled()) { | 403 | + * Fails the entire batch and returns the failed operation. |
568 | - pendingFutures.remove(xid); | 404 | + * @return the failed operation |
569 | - for (Long xid : fms.keySet()) { | 405 | + */ |
570 | - pendingFMs.remove(xid); | 406 | + public CompletedBatchOperation failedCompletion() { |
571 | - } | 407 | + Set<FlowRule> fails = operation.getOperations().stream() |
572 | - } | 408 | + .map(op -> op.target()).collect(Collectors.toSet()); |
409 | + return new CompletedBatchOperation(false, Collections.unmodifiableSet(fails), operation.deviceId()); | ||
573 | } | 410 | } |
574 | 411 | ||
575 | - private void removeRequirement(Dpid dpid) { | 412 | + /** |
576 | - countDownLatch.countDown(); | 413 | + * Returns the completed operation and whether the batch suceeded. |
577 | - sws.remove(dpid); | 414 | + * @return the completed operation |
578 | - //FIXME don't do cleanup here (moved by BOC) | 415 | + */ |
579 | - //cleanUp(); | 416 | + public CompletedBatchOperation completed() { |
417 | + return new CompletedBatchOperation(failures.isEmpty(), | ||
418 | + Collections.unmodifiableSet(failures), operation.deviceId()); | ||
580 | } | 419 | } |
581 | 420 | ||
582 | - @Override | ||
583 | - public String toString() { | ||
584 | - return MoreObjects.toStringHelper(getClass()) | ||
585 | - .add("xid", xid) | ||
586 | - .add("pending devices", sws) | ||
587 | - .add("devices in batch", | ||
588 | - fms.values().stream() | ||
589 | - .map((fbe) -> fbe.target().deviceId()) | ||
590 | - .distinct().collect(Collectors.toList())) | ||
591 | - .add("failedId", failedId) | ||
592 | - .add("latchCount", countDownLatch.getCount()) | ||
593 | - .add("state", state) | ||
594 | - .add("no error?", ok.get()) | ||
595 | - .toString(); | ||
596 | - } | ||
597 | } | 421 | } |
598 | 422 | ||
599 | } | 423 | } | ... | ... |
... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
2 | # Instance-specific configurations, in this case, the number of | 2 | # Instance-specific configurations, in this case, the number of |
3 | # devices per node. | 3 | # devices per node. |
4 | # | 4 | # |
5 | -devConfigs = 192.168.56.30:5,192.168.56.40:7 | 5 | +devConfigs = 192.168.97.132:5,192.168.97.131:5 |
6 | 6 | ||
7 | # | 7 | # |
8 | # Number of ports per device. This is global to all devices | 8 | # Number of ports per device. This is global to all devices | ... | ... |
-
Please register or login to post a comment