Committed by
Gerrit Code Review
Improved consistency for BMv2 flow rules handling
Change-Id: I3a4798af3f35f135e8162385a1bf7fc059028307
Showing
4 changed files
with
56 additions
and
37 deletions
| ... | @@ -24,6 +24,7 @@ import org.onosproject.bmv2.api.context.Bmv2DeviceContext; | ... | @@ -24,6 +24,7 @@ import org.onosproject.bmv2.api.context.Bmv2DeviceContext; |
| 24 | import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator; | 24 | import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator; |
| 25 | import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslatorException; | 25 | import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslatorException; |
| 26 | import org.onosproject.bmv2.api.context.Bmv2Interpreter; | 26 | import org.onosproject.bmv2.api.context.Bmv2Interpreter; |
| 27 | +import org.onosproject.bmv2.api.context.Bmv2TableModel; | ||
| 27 | import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; | 28 | import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; |
| 28 | import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper; | 29 | import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper; |
| 29 | import org.onosproject.bmv2.api.runtime.Bmv2MatchKey; | 30 | import org.onosproject.bmv2.api.runtime.Bmv2MatchKey; |
| ... | @@ -112,10 +113,10 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -112,10 +113,10 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 112 | 113 | ||
| 113 | List<FlowEntry> entryList = Lists.newArrayList(); | 114 | List<FlowEntry> entryList = Lists.newArrayList(); |
| 114 | 115 | ||
| 115 | - configuration.tables().forEach(table -> { | 116 | + for (Bmv2TableModel table : configuration.tables()) { |
| 116 | // For each table in the configuration AND exposed by the interpreter. | 117 | // For each table in the configuration AND exposed by the interpreter. |
| 117 | if (!interpreter.tableIdMap().inverse().containsKey(table.name())) { | 118 | if (!interpreter.tableIdMap().inverse().containsKey(table.name())) { |
| 118 | - return; | 119 | + continue; // next table |
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | List<Bmv2ParsedTableEntry> installedEntries; | 122 | List<Bmv2ParsedTableEntry> installedEntries; |
| ... | @@ -123,33 +124,34 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -123,33 +124,34 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 123 | installedEntries = deviceAgent.getTableEntries(table.name()); | 124 | installedEntries = deviceAgent.getTableEntries(table.name()); |
| 124 | } catch (Bmv2RuntimeException e) { | 125 | } catch (Bmv2RuntimeException e) { |
| 125 | log.warn("Failed to get table entries of table {} of {}: {}", table.name(), deviceId, e.explain()); | 126 | log.warn("Failed to get table entries of table {} of {}: {}", table.name(), deviceId, e.explain()); |
| 126 | - return; | 127 | + continue; // next table |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | - installedEntries.forEach(parsedEntry -> { | 130 | + for (Bmv2ParsedTableEntry parsedEntry : installedEntries) { |
| 130 | - Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, | 131 | + Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, table.name(), |
| 131 | - table.name(), | ||
| 132 | parsedEntry.matchKey()); | 132 | parsedEntry.matchKey()); |
| 133 | - ENTRY_LOCKS.compute(entryRef, (key, value) -> { | ||
| 134 | 133 | ||
| 135 | - Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookupEntryReference(entryRef); | 134 | + ENTRY_LOCKS.putIfAbsent(entryRef, true); |
| 135 | + synchronized (ENTRY_LOCKS.get(entryRef)) { | ||
| 136 | + | ||
| 137 | + Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookup(entryRef); | ||
| 136 | 138 | ||
| 137 | if (frWrapper == null) { | 139 | if (frWrapper == null) { |
| 138 | log.warn("missing reference from table entry service, BUG? " + | 140 | log.warn("missing reference from table entry service, BUG? " + |
| 139 | "deviceId={}, tableName={}, matchKey={}", | 141 | "deviceId={}, tableName={}, matchKey={}", |
| 140 | deviceId, table.name(), entryRef.matchKey()); | 142 | deviceId, table.name(), entryRef.matchKey()); |
| 141 | - return null; | 143 | + continue; // next entry |
| 142 | } | 144 | } |
| 143 | 145 | ||
| 144 | long remoteEntryId = parsedEntry.entryId(); | 146 | long remoteEntryId = parsedEntry.entryId(); |
| 145 | long localEntryId = frWrapper.entryId(); | 147 | long localEntryId = frWrapper.entryId(); |
| 146 | 148 | ||
| 147 | if (remoteEntryId != localEntryId) { | 149 | if (remoteEntryId != localEntryId) { |
| 148 | - log.warn("getFlowEntries(): inconsistent entry id! BUG? Updating it... remote={}, local={}", | 150 | + log.debug("getFlowEntries(): inconsistent entry id! BUG? Updating it... remote={}, local={}", |
| 149 | remoteEntryId, localEntryId); | 151 | remoteEntryId, localEntryId); |
| 150 | frWrapper = new Bmv2FlowRuleWrapper(frWrapper.rule(), remoteEntryId, | 152 | frWrapper = new Bmv2FlowRuleWrapper(frWrapper.rule(), remoteEntryId, |
| 151 | frWrapper.creationDate()); | 153 | frWrapper.creationDate()); |
| 152 | - tableEntryService.bindEntryReference(entryRef, frWrapper); | 154 | + tableEntryService.bind(entryRef, frWrapper); |
| 153 | } | 155 | } |
| 154 | 156 | ||
| 155 | long bytes = 0L; | 157 | long bytes = 0L; |
| ... | @@ -171,11 +173,9 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -171,11 +173,9 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 171 | FlowEntry entry = new DefaultFlowEntry(frWrapper.rule(), ADDED, frWrapper.lifeInSeconds(), | 173 | FlowEntry entry = new DefaultFlowEntry(frWrapper.rule(), ADDED, frWrapper.lifeInSeconds(), |
| 172 | packets, bytes); | 174 | packets, bytes); |
| 173 | entryList.add(entry); | 175 | entryList.add(entry); |
| 174 | - return true; | 176 | + } |
| 175 | - }); | 177 | + } |
| 176 | - | 178 | + } |
| 177 | - }); | ||
| 178 | - }); | ||
| 179 | 179 | ||
| 180 | return Collections.unmodifiableCollection(entryList); | 180 | return Collections.unmodifiableCollection(entryList); |
| 181 | } | 181 | } |
| ... | @@ -226,19 +226,16 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -226,19 +226,16 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 226 | bmv2Entry = translator.translate(rule, context); | 226 | bmv2Entry = translator.translate(rule, context); |
| 227 | } catch (Bmv2FlowRuleTranslatorException e) { | 227 | } catch (Bmv2FlowRuleTranslatorException e) { |
| 228 | log.warn("Unable to translate flow rule: {} - {}", e.getMessage(), rule); | 228 | log.warn("Unable to translate flow rule: {} - {}", e.getMessage(), rule); |
| 229 | - continue; | 229 | + continue; // next rule |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | String tableName = bmv2Entry.tableName(); | 232 | String tableName = bmv2Entry.tableName(); |
| 233 | Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, tableName, bmv2Entry.matchKey()); | 233 | Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, tableName, bmv2Entry.matchKey()); |
| 234 | 234 | ||
| 235 | - /* | 235 | + ENTRY_LOCKS.putIfAbsent(entryRef, true); |
| 236 | - From here on threads are synchronized over entryKey, i.e. serialize operations | 236 | + synchronized (ENTRY_LOCKS.get(entryRef)) { |
| 237 | - over the same matchKey of a specific table and device. | ||
| 238 | - */ | ||
| 239 | - ENTRY_LOCKS.compute(entryRef, (key, value) -> { | ||
| 240 | // Get from store | 237 | // Get from store |
| 241 | - Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookupEntryReference(entryRef); | 238 | + Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookup(entryRef); |
| 242 | try { | 239 | try { |
| 243 | if (operation == Operation.APPLY) { | 240 | if (operation == Operation.APPLY) { |
| 244 | // Apply entry | 241 | // Apply entry |
| ... | @@ -269,15 +266,14 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -269,15 +266,14 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 269 | } catch (Bmv2RuntimeException e) { | 266 | } catch (Bmv2RuntimeException e) { |
| 270 | log.warn("Unable to {} flow rule: {}", operation.name(), e.explain()); | 267 | log.warn("Unable to {} flow rule: {}", operation.name(), e.explain()); |
| 271 | } | 268 | } |
| 272 | - // Update binding in table entry service. | 269 | + |
| 270 | + // Update entryRef binding in table entry service. | ||
| 273 | if (frWrapper != null) { | 271 | if (frWrapper != null) { |
| 274 | - tableEntryService.bindEntryReference(entryRef, frWrapper); | 272 | + tableEntryService.bind(entryRef, frWrapper); |
| 275 | - return true; | ||
| 276 | } else { | 273 | } else { |
| 277 | - tableEntryService.unbindEntryReference(entryRef); | 274 | + tableEntryService.unbind(entryRef); |
| 278 | - return null; | ||
| 279 | } | 275 | } |
| 280 | - }); | 276 | + } |
| 281 | } | 277 | } |
| 282 | 278 | ||
| 283 | return processedFlowRules; | 279 | return processedFlowRules; |
| ... | @@ -287,7 +283,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -287,7 +283,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 287 | try { | 283 | try { |
| 288 | return agent.addTableEntry(entry); | 284 | return agent.addTableEntry(entry); |
| 289 | } catch (Bmv2RuntimeException e) { | 285 | } catch (Bmv2RuntimeException e) { |
| 290 | - if (e.getCode() != TABLE_DUPLICATE_ENTRY) { | 286 | + if (e.getCode().equals(TABLE_DUPLICATE_ENTRY)) { |
| 291 | forceRemove(agent, entry.tableName(), entry.matchKey()); | 287 | forceRemove(agent, entry.tableName(), entry.matchKey()); |
| 292 | return agent.addTableEntry(entry); | 288 | return agent.addTableEntry(entry); |
| 293 | } else { | 289 | } else { |
| ... | @@ -301,7 +297,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement | ... | @@ -301,7 +297,7 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement |
| 301 | try { | 297 | try { |
| 302 | agent.deleteTableEntry(tableName, entryId); | 298 | agent.deleteTableEntry(tableName, entryId); |
| 303 | } catch (Bmv2RuntimeException e) { | 299 | } catch (Bmv2RuntimeException e) { |
| 304 | - if (e.getCode() == TABLE_INVALID_HANDLE || e.getCode() == TABLE_EXPIRED_HANDLE) { | 300 | + if (e.getCode().equals(TABLE_INVALID_HANDLE) || e.getCode().equals(TABLE_EXPIRED_HANDLE)) { |
| 305 | // entry is not there with the declared ID, try with a forced remove. | 301 | // entry is not there with the declared ID, try with a forced remove. |
| 306 | forceRemove(agent, tableName, matchKey); | 302 | forceRemove(agent, tableName, matchKey); |
| 307 | } else { | 303 | } else { | ... | ... |
| ... | @@ -21,6 +21,7 @@ import com.google.common.annotations.Beta; | ... | @@ -21,6 +21,7 @@ import com.google.common.annotations.Beta; |
| 21 | import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator; | 21 | import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator; |
| 22 | import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper; | 22 | import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper; |
| 23 | import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference; | 23 | import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference; |
| 24 | +import org.onosproject.net.DeviceId; | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | * A service for managing BMv2 table entries. | 27 | * A service for managing BMv2 table entries. |
| ... | @@ -41,7 +42,7 @@ public interface Bmv2TableEntryService { | ... | @@ -41,7 +42,7 @@ public interface Bmv2TableEntryService { |
| 41 | * @param entryRef a table entry reference | 42 | * @param entryRef a table entry reference |
| 42 | * @param rule a BMv2 flow rule wrapper | 43 | * @param rule a BMv2 flow rule wrapper |
| 43 | */ | 44 | */ |
| 44 | - void bindEntryReference(Bmv2TableEntryReference entryRef, Bmv2FlowRuleWrapper rule); | 45 | + void bind(Bmv2TableEntryReference entryRef, Bmv2FlowRuleWrapper rule); |
| 45 | 46 | ||
| 46 | /** | 47 | /** |
| 47 | * Returns the ONOS flow rule associated with the given BMv2 table entry reference, or null if there's no such a | 48 | * Returns the ONOS flow rule associated with the given BMv2 table entry reference, or null if there's no such a |
| ... | @@ -50,12 +51,19 @@ public interface Bmv2TableEntryService { | ... | @@ -50,12 +51,19 @@ public interface Bmv2TableEntryService { |
| 50 | * @param entryRef a table entry reference | 51 | * @param entryRef a table entry reference |
| 51 | * @return a BMv2 flow rule wrapper | 52 | * @return a BMv2 flow rule wrapper |
| 52 | */ | 53 | */ |
| 53 | - Bmv2FlowRuleWrapper lookupEntryReference(Bmv2TableEntryReference entryRef); | 54 | + Bmv2FlowRuleWrapper lookup(Bmv2TableEntryReference entryRef); |
| 54 | 55 | ||
| 55 | /** | 56 | /** |
| 56 | * Removes any flow rule previously bound with a given BMv2 table entry reference. | 57 | * Removes any flow rule previously bound with a given BMv2 table entry reference. |
| 57 | * | 58 | * |
| 58 | * @param entryRef a table entry reference | 59 | * @param entryRef a table entry reference |
| 59 | */ | 60 | */ |
| 60 | - void unbindEntryReference(Bmv2TableEntryReference entryRef); | 61 | + void unbind(Bmv2TableEntryReference entryRef); |
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * Removes all bindings for a given device. | ||
| 65 | + * | ||
| 66 | + * @param deviceId a device ID | ||
| 67 | + */ | ||
| 68 | + void unbindAll(DeviceId deviceId); | ||
| 61 | } | 69 | } | ... | ... |
| ... | @@ -34,6 +34,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam; | ... | @@ -34,6 +34,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2ValidMatchParam; |
| 34 | import org.onosproject.bmv2.api.service.Bmv2Controller; | 34 | import org.onosproject.bmv2.api.service.Bmv2Controller; |
| 35 | import org.onosproject.bmv2.api.service.Bmv2DeviceContextService; | 35 | import org.onosproject.bmv2.api.service.Bmv2DeviceContextService; |
| 36 | import org.onosproject.bmv2.api.service.Bmv2TableEntryService; | 36 | import org.onosproject.bmv2.api.service.Bmv2TableEntryService; |
| 37 | +import org.onosproject.net.DeviceId; | ||
| 37 | import org.onosproject.store.serializers.KryoNamespaces; | 38 | import org.onosproject.store.serializers.KryoNamespaces; |
| 38 | import org.onosproject.store.service.EventuallyConsistentMap; | 39 | import org.onosproject.store.service.EventuallyConsistentMap; |
| 39 | import org.onosproject.store.service.StorageService; | 40 | import org.onosproject.store.service.StorageService; |
| ... | @@ -99,21 +100,29 @@ public class Bmv2TableEntryServiceImpl implements Bmv2TableEntryService { | ... | @@ -99,21 +100,29 @@ public class Bmv2TableEntryServiceImpl implements Bmv2TableEntryService { |
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | @Override | 102 | @Override |
| 102 | - public Bmv2FlowRuleWrapper lookupEntryReference(Bmv2TableEntryReference entryRef) { | 103 | + public Bmv2FlowRuleWrapper lookup(Bmv2TableEntryReference entryRef) { |
| 103 | checkNotNull(entryRef, "table entry reference cannot be null"); | 104 | checkNotNull(entryRef, "table entry reference cannot be null"); |
| 104 | return flowRules.get(entryRef); | 105 | return flowRules.get(entryRef); |
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | @Override | 108 | @Override |
| 108 | - public void bindEntryReference(Bmv2TableEntryReference entryRef, Bmv2FlowRuleWrapper rule) { | 109 | + public void bind(Bmv2TableEntryReference entryRef, Bmv2FlowRuleWrapper rule) { |
| 109 | checkNotNull(entryRef, "table entry reference cannot be null"); | 110 | checkNotNull(entryRef, "table entry reference cannot be null"); |
| 110 | checkNotNull(rule, "bmv2 flow rule cannot be null"); | 111 | checkNotNull(rule, "bmv2 flow rule cannot be null"); |
| 111 | flowRules.put(entryRef, rule); | 112 | flowRules.put(entryRef, rule); |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | @Override | 115 | @Override |
| 115 | - public void unbindEntryReference(Bmv2TableEntryReference entryRef) { | 116 | + public void unbind(Bmv2TableEntryReference entryRef) { |
| 116 | checkNotNull(entryRef, "table entry reference cannot be null"); | 117 | checkNotNull(entryRef, "table entry reference cannot be null"); |
| 117 | flowRules.remove(entryRef); | 118 | flowRules.remove(entryRef); |
| 118 | } | 119 | } |
| 120 | + | ||
| 121 | + @Override | ||
| 122 | + public void unbindAll(DeviceId deviceId) { | ||
| 123 | + flowRules.keySet() | ||
| 124 | + .stream() | ||
| 125 | + .filter(entryRef -> entryRef.deviceId().equals(deviceId)) | ||
| 126 | + .forEach(flowRules::remove); | ||
| 127 | + } | ||
| 119 | } | 128 | } | ... | ... |
| ... | @@ -29,6 +29,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; | ... | @@ -29,6 +29,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; |
| 29 | import org.onosproject.bmv2.api.service.Bmv2Controller; | 29 | import org.onosproject.bmv2.api.service.Bmv2Controller; |
| 30 | import org.onosproject.bmv2.api.service.Bmv2DeviceContextService; | 30 | import org.onosproject.bmv2.api.service.Bmv2DeviceContextService; |
| 31 | import org.onosproject.bmv2.api.service.Bmv2DeviceListener; | 31 | import org.onosproject.bmv2.api.service.Bmv2DeviceListener; |
| 32 | +import org.onosproject.bmv2.api.service.Bmv2TableEntryService; | ||
| 32 | import org.onosproject.common.net.AbstractDeviceProvider; | 33 | import org.onosproject.common.net.AbstractDeviceProvider; |
| 33 | import org.onosproject.core.ApplicationId; | 34 | import org.onosproject.core.ApplicationId; |
| 34 | import org.onosproject.core.CoreService; | 35 | import org.onosproject.core.CoreService; |
| ... | @@ -107,6 +108,9 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -107,6 +108,9 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 107 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 108 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 108 | protected Bmv2DeviceContextService contextService; | 109 | protected Bmv2DeviceContextService contextService; |
| 109 | 110 | ||
| 111 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 112 | + protected Bmv2TableEntryService tableEntryService; | ||
| 113 | + | ||
| 110 | private ApplicationId appId; | 114 | private ApplicationId appId; |
| 111 | 115 | ||
| 112 | /** | 116 | /** |
| ... | @@ -228,6 +232,8 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -228,6 +232,8 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 228 | private void resetDeviceState(DeviceId did) { | 232 | private void resetDeviceState(DeviceId did) { |
| 229 | try { | 233 | try { |
| 230 | controller.getAgent(did).resetState(); | 234 | controller.getAgent(did).resetState(); |
| 235 | + // Tables emptied. Reset all bindings. | ||
| 236 | + tableEntryService.unbindAll(did); | ||
| 231 | } catch (Bmv2RuntimeException e) { | 237 | } catch (Bmv2RuntimeException e) { |
| 232 | log.warn("Unable to reset {}: {}", did, e.toString()); | 238 | log.warn("Unable to reset {}: {}", did, e.toString()); |
| 233 | } | 239 | } | ... | ... |
-
Please register or login to post a comment