From 3bad057a3d83945a7e23113aacbdba6ba9cb5d97 Mon Sep 17 00:00:00 2001 From: Michal Rehak Date: Fri, 15 Aug 2014 20:25:19 +0200 Subject: [PATCH] bug 537 - Node Reconciliation https://wiki.opendaylight.org/view/OpenDaylight_OpenFlow_Plugin:Backlog:Node_Status_Reconciliation * FRM Reconciliation Notify Listener (DataChangeScope.BASE for FlowCapableNode in DataStore/OPERATIONAL) * FlowCookieProducer - MapHolder for an unique relation flow_cookie to flow_id via FRM * FlowStatTracker changes * search flow_id by flow_cookie for exist flow * add flow_id - flow_cookie for new Flow * FRM migration for new DataBroker API * merge with new DataStore/OPERATIONAL hierarchy (Flow vs. FlowStatistics) * fixed flow delete - generated cookie is bypassed with mask=0 In additional commit has fixed Bug 282 - Pre-configuration of flows causes exception + remove the transaction validators - not needed for now Change-Id: Iadc2b111780524b9a8fd86cfc248e5fa194e6638 Signed-off-by: Vaclav Demcak Signed-off-by: Michal Rehak --- .../frm/AbstractChangeListener.java | 141 +++++++++--- .../controller/frm/FRMActivator.java | 81 ++++--- .../controller/frm/FlowCookieProducer.java | 79 +++++++ .../frm/flow/FlowChangeListener.java | 142 +++++++------ .../controller/frm/flow/FlowProvider.java | 95 ++++++--- .../frm/flow/FlowTransactionValidator.java | 15 -- .../frm/group/GroupChangeListener.java | 116 +++++----- .../controller/frm/group/GroupProvider.java | 94 +++++--- .../frm/group/GroupTransactionValidator.java | 15 -- .../frm/meter/MeterChangeListener.java | 116 +++++----- .../controller/frm/meter/MeterProvider.java | 96 ++++++--- .../frm/meter/MeterTransactionValidator.java | 15 -- .../frm/reconil/FlowNodeReconcilListener.java | 185 ++++++++++++++++ .../frm/reconil/FlowNodeReconcilProvider.java | 115 ++++++++++ .../src/main/yang/flow-node-inventory.yang | 12 ++ .../md/statistics/manager/FlowComparator.java | 16 +- .../statistics/manager/FlowStatsTracker.java | 201 +++++++++++------- 17 files changed, 1076 insertions(+), 458 deletions(-) create mode 100644 opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java delete mode 100644 opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java delete mode 100644 opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java delete mode 100644 opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java create mode 100644 opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java create mode 100644 opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java index c8a7f01e13..130c096deb 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java @@ -9,67 +9,89 @@ package org.opendaylight.controller.frm; import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** + * AbstractChangeListner implemented basic {@link AsyncDataChangeEvent} processing for + * flow node subDataObject (flows, groups and meters). * * @author Vaclav Demcak * */ public abstract class AbstractChangeListener implements DataChangeListener { + private final static Logger LOG = LoggerFactory.getLogger(AbstractChangeListener.class); + private final AtomicLong txNum = new AtomicLong(); private String transactionId; @Override - public void onDataChanged(DataChangeEvent, DataObject> changeEvent) { + public void onDataChanged(final AsyncDataChangeEvent, DataObject> changeEvent) { this.transactionId = this.newTransactionIdentifier().toString(); - + /* All DataObjects for create */ final Set, DataObject>> createdEntries = - changeEvent.getCreatedConfigurationData().entrySet(); - final Set, DataObject>> updatedEntries = - new HashSet, DataObject>>(); - + changeEvent.getCreatedData().entrySet(); + /* All DataObjects for updates - init HashSet */ + final Set, DataObject>> updatedEntries = new HashSet<>(); + /* Filtered DataObject for update processing only */ Set, DataObject>> updateConfigEntrySet = - changeEvent.getUpdatedConfigurationData().entrySet(); + changeEvent.getUpdatedData().entrySet(); updatedEntries.addAll(updateConfigEntrySet); updatedEntries.removeAll(createdEntries); - + /* All DataObjects for remove */ final Set> removeEntriesInstanceIdentifiers = - changeEvent.getRemovedConfigurationData(); - + changeEvent.getRemovedPaths(); + /* Create DataObject processing (send to device) */ for (final Entry, DataObject> createdEntry : createdEntries) { - InstanceIdentifier c_key = createdEntry.getKey(); - DataObject c_value = createdEntry.getValue(); - this.add(c_key, c_value); + InstanceIdentifier entryKey = createdEntry.getKey(); + DataObject entryValue = createdEntry.getValue(); + if (preconditionForChange(entryKey, entryValue, null)) { + this.add(entryKey, entryValue); + } } for (final Entry, DataObject> updatedEntrie : updatedEntries) { Map, DataObject> origConfigData = - changeEvent.getOriginalConfigurationData(); - - InstanceIdentifier u_key = updatedEntrie.getKey(); - final DataObject originalFlow = origConfigData.get(u_key); - final DataObject updatedFlow = updatedEntrie.getValue(); - this.update(u_key, originalFlow, updatedFlow); + changeEvent.getOriginalData(); + + InstanceIdentifier entryKey = updatedEntrie.getKey(); + final DataObject original = origConfigData.get(entryKey); + final DataObject updated = updatedEntrie.getValue(); + if (preconditionForChange(entryKey, original, updated)) { + this.update(entryKey, original, updated); + } } for (final InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers) { Map, DataObject> origConfigData = - changeEvent.getOriginalConfigurationData(); + changeEvent.getOriginalData(); final DataObject removeValue = origConfigData.get(instanceId); - this.remove(instanceId, removeValue); + if (preconditionForChange(instanceId, removeValue, null)) { + this.remove(instanceId, removeValue); + } } } + /** + * Method returns generated transaction ID, which is unique for + * every transaction. ID is composite from prefix ("DOM") and unique number. + * + * @return String transactionID + */ public String getTransactionId() { return this.transactionId; } @@ -78,17 +100,74 @@ public abstract class AbstractChangeListener implements DataChangeListener { return "DOM-" + txNum.getAndIncrement(); } - protected abstract void validate() throws IllegalStateException; - - protected abstract void remove( + /** + * Method check all local preconditions for apply relevant changes. + * + * @param InstanceIdentifier identifier - the whole path to DataObject + * @param DataObject original - original DataObject (for update) + * or relevant DataObject (add/delete operations) + * @param DataObject update - changed DataObject (contain updates) + * or should be null for (add/delete operations) + * + * @return boolean - applicable + */ + protected abstract boolean preconditionForChange( final InstanceIdentifier identifier, + final DataObject original, final DataObject update); + + /** + * Method checks the node data path in DataStore/OPERATIONAL because + * without the Node Identifier in DataStore/OPERATIONAL, device + * is not connected and device pre-configuration is allowed only. + * + * @param InstanceIdentifier identifier - could be whole path to DataObject, + * but parent Node.class InstanceIdentifier is used for a check only + * + * @return boolean - is the Node available in DataStore/OPERATIONAL (is connected) + */ + protected boolean isNodeAvailable(final InstanceIdentifier identifier, + final ReadOnlyTransaction readTrans) { + final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); + try { + return readTrans.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId).get().isPresent(); + } + catch (InterruptedException | ExecutionException e) { + LOG.error("Unexpected exception by reading Node ".concat(nodeInstanceId.toString()), e); + return false; + } + finally { + readTrans.close(); + } + } + + /** + * Method removes DataObject which is identified by InstanceIdentifier + * from device. + * + * @param InstanceIdentifier identifier - the whole path to DataObject + * @param DataObject remove - DataObject for removing + */ + protected abstract void remove(final InstanceIdentifier identifier, final DataObject remove); - protected abstract void update( - final InstanceIdentifier identifier, + /** + * Method updates the original DataObject to the update DataObject + * in device. Both are identified by same InstanceIdentifier + * + * @param InstanceIdentifier identifier - the whole path to DataObject + * @param DataObject original - original DataObject (for update) + * @param DataObject update - changed DataObject (contain updates) + */ + protected abstract void update(final InstanceIdentifier identifier, final DataObject original, final DataObject update); - protected abstract void add( - final InstanceIdentifier identifier, + /** + * Method adds the DataObject which is identified by InstanceIdentifier + * to device. + * + * @param InstanceIdentifier identifier - the whole path to new DataObject + * @param DataObject add - new DataObject + */ + protected abstract void add(final InstanceIdentifier identifier, final DataObject add); } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java index 2f986ea5bc..c75c644c00 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java @@ -10,52 +10,79 @@ package org.opendaylight.controller.frm; import org.opendaylight.controller.frm.flow.FlowProvider; import org.opendaylight.controller.frm.group.GroupProvider; import org.opendaylight.controller.frm.meter.MeterProvider; +import org.opendaylight.controller.frm.reconil.FlowNodeReconcilProvider; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Forwarding Rules Manager Activator + * + * Activator manages all Providers ({@link FlowProvider}, {@link GroupProvider}, + * {@link MeterProvider} and the {@link FlowNodeReconcilProvider}). + * It registers all listeners (DataChangeEvent, ReconcilNotification) + * in the Session Initialization phase. + * + * @author Vaclav Demcak + * * + */ public class FRMActivator extends AbstractBindingAwareProvider { private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class); - private static FlowProvider flowProvider = new FlowProvider(); - private static GroupProvider groupProvider = new GroupProvider(); - private static MeterProvider meterProvider = new MeterProvider(); + private final FlowProvider flowProvider; + private final GroupProvider groupProvider; + private final MeterProvider meterProvider; + private final FlowNodeReconcilProvider flowNodeReconcilProvider; + + public FRMActivator() { + this.flowProvider = new FlowProvider(); + this.groupProvider = new GroupProvider(); + this.meterProvider = new MeterProvider(); + this.flowNodeReconcilProvider = new FlowNodeReconcilProvider(); + } @Override public void onSessionInitiated(final ProviderContext session) { - DataProviderService flowSalService = session.getSALService(DataProviderService.class); - FRMActivator.flowProvider.setDataService(flowSalService); - SalFlowService rpcFlowSalService = session.getRpcService(SalFlowService.class); - FRMActivator.flowProvider.setSalFlowService(rpcFlowSalService); - FRMActivator.flowProvider.start(); - DataProviderService groupSalService = session.getSALService(DataProviderService.class); - FRMActivator.groupProvider.setDataService(groupSalService); - SalGroupService rpcGroupSalService = session.getRpcService(SalGroupService.class); - FRMActivator.groupProvider.setSalGroupService(rpcGroupSalService); - FRMActivator.groupProvider.start(); - DataProviderService meterSalService = session.getSALService(DataProviderService.class); - FRMActivator.meterProvider.setDataService(meterSalService); - SalMeterService rpcMeterSalService = session.getRpcService(SalMeterService.class); - FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService); - FRMActivator.meterProvider.start(); + LOG.info("FRMActivator initialization."); + /* Flow */ + try { + final DataBroker flowSalService = session.getSALService(DataBroker.class); + this.flowProvider.init(flowSalService); + this.flowProvider.start(session); + /* Group */ + final DataBroker groupSalService = session.getSALService(DataBroker.class); + this.groupProvider.init(groupSalService); + this.groupProvider.start(session); + /* Meter */ + final DataBroker meterSalService = session.getSALService(DataBroker.class); + this.meterProvider.init(meterSalService); + this.meterProvider.start(session); + /* FlowNode Reconciliation */ + final DataBroker dbs = session.getSALService(DataBroker.class); + this.flowNodeReconcilProvider.init(dbs); + this.flowNodeReconcilProvider.start(session); + + LOG.info("FRMActivator started successfully"); + } catch (Exception e) { + String errMsg = "Unexpected error by starting FRMActivator"; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } } @Override protected void stopImpl(final BundleContext context) { try { - FRMActivator.flowProvider.close(); - FRMActivator.groupProvider.close(); - FRMActivator.meterProvider.close(); - } catch (Throwable e) { + this.flowProvider.close(); + this.groupProvider.close(); + this.meterProvider.close(); + this.flowNodeReconcilProvider.close(); + } catch (Exception e) { LOG.error("Unexpected error by stopping FRMActivator", e); - throw new RuntimeException(e); } } } \ No newline at end of file diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java new file mode 100644 index 0000000000..d7b54e8380 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.frm; + +import java.math.BigInteger; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.AtomicLongMap; + +/** + * forwardingrules-manager + * org.opendaylight.controller.frm + * + * Singleton FlowCookieProducer contains a FlowCookie generator which is generated unique + * flowCookie identifier for every flow in same Table. That could help with quick + * identification of flow statistic because DataStore/CONFIGURATION could contains + * a lot of flows with same flowCookie. So we are replacing original flowCookie + * with unique and we are building final FlowCookieMap in DataStore/OPERATIONAL + * + * @author Vaclav Demcak + * + * Created: Jun 13, 2014 + */ +public enum FlowCookieProducer { + + INSTANCE; + + /* Flow_Cookie_Key and Flow_Ids MapHolder */ + private static final AtomicLongMap> cookieKeys = AtomicLongMap.create(); + + /** + * Method returns the unique cookie for a node table. + * Flow Cookie Key signs List for a right flow statistic identification + * in the DataStore/operational. + * We need a List because system doesn't guarantee unique mapping + * from flow_cookie to flow_id. REST Operations doesn't used FRM yet, so + * cookie from user input could have a user input flow ID and an alien system ID + * which is generated by system. + * + * @param InstanceIdentifier tableIdentifier + * @return unique BigInteger flowCookie for a node table + */ + public BigInteger getNewCookie(final InstanceIdentifier
tableIdentifier) { + FlowCookieProducer.validationTableIdentifier(tableIdentifier); + if ( cookieKeys.containsKey(tableIdentifier)) { + /* new identifier always starts from ONE because + * ZERO is reserved for the NO_COOKIES flows */ + return BigInteger.valueOf(cookieKeys.addAndGet(tableIdentifier, 1L)); + } else { + return BigInteger.valueOf(cookieKeys.incrementAndGet(tableIdentifier)); + } + } + + /** + * Method cleans the node table flow_cookie_key for the disconnected Node. + * + * @param InstanceIdentifier
tableIdentifier + */ + public void clean(final InstanceIdentifier
tableIdentifier) { + FlowCookieProducer.validationTableIdentifier(tableIdentifier); + cookieKeys.remove(tableIdentifier); + } + + /* + * Help the TableIdentifer input validation method + */ + private static void validationTableIdentifier(final InstanceIdentifier
tableIdent) { + Preconditions.checkArgument(tableIdent != null, "Input validation exception: TableIdentifier can not be null !"); + } +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java index b60424513f..c10b0da2ba 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java @@ -7,22 +7,21 @@ */ package org.opendaylight.controller.frm.flow; +import java.math.BigInteger; + import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.frm.FlowCookieProducer; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; @@ -31,90 +30,97 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** + * Flow Change Listener + * add, update and remove {@link Flow} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}. * * @author Vaclav Demcak * */ public class FlowChangeListener extends AbstractChangeListener { - private final static Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class); - private final SalFlowService salFlowService; - - public SalFlowService getSalFlowService() { - return this.salFlowService; - } + private final FlowProvider provider; - public FlowChangeListener(final SalFlowService manager) { - this.salFlowService = manager; + public FlowChangeListener (final FlowProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "FlowProvider can not be null !"); } @Override - protected void validate() throws IllegalStateException { - FlowTransactionValidator.validate(this); - } + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { - @Override - protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { - if ((removeDataObj instanceof Flow)) { - - final Flow flow = ((Flow) removeDataObj); - final InstanceIdentifier
tableInstanceId = identifier.
firstIdentifierOf(Table.class); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow); - - builder.setFlowRef(new FlowRef(identifier)); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setFlowTable(new FlowTableRef(tableInstanceId)); - - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salFlowService.removeFlow((RemoveFlowInput) builder.build()); - LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj}); - } + final Flow flow = ((Flow) removeDataObj); + final InstanceIdentifier
tableIdent = identifier.firstIdentifierOf(Table.class); + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow); + + // use empty cookie mask in order to delete flow even with generated cookie + builder.setCookieMask(new FlowCookie(BigInteger.ZERO)); + + builder.setFlowRef(new FlowRef(identifier)); + builder.setNode(new NodeRef(nodeIdent)); + builder.setFlowTable(new FlowTableRef(tableIdent)); + + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalFlowService().removeFlow(builder.build()); + LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj}); } @Override - protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { - if (original instanceof Flow && update instanceof Flow) { + protected void update(final InstanceIdentifier identifier, + final DataObject original, final DataObject update) { + + final Flow originalFlow = ((Flow) original); + final Flow updatedFlow = ((Flow) update); + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder(); - final Flow originalFlow = ((Flow) original); - final Flow updatedFlow = ((Flow) update); - final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); - final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder(); + builder.setNode(new NodeRef(nodeIdent)); + builder.setFlowRef(new FlowRef(identifier)); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setFlowRef(new FlowRef(identifier)); + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); + builder.setUpdatedFlow((new UpdatedFlowBuilder(updatedFlow)).build()); + builder.setOriginalFlow((new OriginalFlowBuilder(originalFlow)).build()); - builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build()); - builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build()); + this.provider.getSalFlowService().updateFlow(builder.build()); + LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update}); + } - this.salFlowService.updateFlow((UpdateFlowInput) builder.build()); - LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update}); - } + @Override + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { + + final Flow flow = ((Flow) addDataObj); + final InstanceIdentifier
tableIdent = identifier.firstIdentifierOf(Table.class); + final NodeRef nodeRef = new NodeRef(identifier.firstIdentifierOf(Node.class)); + final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent)); + final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow); + + builder.setNode(nodeRef); + builder.setFlowRef(new FlowRef(identifier)); + builder.setFlowTable(new FlowTableRef(tableIdent)); + builder.setCookie( flowCookie ); + + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalFlowService().addFlow(builder.build()); + LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj}); } @Override - protected void add(InstanceIdentifier identifier, DataObject addDataObj) { - if ((addDataObj instanceof Flow)) { - - final Flow flow = ((Flow) addDataObj); - final InstanceIdentifier
tableInstanceId = identifier.
firstIdentifierOf(Table.class); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow); - - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setFlowRef(new FlowRef(identifier)); - builder.setFlowTable(new FlowTableRef(tableInstanceId)); - - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salFlowService.addFlow((AddFlowInput) builder.build()); - LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj}); - } + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { + + final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction(); + return update != null + ? (dataObj instanceof Flow && update instanceof Flow && isNodeAvailable(identifier, trans)) + : (dataObj instanceof Flow && isNodeAvailable(identifier, trans)); } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java index 33db529598..8c248fa264 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java @@ -7,9 +7,11 @@ */ package org.opendaylight.controller.frm.flow; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; @@ -17,54 +19,89 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalF import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + +/** + * Flow Provider registers the {@link FlowChangeListener} and it holds all needed + * services for {@link FlowChangeListener}. + * + * @author Vaclav Demcak + * + */ public class FlowProvider implements AutoCloseable { - private final static Logger LOG = LoggerFactory.getLogger(FlowProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowProvider.class); private SalFlowService salFlowService; - private DataProviderService dataService; + private DataBroker dataService; /* DataChangeListener */ - private FlowChangeListener flowDataChangeListener; - ListenerRegistration flowDataChangeListenerRegistration; + private DataChangeListener flowDataChangeListener; + private ListenerRegistration flowDataChangeListenerRegistration; + + /** + * Provider Initialization Phase. + * + * @param DataProviderService dataService + */ + public void init (final DataBroker dataService) { + LOG.info("FRM Flow Config Provider initialization."); + this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !"); + } + + /** + * Listener Registration Phase + * + * @param RpcConsumerRegistry rpcRegistry + */ + public void start(final RpcConsumerRegistry rpcRegistry) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + + this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class), + "RPC SalFlowService not found."); - public void start() { /* Build Path */ - InstanceIdentifierBuilder nodesBuilder = InstanceIdentifier. builder(Nodes.class); - InstanceIdentifierBuilder nodeChild = nodesBuilder. child(Node.class); - InstanceIdentifierBuilder augmentFlowCapNode = nodeChild. augmentation(FlowCapableNode.class); - InstanceIdentifierBuilder
tableChild = augmentFlowCapNode.
child(Table.class); - InstanceIdentifierBuilder flowChild = tableChild. child(Flow.class); - final InstanceIdentifier flowDataObjectPath = flowChild.toInstance(); + InstanceIdentifier flowIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class); /* DataChangeListener registration */ - this.flowDataChangeListener = new FlowChangeListener(this.salFlowService); - this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener); - LOG.info("Flow Config Provider started."); - } + this.flowDataChangeListener = new FlowChangeListener(FlowProvider.this); + this.flowDataChangeListenerRegistration = + this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + flowIdentifier, flowDataChangeListener, DataChangeScope.SUBTREE); - protected DataModificationTransaction startChange() { - return this.dataService.beginTransaction(); + LOG.info("FRM Flow Config Provider started."); } @Override - public void close() throws Exception { - if(flowDataChangeListenerRegistration != null){ - flowDataChangeListenerRegistration.close(); + public void close() { + LOG.info("FRM Flow Config Provider stopped."); + if (flowDataChangeListenerRegistration != null) { + try { + flowDataChangeListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Flow Config Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + flowDataChangeListenerRegistration = null; + } } } - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; + public DataChangeListener getFlowDataChangeListener() { + return flowDataChangeListener; + } + + public SalFlowService getSalFlowService() { + return salFlowService; } - public void setSalFlowService(final SalFlowService salFlowService) { - this.salFlowService = salFlowService; + public DataBroker getDataService() { + return dataService; } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java deleted file mode 100644 index 9cd42466a6..0000000000 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.frm.flow; - -public class FlowTransactionValidator { - - public static void validate(FlowChangeListener transaction) throws IllegalStateException { - // NOOP - } -} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java index 54f12bfdcf..9b03eaad8c 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java @@ -8,17 +8,12 @@ package org.opendaylight.controller.frm.group; import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; @@ -29,85 +24,88 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** + * Group Change Listener + * add, update and remove {@link Group} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}. * * @author Vaclav Demcak * */ public class GroupChangeListener extends AbstractChangeListener { - private final static Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class); - - private final SalGroupService salGroupService; + private static final Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class); - public SalGroupService getSalGroupService() { - return this.salGroupService; - } + private final GroupProvider provider; - public GroupChangeListener(final SalGroupService manager) { - this.salGroupService = manager; + public GroupChangeListener(final GroupProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "GroupProvider can not be null !"); } @Override - protected void validate() throws IllegalStateException { - GroupTransactionValidator.validate(this); + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { + + final Group group = ((Group) removeDataObj); + final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); + final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group); + + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(identifier)); + + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalGroupService().removeGroup(builder.build()); + LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj}); } @Override - protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { - if ((removeDataObj instanceof Group)) { + protected void update(final InstanceIdentifier identifier, + final DataObject original, final DataObject update) { - final Group group = ((Group) removeDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group); + final Group originalGroup = ((Group) original); + final Group updatedGroup = ((Group) update); + final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); + final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder(); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setGroupRef(new GroupRef(identifier)); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(identifier)); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salGroupService.removeGroup((RemoveGroupInput) builder.build()); - LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj}); - } - } + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); - @Override - protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { - if (original instanceof Group && update instanceof Group) { + builder.setUpdatedGroup((new UpdatedGroupBuilder(updatedGroup)).build()); + builder.setOriginalGroup((new OriginalGroupBuilder(originalGroup)).build()); - final Group originalGroup = ((Group) original); - final Group updatedGroup = ((Group) update); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder(); + this.provider.getSalGroupService().updateGroup(builder.build()); + LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update}); + } - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setGroupRef(new GroupRef(identifier)); + @Override + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); + final Group group = ((Group) addDataObj); + final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); + final AddGroupInputBuilder builder = new AddGroupInputBuilder(group); - builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build()); - builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build()); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setGroupRef(new GroupRef(identifier)); - this.salGroupService.updateGroup((UpdateGroupInput) builder.build()); - LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update}); - } + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalGroupService().addGroup(builder.build()); + LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj}); } @Override - protected void add(InstanceIdentifier identifier, DataObject addDataObj) { - if ((addDataObj instanceof Group)) { - final Group group = ((Group) addDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final AddGroupInputBuilder builder = new AddGroupInputBuilder(group); - - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setGroupRef(new GroupRef(identifier)); - - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salGroupService.addGroup((AddGroupInput) builder.build()); - LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj}); - } + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { + + final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction(); + return update != null + ? (dataObj instanceof Group && update instanceof Group && isNodeAvailable(identifier, trans)) + : (dataObj instanceof Group && isNodeAvailable(identifier, trans)); } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java index 9f2806e929..a999242bc0 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java @@ -7,61 +7,99 @@ */ package org.opendaylight.controller.frm.group; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + +/** + * Group Provider registers the {@link GroupChangeListener} and it holds all needed + * services for {@link GroupChangeListener}. + * + * @author Vaclav Demcak + * + */ public class GroupProvider implements AutoCloseable { - private final static Logger LOG = LoggerFactory.getLogger(GroupProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(GroupProvider.class); private SalGroupService salGroupService; - private DataProviderService dataService; + private DataBroker dataService; /* DataChangeListener */ - private GroupChangeListener groupDataChangeListener; - ListenerRegistration groupDataChangeListenerRegistration; + private DataChangeListener groupDataChangeListener; + private ListenerRegistration groupDataChangeListenerRegistration; + + /** + * Provider Initialization Phase. + * + * @param DataProviderService dataService + */ + public void init (final DataBroker dataService) { + LOG.info("FRM Group Config Provider initialization."); + this.dataService = Preconditions.checkNotNull(dataService, "DataService can not be null !"); + } + + /** + * Listener Registration Phase + * + * @param RpcConsumerRegistry rpcRegistry + */ + public void start(final RpcConsumerRegistry rpcRegistry) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + + this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class), + "RPC SalGroupService not found."); - public void start() { /* Build Path */ - InstanceIdentifierBuilder nodesBuilder = InstanceIdentifier. builder(Nodes.class); - InstanceIdentifierBuilder nodeChild = nodesBuilder. child(Node.class); - InstanceIdentifierBuilder augmentFlowCapNode = nodeChild. augmentation(FlowCapableNode.class); - InstanceIdentifierBuilder groupChild = augmentFlowCapNode. child(Group.class); - final InstanceIdentifier groupDataObjectPath = groupChild.toInstance(); + InstanceIdentifier groupIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).child(Group.class); /* DataChangeListener registration */ - this.groupDataChangeListener = new GroupChangeListener(this.salGroupService); - this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener); - LOG.info("Group Config Provider started."); - } + this.groupDataChangeListener = new GroupChangeListener(GroupProvider.this); + this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener( + LogicalDatastoreType.CONFIGURATION, groupIdentifier, groupDataChangeListener, DataChangeScope.SUBTREE); - protected DataModificationTransaction startChange() { - return this.dataService.beginTransaction(); + LOG.info("FRM Group Config Provider started."); } - public void close() throws Exception { - if(groupDataChangeListenerRegistration != null){ - groupDataChangeListenerRegistration.close(); + @Override + public void close() { + LOG.info("FRM Group Config Provider stopped."); + if (groupDataChangeListenerRegistration != null) { + try { + groupDataChangeListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Group Config Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + groupDataChangeListenerRegistration = null; + } } } - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; + public DataChangeListener getGroupDataChangeListener() { + return groupDataChangeListener; + } + + public SalGroupService getSalGroupService() { + return salGroupService; } - public void setSalGroupService(final SalGroupService salGroupService) { - this.salGroupService = salGroupService; + public DataBroker getDataService() { + return dataService; } } diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java deleted file mode 100644 index 88eea0db34..0000000000 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.frm.group; - -public class GroupTransactionValidator { - - public static void validate(GroupChangeListener transaction) throws IllegalStateException { - // NOOP - } -} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java index 48d5257978..a2def8490f 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java @@ -8,19 +8,14 @@ package org.opendaylight.controller.frm.meter; import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeter; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeter; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef; @@ -29,86 +24,89 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + /** + * Meter Change Listener + * add, update and remove {@link Meter} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}. * * @author Vaclav Demcak * */ public class MeterChangeListener extends AbstractChangeListener { - private final static Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class); - - private final SalMeterService salMeterService; - - public SalMeterService getSalMeterService() { - return this.salMeterService; - } + private static final Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class); - public MeterChangeListener(final SalMeterService manager) { - this.salMeterService = manager; - } + private final MeterProvider provider; - @Override - protected void validate() throws IllegalStateException { - MeterTransactionValidator.validate(this); + public MeterChangeListener (final MeterProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "MeterProvider can not be null !"); } @Override - protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { - if ((removeDataObj instanceof Meter)) { + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { - final Meter meter = ((Meter) removeDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter); + final Meter meter = ((Meter) removeDataObj); + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setMeterRef(new MeterRef(identifier)); + builder.setNode(new NodeRef(nodeIdent)); + builder.setMeterRef(new MeterRef(identifier)); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salMeterService.removeMeter((RemoveMeterInput) builder.build()); - LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj}); - } + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalMeterService().removeMeter(builder.build()); + LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj}); } @Override - protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { - if (original instanceof Meter && update instanceof Meter) { + protected void update(final InstanceIdentifier identifier, + final DataObject original, final DataObject update) { - final Meter originalMeter = ((Meter) original); - final Meter updatedMeter = ((Meter) update); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder(); + final Meter originalMeter = ((Meter) original); + final Meter updatedMeter = ((Meter) update); + final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); + final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder(); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setMeterRef(new MeterRef(identifier)); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(identifier)); - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); - builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build()); - builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build()); + builder.setUpdatedMeter((new UpdatedMeterBuilder(updatedMeter)).build()); + builder.setOriginalMeter((new OriginalMeterBuilder(originalMeter)).build()); + + this.provider.getSalMeterService().updateMeter(builder.build()); + LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update}); - this.salMeterService.updateMeter((UpdateMeterInput) builder.build()); - LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update}); - } } @Override - protected void add(InstanceIdentifier identifier, DataObject addDataObj) { - if ((addDataObj instanceof Meter)) { + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { + + final Meter meter = ((Meter) addDataObj); + final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); + final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter); - final Meter meter = ((Meter) addDataObj); - final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); - final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter); + builder.setNode(new NodeRef(nodeInstanceId)); + builder.setMeterRef(new MeterRef(identifier)); - builder.setNode(new NodeRef(nodeInstanceId)); - builder.setMeterRef(new MeterRef(identifier)); + Uri uri = new Uri(this.getTransactionId()); + builder.setTransactionUri(uri); + this.provider.getSalMeterService().addMeter(builder.build()); + LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj}); + } + + @Override + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { - Uri uri = new Uri(this.getTransactionId()); - builder.setTransactionUri(uri); - this.salMeterService.addMeter((AddMeterInput) builder.build()); - LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj}); - } + final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction(); + return update != null + ? (dataObj instanceof Meter && update instanceof Meter && isNodeAvailable(identifier, trans)) + : (dataObj instanceof Meter && isNodeAvailable(identifier, trans)); } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java index 8596c3fec6..44de7af495 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java @@ -7,61 +7,99 @@ */ package org.opendaylight.controller.frm.meter; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Preconditions; + +/** + * Meter Provider registers the {@link MeterChangeListener} and it holds all needed + * services for {@link MeterChangeListener}. + * + * @author Vaclav Demcak + * + */ public class MeterProvider implements AutoCloseable { - private final static Logger LOG = LoggerFactory.getLogger(MeterProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(MeterProvider.class); - private DataProviderService dataService; private SalMeterService salMeterService; + private DataBroker dataService; /* DataChangeListener */ - private MeterChangeListener meterDataChangeListener; - ListenerRegistration meterDataChangeListenerRegistration; + private DataChangeListener meterDataChangeListener; + private ListenerRegistration meterDataChangeListenerRegistration; + + /** + * Provider Initialization Phase. + * + * @param DataProviderService dataService + */ + public void init(final DataBroker dataService) { + LOG.info("FRM Meter Config Provider initialization."); + this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !"); + } + + /** + * Listener Registration Phase + * + * @param RpcConsumerRegistry rpcRegistry + */ + public void start(final RpcConsumerRegistry rpcRegistry) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !"); + this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class), + "RPC SalMeterService not found."); - public void start() { /* Build Path */ - InstanceIdentifierBuilder nodesBuilder = InstanceIdentifier. builder(Nodes.class); - InstanceIdentifierBuilder nodeChild = nodesBuilder. child(Node.class); - InstanceIdentifierBuilder augmentFlowCapNode = nodeChild. augmentation(FlowCapableNode.class); - InstanceIdentifierBuilder meterChild = augmentFlowCapNode. child(Meter.class); - final InstanceIdentifier meterDataObjectPath = meterChild.toInstance(); + InstanceIdentifier meterIdentifier = InstanceIdentifier.create(Nodes.class) + .child(Node.class).augmentation(FlowCapableNode.class).child(Meter.class); /* DataChangeListener registration */ - this.meterDataChangeListener = new MeterChangeListener(this.salMeterService); - this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener); - LOG.info("Meter Config Provider started."); - } + this.meterDataChangeListener = new MeterChangeListener(MeterProvider.this); + this.meterDataChangeListenerRegistration = + this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + meterIdentifier, meterDataChangeListener, DataChangeScope.SUBTREE); - protected DataModificationTransaction startChange() { - return this.dataService.beginTransaction(); + LOG.info("FRM Meter Config Provider started."); } - public void close() throws Exception { - if(meterDataChangeListenerRegistration != null){ - meterDataChangeListenerRegistration.close(); + @Override + public void close() { + LOG.info("FRM Meter Config Provider stopped."); + if (meterDataChangeListenerRegistration != null) { + try { + meterDataChangeListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Meter Config Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + meterDataChangeListenerRegistration = null; + } } } - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; + public DataChangeListener getMeterDataChangeListener() { + return meterDataChangeListener; + } + + public DataBroker getDataService() { + return dataService; } - public void setSalMeterService(final SalMeterService salMeterService) { - this.salMeterService = salMeterService; + public SalMeterService getSalMeterService() { + return salMeterService; } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java deleted file mode 100644 index c8fba23b93..0000000000 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.frm.meter; - -public class MeterTransactionValidator { - - public static void validate(MeterChangeListener transaction) throws IllegalStateException { - // NOOP - } -} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java new file mode 100644 index 0000000000..eb5ae4a9d3 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java @@ -0,0 +1,185 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.frm.reconil; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.frm.AbstractChangeListener; +import org.opendaylight.controller.frm.FlowCookieProducer; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * forwardingrules-manager + * org.opendaylight.controller.frm + * + * FlowNode Reconciliation Listener + * Reconciliation for a new FlowNode + * Remove CookieMapKey for removed FlowNode + * + * @author Vaclav Demcak + * + * Created: Jun 13, 2014 + */ +public class FlowNodeReconcilListener extends AbstractChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilListener.class); + + private final FlowNodeReconcilProvider provider; + + public FlowNodeReconcilListener(final FlowNodeReconcilProvider provider) { + this.provider = Preconditions.checkNotNull(provider, "Flow Node Reconcil Provider can not be null!"); + } + + @Override + public void onDataChanged(AsyncDataChangeEvent, DataObject> changeEvent) { + /* FlowCapableNode DataObjects for reconciliation */ + final Set, DataObject>> createdEntries = + changeEvent.getCreatedData().entrySet(); + /* FlowCapableNode DataObjects for clean FlowCookieHolder */ + final Set> removeEntriesInstanceIdentifiers = + changeEvent.getRemovedPaths(); + for (final Entry, DataObject> createdEntry : createdEntries) { + InstanceIdentifier entryKey = createdEntry.getKey(); + DataObject entryValue = createdEntry.getValue(); + if (preconditionForChange(entryKey, entryValue, null)) { + this.add(entryKey, entryValue); + } + } + for (final InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers) { + Map, DataObject> origConfigData = + changeEvent.getOriginalData(); + final DataObject removeValue = origConfigData.get(instanceId); + if (preconditionForChange(instanceId, removeValue, null)) { + this.remove(instanceId, removeValue); + } + } + } + + @Override + /* Cleaning FlowCookieManager holder for all node tables */ + protected void remove(final InstanceIdentifier identifier, + final DataObject removeDataObj) { + + final InstanceIdentifier flowNodeIdent = + identifier.firstIdentifierOf(FlowCapableNode.class); + final FlowCapableNode flowNode = ((FlowCapableNode) removeDataObj); + + for (Table flowTable : flowNode.getTable()) { + final InstanceIdentifier
tableIdent = + flowNodeIdent.child(Table.class, flowTable.getKey()); + FlowCookieProducer.INSTANCE.clean(tableIdent); + } + } + + @Override + /* Reconciliation by connect new FlowCapableNode */ + protected void add(final InstanceIdentifier identifier, + final DataObject addDataObj) { + + final InstanceIdentifier flowNodeIdent = + identifier.firstIdentifierOf(FlowCapableNode.class); + final Optional flowCapNode = this.readFlowCapableNode(flowNodeIdent); + + if (flowCapNode.isPresent()) { + final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); + final NodeRef nodeRef = new NodeRef(nodeIdent); + /* Groups - have to be first */ + for (Group group : flowCapNode.get().getGroup()) { + final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey())); + final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group); + groupBuilder.setGroupRef(groupRef); + groupBuilder.setNode(nodeRef); + this.provider.getSalGroupService().addGroup(groupBuilder.build()); + } + /* Meters */ + for (Meter meter : flowCapNode.get().getMeter()) { + final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey())); + final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter); + meterBuilder.setMeterRef(meterRef); + meterBuilder.setNode(nodeRef); + this.provider.getSalMeterService().addMeter(meterBuilder.build()); + } + /* Flows */ + for (Table flowTable : flowCapNode.get().getTable()) { + final InstanceIdentifier
tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey()); + for (Flow flow : flowTable.getFlow()) { + final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent)); + final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey())); + final FlowTableRef flowTableRef = new FlowTableRef(tableIdent); + final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow); + flowBuilder.setCookie(flowCookie); + flowBuilder.setNode(nodeRef); + flowBuilder.setFlowTable(flowTableRef); + flowBuilder.setFlowRef(flowRef); + this.provider.getSalFlowService().addFlow(flowBuilder.build()); + } + } + } + } + + @Override + protected void update(final InstanceIdentifier identifier, + final DataObject original, DataObject update) { + // NOOP - Listener is registered for DataChangeScope.BASE only + } + + @Override + protected boolean preconditionForChange(final InstanceIdentifier identifier, + final DataObject dataObj, final DataObject update) { + return (dataObj instanceof FlowCapableNode); + } + + private Optional readFlowCapableNode(final InstanceIdentifier flowNodeIdent) { + ReadOnlyTransaction readTrans = this.provider.getDataService().newReadOnlyTransaction(); + try { + ListenableFuture> confFlowNode = + readTrans.read(LogicalDatastoreType.CONFIGURATION, flowNodeIdent); + if (confFlowNode.get().isPresent()) { + return Optional. of(confFlowNode.get().get()); + } else { + return Optional.absent(); + } + } + catch (InterruptedException | ExecutionException e) { + LOG.error("Unexpected exception by reading flow ".concat(flowNodeIdent.toString()), e); + return Optional.absent(); + } + finally { + readTrans.close(); + } + } +} diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java new file mode 100644 index 0000000000..ad970d6043 --- /dev/null +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.frm.reconil; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +/** + * forwardingrules-manager + * org.opendaylight.controller.frm + * + * FlowNode Reconciliation Provider registers the FlowNodeReconilListener + * and it holds all needed services for FlowNodeReconcilListener. + * + * @author Vaclav Demcak + * + * Created: Jun 13, 2014 + */ +public class FlowNodeReconcilProvider implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilProvider.class); + + private SalFlowService salFlowService; + private SalMeterService salMeterService; + private SalGroupService salGroupService; + private DataBroker dataService; + + /* DataChangeListener */ + private DataChangeListener flowNodeReconcilListener; + private ListenerRegistration flowNodeReconcilListenerRegistration; + + public void init (final DataBroker dataService) { + LOG.info("FRM Flow Node Config Reconcil Provider initialization."); + + this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !"); + } + + public void start( final RpcConsumerRegistry rpcRegistry ) { + Preconditions.checkArgument(rpcRegistry != null, "RpcConcumerRegistry can not be null !"); + + this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class), + "RPC SalFlowService not found."); + this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class), + "RPC SalMeterService not found."); + this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class), + "RPC SalGroupService not found."); + + /* Build Path */ + InstanceIdentifier flowCapableNodeIdent = + InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class); + + /* ReconcilNotificationListener registration */ + this.flowNodeReconcilListener = new FlowNodeReconcilListener(FlowNodeReconcilProvider.this); + this.flowNodeReconcilListenerRegistration = this.dataService.registerDataChangeListener( + LogicalDatastoreType.OPERATIONAL, flowCapableNodeIdent, flowNodeReconcilListener, DataChangeScope.BASE); + LOG.info("FRM Flow Node Config Reconcil Provider started."); + } + + @Override + public void close() { + LOG.info("FRM Flow Node Config Reconcil Provider stopped."); + if (flowNodeReconcilListenerRegistration != null) { + try { + flowNodeReconcilListenerRegistration.close(); + } catch (Exception e) { + String errMsg = "Error by stop FRM Flow Node Config Reconcil Provider."; + LOG.error(errMsg, e); + throw new IllegalStateException(errMsg, e); + } finally { + flowNodeReconcilListenerRegistration = null; + } + } + } + + public DataChangeListener getFlowNodeReconcilListener() { + return flowNodeReconcilListener; + } + + public DataBroker getDataService() { + return dataService; + } + + public SalFlowService getSalFlowService() { + return salFlowService; + } + + public SalMeterService getSalMeterService() { + return salMeterService; + } + + public SalGroupService getSalGroupService() { + return salGroupService; + } +} diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang index 65362a1790..605cb9004a 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang @@ -229,4 +229,16 @@ module flow-node-inventory { uses flow-node-connector; } + augment "/inv:nodes/inv:node/table" { + ext:augment-identifier "flow-cookie-mapping"; + list flow-cookie-map { + key "cookie"; + leaf cookie { + type flow:flow-cookie; + } + leaf-list flow-ids { + type flow-id; + } + } + } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java index b1db280c24..cd9738c894 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java @@ -32,6 +32,9 @@ final class FlowComparator { } public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { + if (statsFlow == null || storedFlow == null) { + return false; + } if (statsFlow.getClass() != storedFlow.getClass()) { return false; } @@ -42,19 +45,18 @@ final class FlowComparator { } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { return false; } - if (statsFlow.getMatch()== null) { - if (storedFlow.getMatch() != null) { + if (storedFlow.getPriority() == null) { + if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { return false; } - } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { - else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { + } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { return false; } - if (storedFlow.getPriority() == null) { - if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { + if (statsFlow.getMatch()== null) { + if (storedFlow.getMatch() != null) { return false; } - } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { + } else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { return false; } if (statsFlow.getTableId() == null) { diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java index 1a14de6f5d..e92d0bd625 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java @@ -7,14 +7,20 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.math.BigInteger; import java.util.Collection; +import java.util.Collections; import java.util.Map.Entry; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCookieMapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; @@ -29,6 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.O import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -36,12 +43,16 @@ import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; + final class FlowStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowStatsTracker.class); + private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*"; private final OpendaylightFlowStatisticsService flowStatsService; private FlowTableStatsTracker flowTableStats; private int unaccountedFlowsCounter = 1; + FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) { super(context); this.flowStatsService = flowStatsService; @@ -66,15 +77,15 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker tableRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - //TODO: Not a good way to do it, need to figure out better way. - //TODO: major issue in any alternate approach is that flow key is incrementally assigned - //to the flows stored in data store. - // Augment same statistics to all the matching masked flow - Table table= (Table)trans.readConfigurationData(tableRef); - if(table != null){ - for(Flow existingFlow : table.getFlow()){ - logger.debug("Existing flow in data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingFlow)){ - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flow.setKey(existingFlow.getKey()); - flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching flow in the datastore, augmenting statistics"); - // Update entry with timestamp of latest response - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flow.build()); - return flowStatsEntry; - } - } - } - - table = (Table)trans.readOperationalData(tableRef); - if(table != null){ - for(Flow existingFlow : table.getFlow()){ - FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); - if(augmentedflowStatisticsData != null){ - FlowBuilder existingOperationalFlow = new FlowBuilder(); - existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); - logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){ - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flow.setKey(existingFlow.getKey()); - flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); - // Update entry with timestamp of latest response - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flow.build()); - return flowStatsEntry; - } - } + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)).toInstance(); + + final FlowCookie flowCookie = flowRule.getCookie() != null + ? flowRule.getCookie() : new FlowCookie(BigInteger.ZERO); + final InstanceIdentifier flowCookieRef = tableRef + .augmentation(FlowCookieMapping.class) + .child(FlowCookieMap.class, new FlowCookieMapKey(flowCookie)); + + FlowCookieMap cookieMap = (FlowCookieMap) trans.readOperationalData(flowCookieRef); + + /* find flowKey in FlowCookieMap from DataStore/OPERATIONAL */ + Optional flowKey = this.getExistFlowKey(flowRule, tableRef, trans, cookieMap); + if ( ! flowKey.isPresent()) { + /* DataStore/CONFIG For every first statistic needs to be created */ + flowKey = this.getFlowKeyFromExistFlow(flowRule, tableRef, trans); + if ( ! flowKey.isPresent()) { + /* Alien flow */ + flowKey = this.makeAlienFlowKey(flowRule); } + cookieMap = applyNewFlowKey(cookieMap, flowKey, flowCookie); + trans.putOperationalData(flowCookieRef, cookieMap); } - String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); - InstanceIdentifier flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,newFlowKey).toInstance(); - flow.setKey(newFlowKey); - flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow", - flow.build()); + InstanceIdentifier flowRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class, flowKey.get()).toInstance(); + flowBuilder.setKey(flowKey.get()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); // Update entry with timestamp of latest response - flow.setKey(newFlowKey); - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flow.build()); + flowBuilder.setKey(flowKey.get()); + FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId, flowBuilder.build()); + trans.putOperationalData(flowRef, flowBuilder.build()); return flowStatsEntry; } @@ -180,9 +160,9 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker tables = flowTableStats.getTables(); - logger.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); + LOG.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); for (final TableKey key : tables) { - logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); + LOG.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); this.requestAggregateFlows(key); } @@ -224,10 +204,10 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker, DataObject> e : change.getCreatedConfigurationData().entrySet()) { if (Flow.class.equals(e.getKey().getTargetType())) { final Flow flow = (Flow) e.getValue(); - logger.debug("Key {} triggered request for flow {}", e.getKey(), flow); + LOG.debug("Key {} triggered request for flow {}", e.getKey(), flow); requestFlow(flow); } else { - logger.debug("Ignoring key {}", e.getKey()); + LOG.debug("Ignoring key {}", e.getKey()); } } @@ -236,7 +216,7 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker flow = (InstanceIdentifier)key; - logger.debug("Key {} triggered remove of Flow from operational space.", key); + LOG.debug("Key {} triggered remove of Flow from operational space.", key); trans.removeOperationalData(flow); } } @@ -246,10 +226,79 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker getExistFlowKey(final Flow flowRule, final InstanceIdentifier
tableRef, + final DataModificationTransaction trans, final FlowCookieMap cookieMap) { + + if (cookieMap != null) { + for (FlowId flowId : cookieMap.getFlowIds()) { + InstanceIdentifier flowIdent = tableRef.child(Flow.class, new FlowKey(flowId)); + if (flowId.getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) { + LOG.debug("Search for flow in the operational datastore by flowID: {} ", flowIdent); + Flow readedFlow = (Flow) trans.readOperationalData(flowIdent); + if (FlowComparator.flowEquals(flowRule, readedFlow)) { + return Optional. of(new FlowKey(flowId)); + } + } else { + LOG.debug("Search for flow in the configuration datastore by flowID: {} ", flowIdent); + Flow readedFlow = (Flow) trans.readConfigurationData(flowIdent); + if (FlowComparator.flowEquals(flowRule, readedFlow)) { + return Optional. of(new FlowKey(flowId)); + } + } + } + LOG.debug("Flow was not found in the datastore. Flow {} ", flowRule); + } + return Optional.absent(); + } + + /* Returns FlowKey from existing Flow in DataStore/CONFIGURATIONAL which is identified by cookie + * and by switch flow identification (priority and match) */ + private Optional getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier
tableRef, + final DataModificationTransaction trans) { + + /* Try to find it in DataSotre/CONFIG */ + Table table= (Table)trans.readConfigurationData(tableRef); + if(table != null) { + for(Flow existingFlow : table.getFlow()) { + LOG.debug("Existing flow in data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingFlow)){ + return Optional. of(new FlowKey(existingFlow.getId())); + } + } + } + return Optional.absent(); + } + + /* Returns FlowKey which doesn't exist in any DataStore for now */ + private Optional makeAlienFlowKey(final Flow flowRule) { + + StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID) + .append(flowRule.getTableId()).append("-").append(this.unaccountedFlowsCounter); + this.unaccountedFlowsCounter++; + final FlowId flowId = new FlowId(sBuilder.toString()); + return Optional. of(new FlowKey(flowId)); + } + + /* Build new whole FlowCookieMap or add new flowKey */ + private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional flowKey, + final FlowCookie flowCookie) { + if (flowCookieMap != null) { + flowCookieMap.getFlowIds().add(flowKey.get().getId()); + } else { + final FlowCookieMapBuilder flowCookieMapBuilder = new FlowCookieMapBuilder(); + flowCookieMapBuilder.setCookie(flowCookie); + flowCookieMapBuilder.setFlowIds(Collections.singletonList(flowKey.get().getId())); + flowCookieMap = flowCookieMapBuilder.build(); + } + return flowCookieMap; + } } -- 2.36.6