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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
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<InstanceIdentifier<?>, DataObject> changeEvent) {
+ public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
this.transactionId = this.newTransactionIdentifier().toString();
-
+ /* All DataObjects for create */
final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
- changeEvent.getCreatedConfigurationData().entrySet();
- final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
- new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
-
+ changeEvent.getCreatedData().entrySet();
+ /* All DataObjects for updates - init HashSet */
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<>();
+ /* Filtered DataObject for update processing only */
Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet =
- changeEvent.getUpdatedConfigurationData().entrySet();
+ changeEvent.getUpdatedData().entrySet();
updatedEntries.addAll(updateConfigEntrySet);
updatedEntries.removeAll(createdEntries);
-
+ /* All DataObjects for remove */
final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
- changeEvent.getRemovedConfigurationData();
-
+ changeEvent.getRemovedPaths();
+ /* Create DataObject processing (send to device) */
for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
- InstanceIdentifier<? extends DataObject> c_key = createdEntry.getKey();
- DataObject c_value = createdEntry.getValue();
- this.add(c_key, c_value);
+ InstanceIdentifier<? extends DataObject> entryKey = createdEntry.getKey();
+ DataObject entryValue = createdEntry.getValue();
+ if (preconditionForChange(entryKey, entryValue, null)) {
+ this.add(entryKey, entryValue);
+ }
}
for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
- changeEvent.getOriginalConfigurationData();
-
- InstanceIdentifier<? extends Object> 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<? extends Object> 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<InstanceIdentifier<? extends DataObject>, 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;
}
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<? extends DataObject> 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<? extends DataObject> identifier,
+ final ReadOnlyTransaction readTrans) {
+ final InstanceIdentifier<Node> 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<? extends DataObject> identifier,
final DataObject remove);
- protected abstract void update(
- final InstanceIdentifier<? extends DataObject> 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<? extends DataObject> identifier,
final DataObject original, final DataObject update);
- protected abstract void add(
- final InstanceIdentifier<? extends DataObject> 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<? extends DataObject> identifier,
final DataObject add);
}
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ * *
+ */
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.<DataProviderService>getSALService(DataProviderService.class);
- FRMActivator.flowProvider.setDataService(flowSalService);
- SalFlowService rpcFlowSalService = session.<SalFlowService>getRpcService(SalFlowService.class);
- FRMActivator.flowProvider.setSalFlowService(rpcFlowSalService);
- FRMActivator.flowProvider.start();
- DataProviderService groupSalService = session.<DataProviderService>getSALService(DataProviderService.class);
- FRMActivator.groupProvider.setDataService(groupSalService);
- SalGroupService rpcGroupSalService = session.<SalGroupService>getRpcService(SalGroupService.class);
- FRMActivator.groupProvider.setSalGroupService(rpcGroupSalService);
- FRMActivator.groupProvider.start();
- DataProviderService meterSalService = session.<DataProviderService>getSALService(DataProviderService.class);
- FRMActivator.meterProvider.setDataService(meterSalService);
- SalMeterService rpcMeterSalService = session.<SalMeterService>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
--- /dev/null
+/**
+ * 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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Jun 13, 2014
+ */
+public enum FlowCookieProducer {
+
+ INSTANCE;
+
+ /* Flow_Cookie_Key and Flow_Ids MapHolder */
+ private static final AtomicLongMap<InstanceIdentifier<Table>> cookieKeys = AtomicLongMap.create();
+
+ /**
+ * Method returns the unique cookie for a node table.
+ * Flow Cookie Key signs List<FlowId> for a right flow statistic identification
+ * in the DataStore/operational.
+ * We need a List<FlowId> 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<Table> tableIdentifier
+ * @return unique BigInteger flowCookie for a node table
+ */
+ public BigInteger getNewCookie(final InstanceIdentifier<Table> 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<Table> tableIdentifier
+ */
+ public void clean(final InstanceIdentifier<Table> tableIdentifier) {
+ FlowCookieProducer.validationTableIdentifier(tableIdentifier);
+ cookieKeys.remove(tableIdentifier);
+ }
+
+ /*
+ * Help the TableIdentifer input validation method
+ */
+ private static void validationTableIdentifier(final InstanceIdentifier<Table> tableIdent) {
+ Preconditions.checkArgument(tableIdent != null, "Input validation exception: TableIdentifier can not be null !");
+ }
+}
*/
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;
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
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<? extends DataObject> identifier,
+ final DataObject removeDataObj) {
- @Override
- protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
- if ((removeDataObj instanceof Flow)) {
-
- final Flow flow = ((Flow) removeDataObj);
- final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<Table> tableIdent = identifier.firstIdentifierOf(Table.class);
+ final InstanceIdentifier<Node> 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<? extends DataObject> identifier, DataObject original, DataObject update) {
- if (original instanceof Flow && update instanceof Flow) {
+ protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject original, final DataObject update) {
+
+ final Flow originalFlow = ((Flow) original);
+ final Flow updatedFlow = ((Flow) update);
+ final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
+ final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
- final Flow originalFlow = ((Flow) original);
- final Flow updatedFlow = ((Flow) update);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node>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<? extends DataObject> identifier,
+ final DataObject addDataObj) {
+
+ final Flow flow = ((Flow) addDataObj);
+ final InstanceIdentifier<Table> 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<? extends DataObject> identifier, DataObject addDataObj) {
- if ((addDataObj instanceof Flow)) {
-
- final Flow flow = ((Flow) addDataObj);
- final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> 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));
}
}
*/
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;
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
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<DataChangeListener> flowDataChangeListenerRegistration;
+ private DataChangeListener flowDataChangeListener;
+ private ListenerRegistration<DataChangeListener> 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<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
- InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
- InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
- InstanceIdentifierBuilder<Table> tableChild = augmentFlowCapNode.<Table> child(Table.class);
- InstanceIdentifierBuilder<Flow> flowChild = tableChild.<Flow> child(Flow.class);
- final InstanceIdentifier<? extends DataObject> flowDataObjectPath = flowChild.toInstance();
+ InstanceIdentifier<Flow> 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;
}
}
+++ /dev/null
-/**
- * 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
- }
-}
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;
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
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<? extends DataObject> identifier,
+ final DataObject removeDataObj) {
+
+ final Group group = ((Group) removeDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> identifier, DataObject removeDataObj) {
- if ((removeDataObj instanceof Group)) {
+ protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject original, final DataObject update) {
- final Group group = ((Group) removeDataObj);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
- final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
+ final Group originalGroup = ((Group) original);
+ final Group updatedGroup = ((Group) update);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> 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<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> identifier,
+ final DataObject addDataObj) {
- Uri uri = new Uri(this.getTransactionId());
- builder.setTransactionUri(uri);
+ final Group group = ((Group) addDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> identifier, DataObject addDataObj) {
- if ((addDataObj instanceof Group)) {
- final Group group = ((Group) addDataObj);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> 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));
}
}
*/
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
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<DataChangeListener> groupDataChangeListenerRegistration;
+ private DataChangeListener groupDataChangeListener;
+ private ListenerRegistration<DataChangeListener> 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<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
- InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
- InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
- InstanceIdentifierBuilder<Group> groupChild = augmentFlowCapNode.<Group> child(Group.class);
- final InstanceIdentifier<? extends DataObject> groupDataObjectPath = groupChild.toInstance();
+ InstanceIdentifier<Group> 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;
}
}
+++ /dev/null
-/**
- * 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
- }
-}
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;
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
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<? extends DataObject> identifier, DataObject removeDataObj) {
- if ((removeDataObj instanceof Meter)) {
+ protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject removeDataObj) {
- final Meter meter = ((Meter) removeDataObj);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
- final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
+ final Meter meter = ((Meter) removeDataObj);
+ final InstanceIdentifier<Node> 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<? extends DataObject> identifier, DataObject original, DataObject update) {
- if (original instanceof Meter && update instanceof Meter) {
+ protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject original, final DataObject update) {
- final Meter originalMeter = ((Meter) original);
- final Meter updatedMeter = ((Meter) update);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
- final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
+ final Meter originalMeter = ((Meter) original);
+ final Meter updatedMeter = ((Meter) update);
+ final InstanceIdentifier<Node> 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<? extends DataObject> identifier, DataObject addDataObj) {
- if ((addDataObj instanceof Meter)) {
+ protected void add(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject addDataObj) {
+
+ final Meter meter = ((Meter) addDataObj);
+ final InstanceIdentifier<Node> nodeInstanceId = identifier.firstIdentifierOf(Node.class);
+ final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter);
- final Meter meter = ((Meter) addDataObj);
- final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> 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<? extends DataObject> 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
+}
*/
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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
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<DataChangeListener> meterDataChangeListenerRegistration;
+ private DataChangeListener meterDataChangeListener;
+ private ListenerRegistration<DataChangeListener> 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<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
- InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
- InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
- InstanceIdentifierBuilder<Meter> meterChild = augmentFlowCapNode.<Meter> child(Meter.class);
- final InstanceIdentifier<? extends DataObject> meterDataObjectPath = meterChild.toInstance();
+ InstanceIdentifier<Meter> 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
+}
+++ /dev/null
-/**
- * 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
- }
-}
--- /dev/null
+/**
+ * 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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * 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<InstanceIdentifier<?>, DataObject> changeEvent) {
+ /* FlowCapableNode DataObjects for reconciliation */
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
+ changeEvent.getCreatedData().entrySet();
+ /* FlowCapableNode DataObjects for clean FlowCookieHolder */
+ final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
+ changeEvent.getRemovedPaths();
+ for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
+ InstanceIdentifier<? extends DataObject> entryKey = createdEntry.getKey();
+ DataObject entryValue = createdEntry.getValue();
+ if (preconditionForChange(entryKey, entryValue, null)) {
+ this.add(entryKey, entryValue);
+ }
+ }
+ for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
+ Map<InstanceIdentifier<? extends DataObject>, 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<? extends DataObject> identifier,
+ final DataObject removeDataObj) {
+
+ final InstanceIdentifier<FlowCapableNode> flowNodeIdent =
+ identifier.firstIdentifierOf(FlowCapableNode.class);
+ final FlowCapableNode flowNode = ((FlowCapableNode) removeDataObj);
+
+ for (Table flowTable : flowNode.getTable()) {
+ final InstanceIdentifier<Table> tableIdent =
+ flowNodeIdent.child(Table.class, flowTable.getKey());
+ FlowCookieProducer.INSTANCE.clean(tableIdent);
+ }
+ }
+
+ @Override
+ /* Reconciliation by connect new FlowCapableNode */
+ protected void add(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject addDataObj) {
+
+ final InstanceIdentifier<FlowCapableNode> flowNodeIdent =
+ identifier.firstIdentifierOf(FlowCapableNode.class);
+ final Optional<FlowCapableNode> flowCapNode = this.readFlowCapableNode(flowNodeIdent);
+
+ if (flowCapNode.isPresent()) {
+ final InstanceIdentifier<Node> 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<Table> 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<? extends DataObject> identifier,
+ final DataObject original, DataObject update) {
+ // NOOP - Listener is registered for DataChangeScope.BASE only
+ }
+
+ @Override
+ protected boolean preconditionForChange(final InstanceIdentifier<? extends DataObject> identifier,
+ final DataObject dataObj, final DataObject update) {
+ return (dataObj instanceof FlowCapableNode);
+ }
+
+ private Optional<FlowCapableNode> readFlowCapableNode(final InstanceIdentifier<FlowCapableNode> flowNodeIdent) {
+ ReadOnlyTransaction readTrans = this.provider.getDataService().newReadOnlyTransaction();
+ try {
+ ListenableFuture<Optional<FlowCapableNode>> confFlowNode =
+ readTrans.read(LogicalDatastoreType.CONFIGURATION, flowNodeIdent);
+ if (confFlowNode.get().isPresent()) {
+ return Optional.<FlowCapableNode> 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();
+ }
+ }
+}
--- /dev/null
+/**
+ * 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 <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * 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<DataChangeListener> 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<FlowCapableNode> 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;
+ }
+}
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;
+ }
+ }
+ }
}
}
public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+ if (statsFlow == null || storedFlow == null) {
+ return false;
+ }
if (statsFlow.getClass() != storedFlow.getClass()) {
return false;
}
} 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) {
*/
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;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
+
final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
- 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;
FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
- FlowBuilder flow = new FlowBuilder(map);
- if(map.getFlowId() != null) {
- flow.setId(new FlowId(map.getFlowId().getValue()));
+ FlowBuilder flowBuilder = new FlowBuilder(map);
+ if (map.getFlowId() != null) {
+ flowBuilder.setId(new FlowId(map.getFlowId().getValue()));
}
- if(map.getFlowId()!= null) {
- flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+ if (map.getFlowId() != null) {
+ flowBuilder.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
}
- Flow flowRule = flow.build();
+ Flow flowRule = flowBuilder.build();
FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
stats.setByteCount(map.getByteCount());
flowStatisticsData.setFlowStatistics(flowStatistics.build());
- logger.debug("Flow : {}",flowRule.toString());
- logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+ LOG.debug("Flow : {}",flowRule.toString());
+ LOG.debug("Statistics to augment : {}",flowStatistics.build().toString());
InstanceIdentifier<Table> 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<Flow> 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<Flow> 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<FlowCookieMap> 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> 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<Flow> 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<Flow> 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;
}
// FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
// comes back -- we do not have any tables anyway.
final Collection<TableKey> 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);
}
for (Entry<InstanceIdentifier<?>, 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());
}
}
if (Flow.class.equals(key.getTargetType())) {
@SuppressWarnings("unchecked")
final InstanceIdentifier<Flow> flow = (InstanceIdentifier<Flow>)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);
}
}
@Override
public void start(final DataBrokerService dbs) {
if (flowStatsService == null) {
- logger.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
+ LOG.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
return;
}
super.start(dbs);
}
+
+ /* Returns Exist FlowKey from exist FlowCookieMap identified by cookie
+ * and by switch flow identification (priority and match)*/
+ private Optional<FlowKey> getExistFlowKey(final Flow flowRule, final InstanceIdentifier<Table> tableRef,
+ final DataModificationTransaction trans, final FlowCookieMap cookieMap) {
+
+ if (cookieMap != null) {
+ for (FlowId flowId : cookieMap.getFlowIds()) {
+ InstanceIdentifier<Flow> 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.<FlowKey> 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.<FlowKey> 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<FlowKey> getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier<Table> 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.<FlowKey> of(new FlowKey(existingFlow.getId()));
+ }
+ }
+ }
+ return Optional.absent();
+ }
+
+ /* Returns FlowKey which doesn't exist in any DataStore for now */
+ private Optional<FlowKey> 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.<FlowKey> of(new FlowKey(flowId));
+ }
+
+ /* Build new whole FlowCookieMap or add new flowKey */
+ private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional<FlowKey> 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;
+ }
}