Add a simple l2agent for demo. 47/1447/2
authorSuchi Raman <suchi.raman@plexxi.com>
Thu, 26 Sep 2013 17:56:54 +0000 (13:56 -0400)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 27 Sep 2013 13:28:43 +0000 (13:28 +0000)
Signed-off-by: Suchi Raman <suchi.raman@plexxi.com>
affinity/implementation/pom.xml
affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/Activator.java
affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/AffinityManagerImpl.java
l2agent/pom.xml [new file with mode: 0644]
l2agent/src/main/java/org/opendaylight/l2agent/Activator.java [new file with mode: 0644]
l2agent/src/main/java/org/opendaylight/l2agent/L2Agent.java [new file with mode: 0644]
l2agent/src/test/java/org/opendaylight/l2agent/L2AgentTest.java [new file with mode: 0644]
pom.xml

index 2abf5c6250dcaaba9288c1eef119c14deac0f2d3..84df90b5a512513a2e03d7a857b52874f6bc432a 100644 (file)
@@ -35,6 +35,7 @@
           <instructions>
             <Import-Package>
               org.opendaylight.affinity.affinity,
+              org.opendaylight.affinity.l2agent,
               org.opendaylight.controller.clustering.services,
               org.opendaylight.controller.configuration,
               org.opendaylight.controller.hosttracker,
@@ -43,7 +44,6 @@
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.sal.packet,
               org.opendaylight.controller.sal.inventory,
-              org.opendaylight.controller.tutorial_L2_forwarding,
               org.opendaylight.controller.sal.flowprogrammer, 
               org.opendaylight.controller.sal.match,
               org.opendaylight.controller.sal.action,
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
     <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>tutorial_L2_forwarding</artifactId>
+      <groupId>org.opendaylight.affinity</groupId>
+      <artifactId>l2agent</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
index 8d8fbec054e45fd7637bc378027ee90755721480..98ec073d3f3ab91afebd6967011889c4fed613a8 100644 (file)
@@ -23,7 +23,7 @@ import org.opendaylight.affinity.affinity.IAffinityManagerAware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
-import org.opendaylight.controller.tutorial_L2_forwarding.TutorialL2Forwarding;
+import org.opendaylight.affinity.l2agent.L2Agent;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 
 /**
@@ -108,7 +108,7 @@ public class Activator extends ComponentActivatorAbstractBase {
                     "setFlowProgrammerService", "unsetFlowProgrammerService")
                     .setRequired(true));
             c.add(createContainerServiceDependency(containerName).setService(
-                    TutorialL2Forwarding.class).setCallbacks(
+                    L2Agent.class).setCallbacks(
                     "setL2AgentService", "unsetL2AgentService")
                     .setRequired(true));
             c.add(createContainerServiceDependency(containerName).setService(
index 4a7799e450b63f6cfe820bf7dcfd9c46b5e5099f..2e8ffbd9e91b290b21c22d364f90a9695ecc998b 100644 (file)
@@ -89,7 +89,7 @@ import org.opendaylight.affinity.affinity.IAffinityManagerAware;
 import org.opendaylight.controller.hosttracker.IfIptoHost;
 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
-import org.opendaylight.controller.tutorial_L2_forwarding.TutorialL2Forwarding;
+import org.opendaylight.affinity.l2agent.L2Agent;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -107,7 +107,7 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
     private String affinityGroupFileName = null;
     private IFlowProgrammerService fps = null;
     private ISwitchManager switchManager = null;
-    private TutorialL2Forwarding l2agent = null;
+    private L2Agent l2agent = null;
 
     private ConcurrentMap<String, AffinityGroup> affinityGroupList;
     private ConcurrentMap<String, AffinityLink> affinityLinkList;
@@ -245,12 +245,12 @@ public class AffinityManagerImpl implements IAffinityManager, IConfigurationCont
             this.fps = null;
         }
     }
-    public void setL2Agent(TutorialL2Forwarding s)
+    public void setL2Agent(L2Agent s)
     {
         this.l2agent = s;
     }
 
-    public void unsetL2Agent(TutorialL2Forwarding s) {
+    public void unsetL2Agent(L2Agent s) {
         if (this.l2agent == s) {
             this.l2agent = null;
         }
diff --git a/l2agent/pom.xml b/l2agent/pom.xml
new file mode 100644 (file)
index 0000000..339817f
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.affinity</groupId>
+    <artifactId>affinityParent</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <artifactId>l2agent</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.match,
+              org.opendaylight.controller.sal.action,
+              org.opendaylight.controller.sal.flowprogrammer,
+              org.opendaylight.controller.switchmanager,
+              org.apache.felix.dm,
+              org.osgi.service.component,
+              org.slf4j
+            </Import-Package>
+            <Export-Package>
+              org.opendaylight.affinity.l2agent
+            </Export-Package>
+            <Bundle-Activator>
+              org.opendaylight.affinity.l2agent.Activator
+            </Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>switchmanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/l2agent/src/main/java/org/opendaylight/l2agent/Activator.java b/l2agent/src/main/java/org/opendaylight/l2agent/Activator.java
new file mode 100644 (file)
index 0000000..3ade6e7
--- /dev/null
@@ -0,0 +1,97 @@
+
+/*
+ * Copyright (c) 2013 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.affinity.l2agent;
+
+import java.util.Hashtable;
+import java.util.Dictionary;
+import org.apache.felix.dm.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+
+public class Activator extends ComponentActivatorAbstractBase {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Activator.class);
+
+    /**
+     * Function called when the activator starts just after some
+     * initializations are done by the
+     * ComponentActivatorAbstractBase.
+     *
+     */
+    public void init() {
+
+    }
+
+    /**
+     * Function called when the activator stops just before the
+     * cleanup done by ComponentActivatorAbstractBase
+     *
+     */
+    public void destroy() {
+
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the
+     * list of known implementations for services inside a container
+     *
+     *
+     * @return An array containing all the CLASS objects that will be
+     * instantiated in order to get an fully working implementation
+     * Object
+     */
+    public Object[] getImplementations() {
+        Object[] res = { L2Agent.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies
+     * is required.
+     *
+     * @param c dependency manager Component object, used for
+     * configuring the dependencies exported and imported
+     * @param imp Implementation class that is being configured,
+     * needed as long as the same routine can configure multiple
+     * implementations
+     * @param containerName The containerName being configured, this allow
+     * also optional per-container different behavior if needed, usually
+     * should not be the case though.
+     */
+    public void configureInstance(Component c, Object imp, String containerName) {
+        if (imp.equals(L2Agent.class)) {
+            // export the services
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "L2Agent");
+            c.setInterface(new String[] { IListenDataPacket.class.getName() }, props);
+
+            // register dependent modules
+            c.add(createContainerServiceDependency(containerName).setService(
+                    ISwitchManager.class).setCallbacks("setSwitchManager",
+                    "unsetSwitchManager").setRequired(true));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IDataPacketService.class).setCallbacks(
+                    "setDataPacketService", "unsetDataPacketService")
+                    .setRequired(true));
+
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IFlowProgrammerService.class).setCallbacks(
+                    "setFlowProgrammerService", "unsetFlowProgrammerService")
+                    .setRequired(true));
+        }
+    }
+}
diff --git a/l2agent/src/main/java/org/opendaylight/l2agent/L2Agent.java b/l2agent/src/main/java/org/opendaylight/l2agent/L2Agent.java
new file mode 100644 (file)
index 0000000..56c0041
--- /dev/null
@@ -0,0 +1,224 @@
+
+/*
+ * Copyright (c) 2013 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.affinity.l2agent;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.lang.String;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.packet.ARP;
+import org.opendaylight.controller.sal.packet.BitBufferHelper;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.PacketResult;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Output;
+import org.opendaylight.controller.sal.action.Flood;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.match.MatchField;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+import org.opendaylight.controller.switchmanager.Subnet;
+
+public class L2Agent implements IListenDataPacket {
+    private static final Logger logger = LoggerFactory
+            .getLogger(L2Agent.class);
+    private ISwitchManager switchManager = null;
+    private IFlowProgrammerService programmer = null;
+    private IDataPacketService dataPacketService = null;
+    private Map<Long, NodeConnector> mac_to_port = new HashMap<Long, NodeConnector>();
+    private String function = "switch";
+
+    void setDataPacketService(IDataPacketService s) {
+        this.dataPacketService = s;
+    }
+
+    void unsetDataPacketService(IDataPacketService s) {
+        if (this.dataPacketService == s) {
+            this.dataPacketService = null;
+        }
+    }
+
+    public void setFlowProgrammerService(IFlowProgrammerService s)
+    {
+        this.programmer = s;
+    }
+
+    public void unsetFlowProgrammerService(IFlowProgrammerService s) {
+        if (this.programmer == s) {
+            this.programmer = null;
+        }
+    }
+
+    void setSwitchManager(ISwitchManager s) {
+        logger.debug("SwitchManager set");
+        this.switchManager = s;
+    }
+
+    void unsetSwitchManager(ISwitchManager s) {
+        if (this.switchManager == s) {
+            logger.debug("SwitchManager removed!");
+            this.switchManager = null;
+        }
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        logger.info("Initialized");
+    }
+
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called
+     * and after the services provided by the class are registered in
+     * the service registry
+     *
+     */
+    void start() {
+        logger.info("Started");
+    }
+
+    /**
+     * Function called by the dependency manager before the services
+     * exported by the component are unregistered, this will be
+     * followed by a "destroy ()" calls
+     *
+     */
+    void stop() {
+        logger.info("Stopped");
+    }
+
+    private void floodPacket(RawPacket inPkt) {
+        NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
+        Node incoming_node = incoming_connector.getNode();
+
+        Set<NodeConnector> nodeConnectors =
+                this.switchManager.getUpNodeConnectors(incoming_node);
+
+        for (NodeConnector p : nodeConnectors) {
+            if (!p.equals(incoming_connector)) {
+                try {
+                    RawPacket destPkt = new RawPacket(inPkt);
+                    destPkt.setOutgoingNodeConnector(p);
+                    this.dataPacketService.transmitDataPacket(destPkt);
+                } catch (ConstructionException e2) {
+                    continue;
+                }
+            }
+        }
+    }
+
+    @Override
+    public PacketResult receiveDataPacket(RawPacket inPkt) {
+        if (inPkt == null) {
+            return PacketResult.IGNORED;
+        }
+        logger.trace("Received a frame of size: {}",
+                        inPkt.getPacketData().length);
+
+        Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
+        NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
+        Node incoming_node = incoming_connector.getNode();
+
+        if (formattedPak instanceof Ethernet) {
+            byte[] srcMAC = ((Ethernet)formattedPak).getSourceMACAddress();
+            byte[] dstMAC = ((Ethernet)formattedPak).getDestinationMACAddress();
+
+            // Hub implementation
+            if (function.equals("hub")) {
+                floodPacket(inPkt);
+                return PacketResult.CONSUME;
+            }
+
+            // Switch
+            else {
+                long srcMAC_val = BitBufferHelper.toNumber(srcMAC);
+                long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
+
+                this.mac_to_port.put(srcMAC_val, incoming_connector);
+
+                Match match = new Match();
+                match.setField( new MatchField(MatchType.IN_PORT, incoming_connector) );
+                match.setField( new MatchField(MatchType.DL_DST, dstMAC.clone()) );
+
+                NodeConnector dst_connector;
+
+                // Do I know the destination MAC?
+                if ((dst_connector = this.mac_to_port.get(dstMAC_val)) != null) {
+                    List<Action> actions = new ArrayList<Action>();
+                    actions.add(new Output(dst_connector));
+
+                    Flow f = new Flow(match, actions);
+
+                    // Modify the flow on the network node
+                    Status status = programmer.addFlow(incoming_node, f);
+                    if (!status.isSuccess()) {
+                        logger.warn(
+                                "SDN Plugin failed to program the flow: {}. The failure is: {}",
+                                f, status.getDescription());
+                        return PacketResult.IGNORED;
+                    }
+                    logger.info("Installed flow {} in node {}",
+                            f, incoming_node);
+                }
+                else
+                    floodPacket(inPkt);
+            }
+        }
+        return PacketResult.IGNORED;
+    }
+
+    /*
+     * Return MAC adderss to port
+     */
+    public NodeConnector lookupMacAddress(byte[] macAddress) {
+        NodeConnector dst_connector;
+        return this.mac_to_port.get(macAddress);
+    }
+}
diff --git a/l2agent/src/test/java/org/opendaylight/l2agent/L2AgentTest.java b/l2agent/src/test/java/org/opendaylight/l2agent/L2AgentTest.java
new file mode 100644 (file)
index 0000000..d08c4e7
--- /dev/null
@@ -0,0 +1,29 @@
+\r
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.affinity.l2agent;\r
+\r
+\r
+import junit.framework.TestCase;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+\r
+public class L2AgentTest extends TestCase {\r
+\r
+        @Test\r
+        public void testL2AgentCreation() {\r
+\r
+                L2Agent ah = null;\r
+                ah = new L2Agent();\r
+                Assert.assertTrue(ah != null);\r
+\r
+        }\r
+\r
+}\r
diff --git a/pom.xml b/pom.xml
index 49d2c59246ad35d9cc3877b97bfc87b585e0d39a..d2a42d1d2eedd95dc74b88dc67e50a73977d10c6 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,7 @@
       <module>analytics/implementation</module>
       <module>analytics/integrationtest</module>
       <module>analytics/northbound</module>
+      <module>l2agent</module>
     </modules>
 
     <repositories>