From 78ecb31812f3ddee9726d36c7455ba8b5bd6b5fd Mon Sep 17 00:00:00 2001 From: Suchi Raman Date: Thu, 26 Sep 2013 13:56:54 -0400 Subject: [PATCH] Add a simple l2agent for demo. Signed-off-by: Suchi Raman --- affinity/implementation/pom.xml | 6 +- .../affinity/affinity/internal/Activator.java | 4 +- .../internal/AffinityManagerImpl.java | 8 +- l2agent/pom.xml | 62 +++++ .../org/opendaylight/l2agent/Activator.java | 97 ++++++++ .../org/opendaylight/l2agent/L2Agent.java | 224 ++++++++++++++++++ .../org/opendaylight/l2agent/L2AgentTest.java | 29 +++ pom.xml | 1 + 8 files changed, 422 insertions(+), 9 deletions(-) create mode 100644 l2agent/pom.xml create mode 100644 l2agent/src/main/java/org/opendaylight/l2agent/Activator.java create mode 100644 l2agent/src/main/java/org/opendaylight/l2agent/L2Agent.java create mode 100644 l2agent/src/test/java/org/opendaylight/l2agent/L2AgentTest.java diff --git a/affinity/implementation/pom.xml b/affinity/implementation/pom.xml index 2abf5c6..84df90b 100644 --- a/affinity/implementation/pom.xml +++ b/affinity/implementation/pom.xml @@ -35,6 +35,7 @@ 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, @@ -124,8 +124,8 @@ 0.4.0-SNAPSHOT - org.opendaylight.controller - tutorial_L2_forwarding + org.opendaylight.affinity + l2agent 0.4.0-SNAPSHOT diff --git a/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/Activator.java b/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/Activator.java index 8d8fbec..98ec073 100644 --- a/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/Activator.java +++ b/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/Activator.java @@ -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( diff --git a/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/AffinityManagerImpl.java b/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/AffinityManagerImpl.java index 4a7799e..2e8ffbd 100644 --- a/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/AffinityManagerImpl.java +++ b/affinity/implementation/src/main/java/org/opendaylight/affinity/affinity/internal/AffinityManagerImpl.java @@ -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 affinityGroupList; private ConcurrentMap 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 index 0000000..339817f --- /dev/null +++ b/l2agent/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + + org.opendaylight.affinity + affinityParent + 0.4.1-SNAPSHOT + .. + + + l2agent + 0.4.0-SNAPSHOT + bundle + + + + + org.apache.felix + maven-bundle-plugin + 2.3.6 + true + + + + 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 + + + org.opendaylight.affinity.l2agent + + + org.opendaylight.affinity.l2agent.Activator + + + ${project.basedir}/META-INF + + + + + + + org.opendaylight.controller + switchmanager + 0.4.0-SNAPSHOT + + + org.opendaylight.controller + sal + 0.5.0-SNAPSHOT + + + 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 index 0000000..3ade6e7 --- /dev/null +++ b/l2agent/src/main/java/org/opendaylight/l2agent/Activator.java @@ -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 props = new Hashtable(); + 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 index 0000000..56c0041 --- /dev/null +++ b/l2agent/src/main/java/org/opendaylight/l2agent/L2Agent.java @@ -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 mac_to_port = new HashMap(); + 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 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 actions = new ArrayList(); + 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 index 0000000..d08c4e7 --- /dev/null +++ b/l2agent/src/test/java/org/opendaylight/l2agent/L2AgentTest.java @@ -0,0 +1,29 @@ + +/* + * 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 junit.framework.TestCase; + +import org.junit.Assert; +import org.junit.Test; + +public class L2AgentTest extends TestCase { + + @Test + public void testL2AgentCreation() { + + L2Agent ah = null; + ah = new L2Agent(); + Assert.assertTrue(ah != null); + + } + +} diff --git a/pom.xml b/pom.xml index 49d2c59..d2a42d1 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ analytics/implementation analytics/integrationtest analytics/northbound + l2agent -- 2.36.6