DevideManagerImpl 08/17608/2
authorVaclav Demcak <vdemcak@cisco.com>
Thu, 2 Apr 2015 09:27:16 +0000 (11:27 +0200)
committermichal rehak <mirehak@cisco.com>
Thu, 2 Apr 2015 11:38:22 +0000 (11:38 +0000)
* add ProviderContext to DeviceManager constructor + fix referenced code
* implement DeviceManager#deviceConnected
* aug TableFeatures

TODO: add test suite

Change-Id: I736b3b26c3aa1f685a27bd226a6d67d6bffa8b8a
Signed-off-by: Vaclav Demcak <vdemcak@cisco.com>
model/model-flow-statistics/src/main/yang/opendaylight-flow-table-statistics.yang
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceState.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/OpenflowProtocolListenerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceStateImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java

index 5ce0565bcd088dc954be94533433a09c5600fd29..292b09e52d08b10bd871ea4bf8eee6962a9f6a9a 100644 (file)
@@ -25,6 +25,14 @@ module opendaylight-flow-table-statistics {
         uses flow-table-statistics;
     }
     
+    augment "/inv:nodes/inv:node/flow-node:table" {
+        description "Openflow flow table features data into the table node.";
+        ext:augment-identifier "node-table-features";
+        container table-feature-container {
+            uses table-types:table-features;
+        }
+    }
+    
     grouping flow-table-statistics {
         description "TODO:: simplify.";
         container flow-table-statistics {
index bee1ff23af824023e655fde64766b9b5df200176..6584f69383d3e16ddd2e021711dbf137d558f2ce 100644 (file)
@@ -108,6 +108,13 @@ public interface DeviceState {
      */
     List<PortGrouping> getEnabledPorts();
 
+    /**
+     * Return node current OF protocol version
+     *
+     * @return
+     */
+    short getVersion();
+
     /**
      * @return seed value for random operations
      */
index dd2e9e537e0137433f169407c57bac6004afd04b..ae193ad80a23facdc8cbd59b69be964e82c5b052 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.openflowplugin.impl;
 
 
+import java.util.Collection;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
 import org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProvider;
@@ -18,7 +19,6 @@ import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager
 import org.opendaylight.openflowplugin.impl.device.DeviceManagerImpl;
 import org.opendaylight.openflowplugin.impl.rpc.RpcManagerImpl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.api.types.rev150327.OfpRole;
-import java.util.Collection;
 
 /**
  * Created by Martin Bobak &lt;mbobak@cisco.com&gt; on 27.3.2015.
@@ -47,7 +47,7 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider {
 
     @Override
     public void initialize() {
-        deviceManager = new DeviceManagerImpl();
+        deviceManager = new DeviceManagerImpl(providerContext);
         rpcManager = new RpcManagerImpl(providerContext);
         //TODO : initialize statistics manager
         //TODO : initialize translatorLibrary + inject into deviceMngr
index 883b83108f295ca5bed9b93432d01a2fc5421f31..d5239ae501bf6099a5c2246ab8ff848bd977c60b 100644 (file)
@@ -87,9 +87,7 @@ public class OpenflowProtocolListenerImpl implements OpenflowProtocolListener {
     @Override
     public void onMultipartReplyMessage(final MultipartReplyMessage notification) {
         LOG.trace("Multipart Reply with XID: {}", notification.getXid());
-        if (checkState(ConnectionContext.CONNECTION_STATE.WORKING)) {
-            connectionContext.addMultipartMsg(notification);
-        }
+        connectionContext.addMultipartMsg(notification);
     }
 
     @Override
index 31a188f75bf743241528b342afca821e007961a3..56706b9c56847652cdb06555ed3371c4b3a47476 100644 (file)
@@ -8,21 +8,52 @@
 package org.opendaylight.openflowplugin.impl.device;
 
 import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Future;
 import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceContextReadyHandler;
+import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager;
+import org.opendaylight.openflowplugin.impl.common.MultipartRequestInputFactory;
+import org.opendaylight.openflowplugin.impl.common.NodeStaticReplyTranslatorUtil;
+import org.opendaylight.openflowplugin.impl.rpc.RequestContextImpl;
+import org.opendaylight.openflowplugin.impl.rpc.RpcContextImpl;
+import org.opendaylight.openflowplugin.impl.rpc.RpcManagerImpl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartRequestFlags;
+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.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestDescCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDesc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.features._case.MultipartReplyGroupFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.features._case.MultipartReplyMeterFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,41 +64,44 @@ public class DeviceManagerImpl implements DeviceManager {
 
     private static final Logger LOG = LoggerFactory.getLogger(DeviceManagerImpl.class);
 
-    @Override
-    public void deviceConnected(@CheckForNull final ConnectionContext connectionContext) {
-        Preconditions.checkArgument(connectionContext != null);
-        final DeviceState deviceState = new DeviceStateImpl(connectionContext.getFeatures(), connectionContext.getNodeId());
-//        final DeviceContextImpl deviceContextImpl = new DeviceContextImpl(connectionContext, deviceState);
+    private final BindingAwareBroker.ProviderContext providerContext;
 
-//        try {
-//            final FlowCapableNode description = queryDescription(connectionContext, deviceContextImpl.getNextXid()).get();
 
-//        } catch (InterruptedException | ExecutionException e) {
-//            // TODO Auto-generated catch block
-//            LOG.info("Failed to retrieve node static info: {}", e.getMessage());
-//        }
-
-
-        //TODO: inject translatorLibrary into deviceCtx
+    public DeviceManagerImpl (@Nonnull final ProviderContext providerContext) {
+        this.providerContext = Preconditions.checkNotNull(providerContext);
     }
 
-    /**
-     * @param connectionContext
-     * @param xid
-     */
-    private static ListenableFuture<FlowCapableNode> queryDescription(final ConnectionContext connectionContext, final Xid xid) {
-        final MultipartRequestInputBuilder builder = new MultipartRequestInputBuilder();
-        builder.setType(MultipartType.OFPMPDESC);
-        builder.setVersion(connectionContext.getFeatures().getVersion());
-        builder.setFlags(new MultipartRequestFlags(false));
-        builder.setMultipartRequestBody(new MultipartRequestDescCaseBuilder()
-                .build());
-        builder.setXid(xid.getValue());
-        connectionContext.getConnectionAdapter().multipartRequest(builder.build());
-
-        //TODO: involve general wait-for-answer mechanism and return future with complete value
-        //TODO: translate message
-        return Futures.immediateFuture(null);
+    @Override
+    public void deviceConnected(@CheckForNull final ConnectionContext connectionContext) {
+        Preconditions.checkArgument(connectionContext != null);
+        final DataBroker dataBroker = providerContext.getSALService(DataBroker.class);
+        final DeviceState deviceState = new DeviceStateImpl(connectionContext.getFeatures(), connectionContext.getNodeId());
+        final DeviceContext deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker);
+        final WriteTransaction tx = deviceContext.getWriteTransaction();
+
+        final Xid nodeDescXid = deviceContext.getNextXid();
+        final ListenableFuture<Collection<MultipartReply>> replyDesc = getNodeStaticInfo(nodeDescXid, connectionContext,
+                MultipartType.OFPMPDESC, tx, deviceState.getNodeInstanceIdentifier(), deviceState.getVersion());
+
+        final Xid nodeMeterXid = deviceContext.getNextXid();
+        final ListenableFuture<Collection<MultipartReply>> replyMeterFeature = getNodeStaticInfo(nodeMeterXid, connectionContext,
+                MultipartType.OFPMPMETERFEATURES, tx, deviceState.getNodeInstanceIdentifier(), deviceState.getVersion());
+
+        final Xid nodeGroupXid = deviceContext.getNextXid();
+        final ListenableFuture<Collection<MultipartReply>> replyGroupFeatures = getNodeStaticInfo(nodeGroupXid, connectionContext,
+                MultipartType.OFPMPGROUPFEATURES, tx, deviceState.getNodeInstanceIdentifier(), deviceState.getVersion());
+
+        final Xid nodeTableXid = deviceContext.getNextXid();
+        final ListenableFuture<Collection<MultipartReply>> replyTableFeatures = getNodeStaticInfo(nodeTableXid, connectionContext,
+                MultipartType.OFPMPTABLEFEATURES, tx, deviceState.getNodeInstanceIdentifier(), deviceState.getVersion());
+
+        // FIXME : add statistics
+        final RpcManager rpcManager = new RpcManagerImpl(providerContext);
+        final RequestContextStack rcs = new RpcContextImpl(providerContext, deviceContext);
+        final RequestContext<?> requestContext = new RequestContextImpl<>(rcs);
+        rpcManager.deviceConnected(deviceContext, requestContext);
+        // TODO : barier...
+        tx.submit();
     }
 
     @Override
@@ -88,4 +122,74 @@ public class DeviceManagerImpl implements DeviceManager {
 
     }
 
+    private static ListenableFuture<Collection<MultipartReply>> getNodeStaticInfo(final Xid xid, final ConnectionContext cContext,
+            final MultipartType type, final WriteTransaction tx, final InstanceIdentifier<Node> nodeII, final short version) {
+        final ListenableFuture<Collection<MultipartReply>> future = cContext.registerMultipartMsg(xid.getValue());
+        Futures.addCallback(future, new FutureCallback<Collection<MultipartReply>>() {
+            @Override
+            public void onSuccess(final Collection<MultipartReply> result) {
+                Preconditions.checkArgument(result != null);
+                translateAndWriteReply(type, tx, nodeII, result);
+            }
+            @Override
+            public void onFailure(final Throwable t) {
+                LOG.info("Failed to retrieve static node {} info: {}", type, t.getMessage());
+            }
+        });
+        final Future<RpcResult<Void>> rpcFuture = cContext.getConnectionAdapter()
+                .multipartRequest(MultipartRequestInputFactory.makeMultipartRequestInput(xid.getValue(), version, type));
+        Futures.addCallback(JdkFutureAdapters.listenInPoolThread(rpcFuture), new FutureCallback<RpcResult<Void>>() {
+            @Override
+            public void onSuccess(final RpcResult<Void> result) {
+                // NOOP
+            }
+            @Override
+            public void onFailure(final Throwable t) {
+                future.cancel(true);
+            }
+        });
+        return future;
+    }
+
+    private static void translateAndWriteReply(final MultipartType type, final WriteTransaction tx,
+            final InstanceIdentifier<Node> nodeII, final Collection<MultipartReply> result) {
+        for (final MultipartReply reply : result) {
+            switch (type) {
+            case OFPMPDESC:
+                Preconditions.checkArgument(reply instanceof MultipartReplyDesc);
+                final FlowCapableNode fcNode = NodeStaticReplyTranslatorUtil.nodeDescTranslator((MultipartReplyDesc) reply);
+                final InstanceIdentifier<FlowCapableNode> fNodeII = nodeII.augmentation(FlowCapableNode.class);
+                tx.put(LogicalDatastoreType.OPERATIONAL, fNodeII, fcNode);
+                break;
+
+            case OFPMPTABLEFEATURES:
+                Preconditions.checkArgument(reply instanceof MultipartReplyTableFeatures);
+                final List<TableFeatures> tables = NodeStaticReplyTranslatorUtil.nodeTableFeatureTranslator((MultipartReplyTableFeatures) reply);
+                for (final TableFeatures table : tables) {
+                    final Short tableId = table.getTableId();
+                    final InstanceIdentifier<Table> tableII = nodeII.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId));
+                    tx.put(LogicalDatastoreType.OPERATIONAL, tableII, new TableBuilder().setId(tableId).setTableFeatures(Collections.singletonList(table)).build());
+                }
+                break;
+
+            case OFPMPMETERFEATURES:
+                Preconditions.checkArgument(reply instanceof MultipartReplyMeterFeatures);
+                final NodeMeterFeatures mFeature = NodeStaticReplyTranslatorUtil.nodeMeterFeatureTranslator((MultipartReplyMeterFeatures) reply);
+                final InstanceIdentifier<NodeMeterFeatures> mFeatureII = nodeII.augmentation(NodeMeterFeatures.class);
+                tx.put(LogicalDatastoreType.OPERATIONAL, mFeatureII, mFeature);
+                break;
+
+            case OFPMPGROUPFEATURES:
+                Preconditions.checkArgument(reply instanceof MultipartReplyGroupFeatures);
+                final NodeGroupFeatures gFeature = NodeStaticReplyTranslatorUtil.nodeGroupFeatureTranslator((MultipartReplyGroupFeatures) reply);
+                final InstanceIdentifier<NodeGroupFeatures> gFeatureII = nodeII.augmentation(NodeGroupFeatures.class);
+                tx.put(LogicalDatastoreType.OPERATIONAL, gFeatureII, gFeature);
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unnexpected MultipartType " + type);
+            }
+        }
+    }
+
 }
index 1da609792cef4c8048a58d5b8916eb712f0d426a..ca55a262e1dc666bfb8465c5c03e6fb87bafa657 100644 (file)
@@ -47,6 +47,7 @@ class DeviceStateImpl implements DeviceState {
     private final Map<Long, Long> portsBandwidth;
     private final NodeId nodeId;
     private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
+    private final short version;
     private boolean valid;
 
     public DeviceStateImpl(@CheckForNull final FeaturesReply featuresReply, @Nonnull final NodeId nodeId) {
@@ -55,6 +56,7 @@ class DeviceStateImpl implements DeviceState {
         featuresOutput = new GetFeaturesOutputBuilder(featuresReply).build();
         this.nodeId = Preconditions.checkNotNull(nodeId);
         nodeII = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+        version = featuresReply.getVersion();
         portGrouping = new HashMap<>();
         portsBandwidth = new HashMap<>();
         for (final PhyPort port : featuresReply.getPhyPort()) {
@@ -133,4 +135,9 @@ class DeviceStateImpl implements DeviceState {
         return hashCode();
     }
 
+    @Override
+    public short getVersion() {
+        return version;
+    }
+
 }
index 9fa3e75f0a084584137b5f61c6401c0f9055414e..496405efcc13becdc308cd100664be5db8e0f398 100644 (file)
@@ -17,6 +17,8 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
@@ -37,16 +39,19 @@ public class DeviceManagerImplTest {
     private ConnectionAdapter connectionAdapter;
     @Mock
     private FeaturesReply features;
+    @Mock
+    private ProviderContext providerContext;
 
     /**
      * @throws java.lang.Exception
      */
     @Before
     public void setUp() throws Exception {
+        Mockito.when(providerContext.getSALService(DataBroker.class)).thenReturn(Mockito.mock(DataBroker.class));
         Mockito.when(connectionContext.getConnectionAdapter()).thenReturn(connectionAdapter);
         Mockito.when(connectionContext.getFeatures()).thenReturn(features);
         Mockito.when(features.getVersion()).thenReturn((short) 42);
-        deviceManager = new DeviceManagerImpl();
+        deviceManager = new DeviceManagerImpl(providerContext);
     }
 
     /**