Initial DistributedDlowRuleStore
- known bug: responding to ClusterMessage not possible. Change-Id: Iaa4245c64d2a6219d7c48ed30ddca7d558dbc177
Showing
5 changed files
with
138 additions
and
27 deletions
| ... | @@ -24,7 +24,18 @@ public class FlowRuleEvent extends AbstractEvent<FlowRuleEvent.Type, FlowRule> { | ... | @@ -24,7 +24,18 @@ public class FlowRuleEvent extends AbstractEvent<FlowRuleEvent.Type, FlowRule> { |
| 24 | /** | 24 | /** |
| 25 | * Signifies that a rule has been updated. | 25 | * Signifies that a rule has been updated. |
| 26 | */ | 26 | */ |
| 27 | - RULE_UPDATED | 27 | + RULE_UPDATED, |
| 28 | + | ||
| 29 | + // internal event between Manager <-> Store | ||
| 30 | + | ||
| 31 | + /* | ||
| 32 | + * Signifies that a request to add flow rule has been added to the store. | ||
| 33 | + */ | ||
| 34 | + RULE_ADD_REQUESTED, | ||
| 35 | + /* | ||
| 36 | + * Signifies that a request to remove flow rule has been added to the store. | ||
| 37 | + */ | ||
| 38 | + RULE_REMOVE_REQUESTED, | ||
| 28 | } | 39 | } |
| 29 | 40 | ||
| 30 | /** | 41 | /** | ... | ... |
| ... | @@ -44,16 +44,18 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat | ... | @@ -44,16 +44,18 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat |
| 44 | * Stores a new flow rule without generating events. | 44 | * Stores a new flow rule without generating events. |
| 45 | * | 45 | * |
| 46 | * @param rule the flow rule to add | 46 | * @param rule the flow rule to add |
| 47 | + * @return true if the rule should be handled locally | ||
| 47 | */ | 48 | */ |
| 48 | - void storeFlowRule(FlowRule rule); | 49 | + boolean storeFlowRule(FlowRule rule); |
| 49 | 50 | ||
| 50 | /** | 51 | /** |
| 51 | * Marks a flow rule for deletion. Actual deletion will occur | 52 | * Marks a flow rule for deletion. Actual deletion will occur |
| 52 | * when the provider indicates that the flow has been removed. | 53 | * when the provider indicates that the flow has been removed. |
| 53 | * | 54 | * |
| 54 | * @param rule the flow rule to delete | 55 | * @param rule the flow rule to delete |
| 56 | + * @return true if the rule should be handled locally | ||
| 55 | */ | 57 | */ |
| 56 | - void deleteFlowRule(FlowRule rule); | 58 | + boolean deleteFlowRule(FlowRule rule); |
| 57 | 59 | ||
| 58 | /** | 60 | /** |
| 59 | * Stores a new flow rule, or updates an existing entry. | 61 | * Stores a new flow rule, or updates an existing entry. | ... | ... |
| ... | @@ -104,24 +104,52 @@ public class FlowRuleManager | ... | @@ -104,24 +104,52 @@ public class FlowRuleManager |
| 104 | public void applyFlowRules(FlowRule... flowRules) { | 104 | public void applyFlowRules(FlowRule... flowRules) { |
| 105 | for (int i = 0; i < flowRules.length; i++) { | 105 | for (int i = 0; i < flowRules.length; i++) { |
| 106 | FlowRule f = flowRules[i]; | 106 | FlowRule f = flowRules[i]; |
| 107 | - final Device device = deviceService.getDevice(f.deviceId()); | 107 | + boolean local = store.storeFlowRule(f); |
| 108 | - final FlowRuleProvider frp = getProvider(device.providerId()); | 108 | + if (local) { |
| 109 | - store.storeFlowRule(f); | 109 | + // TODO: aggregate all local rules and push down once? |
| 110 | - frp.applyFlowRule(f); | 110 | + applyFlowRulesToProviders(f); |
| 111 | + } | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + private void applyFlowRulesToProviders(FlowRule... flowRules) { | ||
| 116 | + DeviceId did = null; | ||
| 117 | + FlowRuleProvider frp = null; | ||
| 118 | + for (FlowRule f : flowRules) { | ||
| 119 | + if (!f.deviceId().equals(did)) { | ||
| 120 | + did = f.deviceId(); | ||
| 121 | + final Device device = deviceService.getDevice(did); | ||
| 122 | + frp = getProvider(device.providerId()); | ||
| 123 | + } | ||
| 124 | + if (frp != null) { | ||
| 125 | + frp.applyFlowRule(f); | ||
| 126 | + } | ||
| 111 | } | 127 | } |
| 112 | } | 128 | } |
| 113 | 129 | ||
| 114 | @Override | 130 | @Override |
| 115 | public void removeFlowRules(FlowRule... flowRules) { | 131 | public void removeFlowRules(FlowRule... flowRules) { |
| 116 | FlowRule f; | 132 | FlowRule f; |
| 117 | - FlowRuleProvider frp; | ||
| 118 | - Device device; | ||
| 119 | for (int i = 0; i < flowRules.length; i++) { | 133 | for (int i = 0; i < flowRules.length; i++) { |
| 120 | f = flowRules[i]; | 134 | f = flowRules[i]; |
| 121 | - device = deviceService.getDevice(f.deviceId()); | 135 | + boolean local = store.deleteFlowRule(f); |
| 122 | - store.deleteFlowRule(f); | 136 | + if (local) { |
| 123 | - if (device != null) { | 137 | + // TODO: aggregate all local rules and push down once? |
| 138 | + removeFlowRulesFromProviders(f); | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + private void removeFlowRulesFromProviders(FlowRule... flowRules) { | ||
| 144 | + DeviceId did = null; | ||
| 145 | + FlowRuleProvider frp = null; | ||
| 146 | + for (FlowRule f : flowRules) { | ||
| 147 | + if (!f.deviceId().equals(did)) { | ||
| 148 | + did = f.deviceId(); | ||
| 149 | + final Device device = deviceService.getDevice(did); | ||
| 124 | frp = getProvider(device.providerId()); | 150 | frp = getProvider(device.providerId()); |
| 151 | + } | ||
| 152 | + if (frp != null) { | ||
| 125 | frp.removeFlowRule(f); | 153 | frp.removeFlowRule(f); |
| 126 | } | 154 | } |
| 127 | } | 155 | } |
| ... | @@ -135,8 +163,11 @@ public class FlowRuleManager | ... | @@ -135,8 +163,11 @@ public class FlowRuleManager |
| 135 | 163 | ||
| 136 | for (FlowRule f : rules) { | 164 | for (FlowRule f : rules) { |
| 137 | store.deleteFlowRule(f); | 165 | store.deleteFlowRule(f); |
| 166 | + // FIXME: only accept request and push to provider on internal event | ||
| 138 | device = deviceService.getDevice(f.deviceId()); | 167 | device = deviceService.getDevice(f.deviceId()); |
| 139 | frp = getProvider(device.providerId()); | 168 | frp = getProvider(device.providerId()); |
| 169 | + // FIXME: flows removed from store and flows removed from might diverge | ||
| 170 | + // get rid of #removeRulesById? | ||
| 140 | frp.removeRulesById(id, f); | 171 | frp.removeRulesById(id, f); |
| 141 | } | 172 | } |
| 142 | } | 173 | } |
| ... | @@ -352,7 +383,23 @@ public class FlowRuleManager | ... | @@ -352,7 +383,23 @@ public class FlowRuleManager |
| 352 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { | 383 | private class InternalStoreDelegate implements FlowRuleStoreDelegate { |
| 353 | @Override | 384 | @Override |
| 354 | public void notify(FlowRuleEvent event) { | 385 | public void notify(FlowRuleEvent event) { |
| 355 | - eventDispatcher.post(event); | 386 | + switch (event.type()) { |
| 387 | + case RULE_ADD_REQUESTED: | ||
| 388 | + applyFlowRulesToProviders(event.subject()); | ||
| 389 | + break; | ||
| 390 | + case RULE_REMOVE_REQUESTED: | ||
| 391 | + removeFlowRulesFromProviders(event.subject()); | ||
| 392 | + break; | ||
| 393 | + | ||
| 394 | + case RULE_ADDED: | ||
| 395 | + case RULE_REMOVED: | ||
| 396 | + case RULE_UPDATED: | ||
| 397 | + // only dispatch events related to switch | ||
| 398 | + eventDispatcher.post(event); | ||
| 399 | + break; | ||
| 400 | + default: | ||
| 401 | + break; | ||
| 402 | + } | ||
| 356 | } | 403 | } |
| 357 | } | 404 | } |
| 358 | 405 | ... | ... |
| ... | @@ -2,6 +2,7 @@ package org.onlab.onos.store.flow.impl; | ... | @@ -2,6 +2,7 @@ package org.onlab.onos.store.flow.impl; |
| 2 | 2 | ||
| 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; |
| 4 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
| 5 | +import static org.onlab.onos.store.flow.impl.FlowStoreMessageSubjects.*; | ||
| 5 | 6 | ||
| 6 | import java.io.IOException; | 7 | import java.io.IOException; |
| 7 | import java.util.Collection; | 8 | import java.util.Collection; |
| ... | @@ -30,6 +31,7 @@ import org.onlab.onos.net.flow.StoredFlowEntry; | ... | @@ -30,6 +31,7 @@ import org.onlab.onos.net.flow.StoredFlowEntry; |
| 30 | import org.onlab.onos.store.AbstractStore; | 31 | import org.onlab.onos.store.AbstractStore; |
| 31 | import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; | 32 | import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; |
| 32 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; | 33 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; |
| 34 | +import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; | ||
| 33 | import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse; | 35 | import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse; |
| 34 | import org.onlab.onos.store.flow.ReplicaInfo; | 36 | import org.onlab.onos.store.flow.ReplicaInfo; |
| 35 | import org.onlab.onos.store.flow.ReplicaInfoService; | 37 | import org.onlab.onos.store.flow.ReplicaInfoService; |
| ... | @@ -80,10 +82,44 @@ public class DistributedFlowRuleStore | ... | @@ -80,10 +82,44 @@ public class DistributedFlowRuleStore |
| 80 | }; | 82 | }; |
| 81 | 83 | ||
| 82 | // TODO: make this configurable | 84 | // TODO: make this configurable |
| 83 | - private static final long FLOW_RULE_STORE_TIMEOUT_MILLIS = 1000; | 85 | + private static final long FLOW_RULE_STORE_TIMEOUT_MILLIS = 5000; |
| 84 | 86 | ||
| 85 | @Activate | 87 | @Activate |
| 86 | public void activate() { | 88 | public void activate() { |
| 89 | + clusterCommunicator.addSubscriber(STORE_FLOW_RULE, new ClusterMessageHandler() { | ||
| 90 | + | ||
| 91 | + @Override | ||
| 92 | + public void handle(ClusterMessage message) { | ||
| 93 | + FlowRule rule = SERIALIZER.decode(message.payload()); | ||
| 94 | + log.info("received add request for {}", rule); | ||
| 95 | + storeFlowEntryInternal(rule); | ||
| 96 | + // FIXME what to respond. | ||
| 97 | + try { | ||
| 98 | + // FIXME: #respond() not working. responded message is | ||
| 99 | + // handled by this sender node and never goes back. | ||
| 100 | + message.respond(SERIALIZER.encode("ACK")); | ||
| 101 | + } catch (IOException e) { | ||
| 102 | + log.error("Failed to respond back", e); | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + }); | ||
| 106 | + | ||
| 107 | + clusterCommunicator.addSubscriber(DELETE_FLOW_RULE, new ClusterMessageHandler() { | ||
| 108 | + | ||
| 109 | + @Override | ||
| 110 | + public void handle(ClusterMessage message) { | ||
| 111 | + FlowRule rule = SERIALIZER.decode(message.payload()); | ||
| 112 | + log.info("received delete request for {}", rule); | ||
| 113 | + deleteFlowRuleInternal(rule); | ||
| 114 | + // FIXME what to respond. | ||
| 115 | + try { | ||
| 116 | + message.respond(SERIALIZER.encode("ACK")); | ||
| 117 | + } catch (IOException e) { | ||
| 118 | + log.error("Failed to respond back", e); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + } | ||
| 122 | + }); | ||
| 87 | log.info("Started"); | 123 | log.info("Started"); |
| 88 | } | 124 | } |
| 89 | 125 | ||
| ... | @@ -131,13 +167,14 @@ public class DistributedFlowRuleStore | ... | @@ -131,13 +167,14 @@ public class DistributedFlowRuleStore |
| 131 | } | 167 | } |
| 132 | 168 | ||
| 133 | @Override | 169 | @Override |
| 134 | - public void storeFlowRule(FlowRule rule) { | 170 | + public boolean storeFlowRule(FlowRule rule) { |
| 135 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | 171 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); |
| 136 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 172 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
| 137 | - storeFlowEntryInternal(rule); | 173 | + return storeFlowEntryInternal(rule); |
| 138 | - return; | ||
| 139 | } | 174 | } |
| 140 | 175 | ||
| 176 | + log.warn("Not my flow forwarding to {}", replicaInfo.master().orNull()); | ||
| 177 | + | ||
| 141 | ClusterMessage message = new ClusterMessage( | 178 | ClusterMessage message = new ClusterMessage( |
| 142 | clusterService.getLocalNode().id(), | 179 | clusterService.getLocalNode().id(), |
| 143 | FlowStoreMessageSubjects.STORE_FLOW_RULE, | 180 | FlowStoreMessageSubjects.STORE_FLOW_RULE, |
| ... | @@ -150,26 +187,29 @@ public class DistributedFlowRuleStore | ... | @@ -150,26 +187,29 @@ public class DistributedFlowRuleStore |
| 150 | // FIXME: throw a FlowStoreException | 187 | // FIXME: throw a FlowStoreException |
| 151 | throw new RuntimeException(e); | 188 | throw new RuntimeException(e); |
| 152 | } | 189 | } |
| 190 | + return false; | ||
| 153 | } | 191 | } |
| 154 | 192 | ||
| 155 | - private synchronized void storeFlowEntryInternal(FlowRule flowRule) { | 193 | + private synchronized boolean storeFlowEntryInternal(FlowRule flowRule) { |
| 156 | StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); | 194 | StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule); |
| 157 | DeviceId deviceId = flowRule.deviceId(); | 195 | DeviceId deviceId = flowRule.deviceId(); |
| 158 | // write to local copy. | 196 | // write to local copy. |
| 159 | if (!flowEntries.containsEntry(deviceId, flowEntry)) { | 197 | if (!flowEntries.containsEntry(deviceId, flowEntry)) { |
| 160 | flowEntries.put(deviceId, flowEntry); | 198 | flowEntries.put(deviceId, flowEntry); |
| 161 | flowEntriesById.put(flowRule.appId(), flowEntry); | 199 | flowEntriesById.put(flowRule.appId(), flowEntry); |
| 200 | + notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, flowRule)); | ||
| 201 | + return true; | ||
| 162 | } | 202 | } |
| 163 | // write to backup. | 203 | // write to backup. |
| 164 | // TODO: write to a hazelcast map. | 204 | // TODO: write to a hazelcast map. |
| 205 | + return false; | ||
| 165 | } | 206 | } |
| 166 | 207 | ||
| 167 | @Override | 208 | @Override |
| 168 | - public synchronized void deleteFlowRule(FlowRule rule) { | 209 | + public synchronized boolean deleteFlowRule(FlowRule rule) { |
| 169 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | 210 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); |
| 170 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 211 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
| 171 | - deleteFlowRuleInternal(rule); | 212 | + return deleteFlowRuleInternal(rule); |
| 172 | - return; | ||
| 173 | } | 213 | } |
| 174 | 214 | ||
| 175 | ClusterMessage message = new ClusterMessage( | 215 | ClusterMessage message = new ClusterMessage( |
| ... | @@ -184,15 +224,21 @@ public class DistributedFlowRuleStore | ... | @@ -184,15 +224,21 @@ public class DistributedFlowRuleStore |
| 184 | // FIXME: throw a FlowStoreException | 224 | // FIXME: throw a FlowStoreException |
| 185 | throw new RuntimeException(e); | 225 | throw new RuntimeException(e); |
| 186 | } | 226 | } |
| 227 | + return false; | ||
| 187 | } | 228 | } |
| 188 | 229 | ||
| 189 | - private synchronized void deleteFlowRuleInternal(FlowRule flowRule) { | 230 | + private synchronized boolean deleteFlowRuleInternal(FlowRule flowRule) { |
| 190 | StoredFlowEntry entry = getFlowEntryInternal(flowRule); | 231 | StoredFlowEntry entry = getFlowEntryInternal(flowRule); |
| 191 | if (entry == null) { | 232 | if (entry == null) { |
| 192 | - return; | 233 | + return false; |
| 193 | } | 234 | } |
| 194 | entry.setState(FlowEntryState.PENDING_REMOVE); | 235 | entry.setState(FlowEntryState.PENDING_REMOVE); |
| 236 | + | ||
| 195 | // TODO: also update backup. | 237 | // TODO: also update backup. |
| 238 | + | ||
| 239 | + notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, flowRule)); | ||
| 240 | + | ||
| 241 | + return true; | ||
| 196 | } | 242 | } |
| 197 | 243 | ||
| 198 | @Override | 244 | @Override | ... | ... |
| ... | @@ -148,8 +148,9 @@ public class SimpleFlowRuleStore | ... | @@ -148,8 +148,9 @@ public class SimpleFlowRuleStore |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | @Override | 150 | @Override |
| 151 | - public void storeFlowRule(FlowRule rule) { | 151 | + public boolean storeFlowRule(FlowRule rule) { |
| 152 | final boolean added = storeFlowRuleInternal(rule); | 152 | final boolean added = storeFlowRuleInternal(rule); |
| 153 | + return added; | ||
| 153 | } | 154 | } |
| 154 | 155 | ||
| 155 | private boolean storeFlowRuleInternal(FlowRule rule) { | 156 | private boolean storeFlowRuleInternal(FlowRule rule) { |
| ... | @@ -166,13 +167,14 @@ public class SimpleFlowRuleStore | ... | @@ -166,13 +167,14 @@ public class SimpleFlowRuleStore |
| 166 | } | 167 | } |
| 167 | // new flow rule added | 168 | // new flow rule added |
| 168 | existing.add(f); | 169 | existing.add(f); |
| 169 | - // TODO: notify through delegate about remote event? | 170 | + // TODO: Should we notify only if it's "remote" event? |
| 171 | + //notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, rule)); | ||
| 170 | return true; | 172 | return true; |
| 171 | } | 173 | } |
| 172 | } | 174 | } |
| 173 | 175 | ||
| 174 | @Override | 176 | @Override |
| 175 | - public void deleteFlowRule(FlowRule rule) { | 177 | + public boolean deleteFlowRule(FlowRule rule) { |
| 176 | 178 | ||
| 177 | List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id()); | 179 | List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id()); |
| 178 | synchronized (entries) { | 180 | synchronized (entries) { |
| ... | @@ -180,12 +182,15 @@ public class SimpleFlowRuleStore | ... | @@ -180,12 +182,15 @@ public class SimpleFlowRuleStore |
| 180 | if (entry.equals(rule)) { | 182 | if (entry.equals(rule)) { |
| 181 | synchronized (entry) { | 183 | synchronized (entry) { |
| 182 | entry.setState(FlowEntryState.PENDING_REMOVE); | 184 | entry.setState(FlowEntryState.PENDING_REMOVE); |
| 183 | - return; | 185 | + // TODO: Should we notify only if it's "remote" event? |
| 186 | + //notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, rule)); | ||
| 187 | + return true; | ||
| 184 | } | 188 | } |
| 185 | } | 189 | } |
| 186 | } | 190 | } |
| 187 | } | 191 | } |
| 188 | //log.warn("Cannot find rule {}", rule); | 192 | //log.warn("Cannot find rule {}", rule); |
| 193 | + return false; | ||
| 189 | } | 194 | } |
| 190 | 195 | ||
| 191 | @Override | 196 | @Override | ... | ... |
-
Please register or login to post a comment