Initial code structure of MDSAL based FRM module. 23/2223/4
authorPrasanna Huddar <prasanna.huddar@ericsson.com>
Mon, 28 Oct 2013 14:52:46 +0000 (20:22 +0530)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 29 Oct 2013 12:38:42 +0000 (12:38 +0000)
This is base code structure for using MD-SAL from NSF.
This is not integrated with MAIN Pom.xml.
Its still independent bundle.
We need provider in plugin to execute this code.
Also there is addFlowTest() in file FlowConsumerImpl file is used to send hardcoded data to provider in plugin comment out the code if you use rest conf API.

Signed-off-by: Prasanna Huddar <prasanna.huddar@ericsson.com>
Change-Id: Iaba741863a5aaa9d9f588a7964fc699771cee1ed

opendaylight/forwardingrulesmanager_mdsal/openflow/pom.xml [new file with mode: 0644]
opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FRMConsumerImpl.java [new file with mode: 0644]
opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FlowConsumerImpl.java [new file with mode: 0644]
opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/GroupConsumerImpl.java [new file with mode: 0644]

diff --git a/opendaylight/forwardingrulesmanager_mdsal/openflow/pom.xml b/opendaylight/forwardingrulesmanager_mdsal/openflow/pom.xml
new file mode 100644 (file)
index 0000000..9b96f86
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.1-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+    <tag>HEAD</tag>
+  </scm>
+
+  <artifactId>forwardingrulesmanager_mdsal</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>${bundle.plugin.version}</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              org.opendaylight.controller.sal.binding.api,
+              org.opendaylight.controller.sal.binding.api.data,
+              org.opendaylight.controller.md.sal.common.api.data,              
+              org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev130819.flow,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819,
+              org.opendaylight.yangtools.concepts,              
+              org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819,
+              org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes,
+              org.opendaylight.controller.sal.common.util, 
+              org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows, 
+              org.opendaylight.yangtools.yang.common,
+              org.opendaylight.yangtools.yang.binding,
+              org.apache.commons.lang3.builder,
+              org.apache.commons.lang3.tuple,
+              org.apache.felix.dm,
+              org.slf4j,
+              org.eclipse.osgi.framework.console,
+              org.osgi.framework,
+              javax.net.ssl
+            </Import-Package>
+            
+           
+            <Embed-Transitive>
+              false
+            </Embed-Transitive>
+            <Bundle-Activator>
+              org.opendaylight.controller.forwardingrulesmanager_mdsal.consumer.impl.FRMConsumerImpl
+            </Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.osgi</artifactId>
+    </dependency>    
+    <dependency>
+         <groupId>org.opendaylight.controller</groupId>
+               <artifactId>sal-binding-api</artifactId>
+               <version>1.0-SNAPSHOT</version>
+       </dependency>   
+       <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>flow-management-compatibility</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>    
+       <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+   <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-management</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <version>1.0-SNAPSHOT</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FRMConsumerImpl.java b/opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FRMConsumerImpl.java
new file mode 100644 (file)
index 0000000..ae488b6
--- /dev/null
@@ -0,0 +1,98 @@
+
+/*
+ * Copyright (c) 2013 Ericsson , 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.forwardingrulesmanager_mdsal.consumer.impl;
+
+
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class FRMConsumerImpl extends AbstractBindingAwareProvider {
+       protected static final Logger logger = LoggerFactory.getLogger(FRMConsumerImpl.class);
+       private static ProviderContext p_session;
+    private static DataBrokerService dataBrokerService;         
+    private static NotificationService notificationService;    
+    private FlowConsumerImpl flowImplRef;
+       private GroupConsumerImpl groupImplRef;
+       private static DataProviderService dataProviderService;  
+
+       @Override
+    public void onSessionInitiated(ProviderContext session) {
+       
+        FRMConsumerImpl.p_session = session;
+        
+        if (null != session) {
+               notificationService = session.getSALService(NotificationService.class);
+               
+               if (null != notificationService) {
+                       dataBrokerService = session.getSALService(DataBrokerService.class);
+                       
+                       if (null != dataBrokerService) {
+                               dataProviderService = session.getSALService(DataProviderService.class);
+                               
+                               if (null != dataProviderService) {
+                                       flowImplRef = new FlowConsumerImpl();
+                                       groupImplRef = new GroupConsumerImpl();
+                               }
+                               else {
+                                       logger.error("Data Provider Service is down or NULL. " +
+                                                       "Accessing data from configuration data store will not be possible");
+                       System.out.println("Data Broker Service is down or NULL.");
+                               }
+                                       
+                       }
+                       else {
+                               logger.error("Data Broker Service is down or NULL.");
+                       System.out.println("Data Broker Service is down or NULL.");
+                       }
+               }
+               else {
+                       logger.error("Notification Service is down or NULL.");
+               System.out.println("Notification Service is down or NULL.");
+               }                       
+        }
+        else {
+               logger.error("Consumer session is NULL. Please check if provider is registered");
+               System.out.println("Consumer session is NULL. Please check if provider is registered");
+        }
+  
+    }
+
+       public static DataProviderService getDataProviderService() {
+               return dataProviderService;
+       }
+
+       public FlowConsumerImpl getFlowImplRef() {
+               return flowImplRef;
+       }
+
+       public GroupConsumerImpl getGroupImplRef() {
+                       return groupImplRef;
+       }
+        
+       public static ProviderContext getProviderSession() {
+               return p_session;
+       }       
+
+       public static NotificationService getNotificationService() {
+               return notificationService;
+       }
+
+       public static DataBrokerService getDataBrokerService() {
+               return dataBrokerService;
+       }
+
+}
+       
diff --git a/opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FlowConsumerImpl.java b/opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/FlowConsumerImpl.java
new file mode 100644 (file)
index 0000000..a6a3c71
--- /dev/null
@@ -0,0 +1,317 @@
+package org.opendaylight.controller.forwardingrulesmanager_mdsal.consumer.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+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.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowConsumerImpl {
+       protected static final Logger logger = LoggerFactory.getLogger(FlowConsumerImpl.class);
+       private FlowEventListener flowEventListener = new FlowEventListener();
+    private Registration<NotificationListener> listener1Reg;
+       private SalFlowService flowService;
+       private FlowDataListener listener;
+       private FlowDataCommitHandler commitHandler;
+       private ConcurrentHashMap<FlowKey, Flow> originalSwView;
+       
+    public FlowConsumerImpl() {        
+               InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder().node(Flows.class).toInstance();
+       flowService = FRMConsumerImpl.getProviderSession().getRpcService(SalFlowService.class);
+               
+               if (null == flowService) {
+                       logger.error("Consumer SAL Service is down or NULL. FRM may not function as intended");
+               System.out.println("Consumer SAL Service is down or NULL.");
+               return;
+               }
+               
+               listener = new FlowDataListener();
+               if (null == FRMConsumerImpl.getDataBrokerService().registerDataChangeListener(path, listener)) {
+                       logger.error("Failed to listen on flow data modifcation events");
+               System.out.println("Consumer SAL Service is down or NULL.");
+               return;
+               }       
+                       
+               // For switch events
+               listener1Reg = FRMConsumerImpl.getNotificationService().registerNotificationListener(flowEventListener);
+               
+               if (null == listener1Reg) {
+                       logger.error("Listener to listen on flow data modifcation events");
+               System.out.println("Consumer SAL Service is down or NULL.");
+               return;
+               }
+               addFlowTest();
+               System.out.println("-------------------------------------------------------------------");
+               allocateCaches();
+               commitHandler = new FlowDataCommitHandler();
+               FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, commitHandler);
+    }
+    
+    private void allocateCaches() {
+       originalSwView = new ConcurrentHashMap<FlowKey, Flow>();
+    }
+    
+    private void addFlowTest()
+    {
+       try {
+                       NodeRef nodeOne = createNodeRef("foo:node:1");
+                       AddFlowInputBuilder input1 = new AddFlowInputBuilder();
+                       
+                       input1.setNode(nodeOne);
+                       AddFlowInput firstMsg = input1.build();
+                       
+                       if(null != flowService) {
+                               System.out.println(flowService.toString());
+                       }
+                       else
+                       {
+                               System.out.println("ConsumerFlowService is NULL");
+                       }
+                       @SuppressWarnings("unused")
+                       Future<RpcResult<java.lang.Void>> result1 = flowService.addFlow(firstMsg);
+                       
+                       
+               } catch (Exception e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+    }
+    /**
+     * Adds flow to the southbound plugin and our internal database
+     *
+     * @param path
+     * @param dataObject
+     */
+    private void addFlow(InstanceIdentifier<?> path, Flow dataObject) {
+
+        AddFlowInputBuilder input = new AddFlowInputBuilder();
+        input.setNode((dataObject).getNode());
+        input.setPriority((dataObject).getPriority());
+        input.setMatch((dataObject).getMatch());
+        input.setCookie((dataObject).getCookie());
+        input.setAction((dataObject).getAction());
+
+        // We send flow to the sounthbound plugin
+        flowService.addFlow(input.build());
+    }
+    
+    private void commitToPlugin(internalTransaction transaction) {
+        for(Entry<InstanceIdentifier<?>, Flow> entry :transaction.additions.entrySet()) {
+            addFlow(entry.getKey(),entry.getValue());
+        }
+        for(@SuppressWarnings("unused") Entry<InstanceIdentifier<?>, Flow> entry :transaction.additions.entrySet()) {
+           // updateFlow(entry.getKey(),entry.getValue());
+        }
+        
+        for(@SuppressWarnings("unused") InstanceIdentifier<?> removal : transaction.removals) {
+           // removeFlow(removal);
+        }
+    }
+    
+    private final class FlowDataCommitHandler implements DataCommitHandler<InstanceIdentifier<?>, DataObject> {
+
+        @SuppressWarnings("unchecked")
+               @Override
+         public DataCommitTransaction requestCommit(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+             // We should verify transaction
+                System.out.println("Coming in FlowDatacommitHandler");
+             internalTransaction transaction = new internalTransaction(modification);
+             transaction.prepareUpdate();
+             return transaction;
+         }
+    }
+
+    private final class internalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
+
+        private final DataModification<InstanceIdentifier<?>, DataObject> modification;
+
+        @Override
+        public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
+            return modification;
+        }
+
+        public internalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+            this.modification = modification;
+        }
+
+        Map<InstanceIdentifier<?>, Flow> additions = new HashMap<>();
+        Map<InstanceIdentifier<?>, Flow> updates = new HashMap<>();
+        Set<InstanceIdentifier<?>> removals = new HashSet<>();
+
+        /**
+         * We create a plan which flows will be added, which will be updated and
+         * which will be removed based on our internal state.
+         * 
+         */
+        void prepareUpdate() {
+
+            Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
+            for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
+                if (entry.getValue() instanceof Flow) {
+                    Flow flow = (Flow) entry.getValue();
+                    preparePutEntry(entry.getKey(), flow);
+                }
+
+            }
+
+            removals = modification.getRemovedConfigurationData();
+        }
+
+        private void preparePutEntry(InstanceIdentifier<?> key, Flow flow) {
+            Flow original = originalSwView.get(key);
+            if (original != null) {
+                // It is update for us
+                updates.put(key, flow);
+            } else {
+                // It is addition for us
+                additions.put(key, flow);
+            }
+        }
+
+        /**
+         * We are OK to go with execution of plan
+         * 
+         */
+        @Override
+        public RpcResult<Void> finish() throws IllegalStateException {
+            
+            commitToPlugin(this);
+            // We return true if internal transaction is successful.
+          //  return Rpcs.getRpcResult(true, null, Collections.emptySet());
+               return Rpcs.getRpcResult(true, null, null);
+        }
+
+        /**
+         * 
+         * We should rollback our preparation
+         * 
+         */
+        @Override
+        public RpcResult<Void> rollback() throws IllegalStateException {
+            // NOOP - we did not modified any internal state during
+            // requestCommit phase
+           // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+            return Rpcs.getRpcResult(true, null, null);
+               
+        }
+
+    }
+    
+       final class FlowEventListener implements SalFlowListener {
+       
+        List<FlowAdded> addedFlows = new ArrayList<>();
+        List<FlowRemoved> removedFlows = new ArrayList<>();
+        List<FlowUpdated> updatedFlows = new ArrayList<>();
+       
+        @Override
+        public void onFlowAdded(FlowAdded notification) {
+               System.out.println("added flow..........................");
+        addedFlows.add(notification);
+           }
+       
+           @Override
+           public void onFlowRemoved(FlowRemoved notification) {
+               removedFlows.add(notification);
+           };
+       
+           @Override
+           public void onFlowUpdated(FlowUpdated notification) {
+               updatedFlows.add(notification);
+           }
+       
+       }
+       
+       final class FlowDataListener implements DataChangeListener {
+               private SalFlowService flowService;
+               
+               public FlowDataListener() {
+                       
+               }
+               
+               @Override
+               public void onDataChanged(
+                               DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {                    
+                       System.out.println("Coming in onDataChange..............");
+                       @SuppressWarnings("unchecked")
+                       Collection<DataObject> additions = (Collection<DataObject>) change.getCreatedConfigurationData();
+                       // we can check for getCreated, getDeleted or getUpdated from DataChange Event class
+                       for (DataObject dataObject : additions) {
+                           if (dataObject instanceof NodeFlow) {
+                               NodeRef nodeOne = createNodeRef("foo:node:1");
+                                       // validating the dataObject here
+                                   AddFlowInputBuilder input = new AddFlowInputBuilder();
+                                   input.setNode(((NodeFlow) dataObject).getNode());
+                                   input.setNode(nodeOne);
+                                         //  input.setPriority(((NodeFlow) dataObject).getPriority());
+                                       //input.setMatch(((NodeFlow) dataObject).getMatch());
+                                       //input.setFlowTable(((NodeFlow) dataObject).getFlowTable());
+                                       //input.setCookie(((NodeFlow) dataObject).getCookie());
+                                       //input.setAction(((NodeFlow) dataObject).getAction());
+       
+                               @SuppressWarnings("unused")
+                                       Future<RpcResult<java.lang.Void>> result = flowService.addFlow(input.build());
+                   }
+                       }       
+               } 
+       }
+                               
+           
+           
+    private static NodeRef createNodeRef(String string) {
+        NodeKey key = new NodeKey(new NodeId(string));
+        InstanceIdentifier<Node> path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key)
+                .toInstance();
+
+        return new NodeRef(path);
+    }
+           
+         /*  private void loadFlowData() {
+       
+                   DataModification modification = (DataModification) dataservice.beginTransaction();
+                   String id = "abc";
+                   FlowKey key = new FlowKey(id, new NodeRef());
+                   InstanceIdentifier<?> path1;
+                   FlowBuilder flow = new FlowBuilder();
+                   flow.setKey(key);
+                   path1 = InstanceIdentifier.builder().node(Flows.class).node(Flow.class, key).toInstance();
+                   DataObject cls = (DataObject) modification.readConfigurationData(path);
+                   modification.putConfigurationData(path, flow.build());
+                   modification.commit();
+               }*/
+
+}
diff --git a/opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/GroupConsumerImpl.java b/opendaylight/forwardingrulesmanager_mdsal/openflow/src/main/java/org/opendaylight/controller/forwardingrulesmanager_mdsal/consumer/impl/GroupConsumerImpl.java
new file mode 100644 (file)
index 0000000..cc42e21
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.forwardingrulesmanager_mdsal.consumer.impl;
+
+public class GroupConsumerImpl {
+       public GroupConsumerImpl() {
+               
+       }
+}