From 867026efeb7046076e7e0cf34b5ac2d18c54618b Mon Sep 17 00:00:00 2001 From: Colin Dixon Date: Mon, 10 Jun 2013 11:00:18 -0500 Subject: [PATCH] Adding a simple broadcast handler 1.) An interface IBroadcastHandler for enabling/disabling and controlling the mode of operation for a module that provides broadcast handling and a function to broadcast a packet. 2.) An implementation of that interface, SimpleBroadcastHandler, that both handles broadcast traffic received from the DataPacketService and provides a way to braodcast a synthetically-generated packet. There are four modes only two of which have currently been extensively tested: DISABLED and BROADCAST_TO_HOSTS. Change-Id: I6ab6042ad7ec08b819a8840e8518022c7805f4e2 Signed-off-by: Colin Dixon --- opendaylight/samples/simpleforwarding/pom.xml | 1 + .../simpleforwarding/IBroadcastHandler.java | 66 +++++ .../IBroadcastPortSelector.java | 17 ++ .../simpleforwarding/internal/Activator.java | 33 ++- .../internal/SimpleBroadcastHandlerImpl.java | 225 ++++++++++++++++++ 5 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastHandler.java create mode 100644 opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastPortSelector.java create mode 100644 opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java diff --git a/opendaylight/samples/simpleforwarding/pom.xml b/opendaylight/samples/simpleforwarding/pom.xml index 859248b755..edd146e615 100644 --- a/opendaylight/samples/simpleforwarding/pom.xml +++ b/opendaylight/samples/simpleforwarding/pom.xml @@ -37,6 +37,7 @@ org.opendaylight.controller.clustering.services, org.opendaylight.controller.sal.action, org.opendaylight.controller.sal.flowprogrammer, + org.opendaylight.controller.sal.inventory, org.opendaylight.controller.sal.match, org.opendaylight.controller.sal.packet, org.opendaylight.controller.sal.routing, diff --git a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastHandler.java b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastHandler.java new file mode 100644 index 0000000000..8140019622 --- /dev/null +++ b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastHandler.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 IBM 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.samples.simpleforwarding; + +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.packet.RawPacket; +import org.opendaylight.controller.topologymanager.ITopologyManager; + +/** + * Provides support for flooding/broadcasting of packets. + */ +public interface IBroadcastHandler { + + /** + * The mode to select which ports to broadcast a given packet. See the + * individual modes for the expected behavior. + */ + static enum BroadcastMode { + /** + * Turn off broadcast handling and ignore all received data packets. + */ + DISABLED, + + /** + * sends broadcast packets out ports where there are known hosts as + * discovered by {@link ITopologyManager#getNodeConnectorWithHost}. + */ + BROADCAST_TO_HOSTS, + + /** + * sends broadcast packets out all non-internal links as discovered by + * {@link ITopologyManager#isInternal}. Also ignores ports which have + * {@link NodeConnector#getType} of "SW" indicating OFPP_LOCAL. + */ + BROADCAST_TO_NONINTERNAL, + + /** + * sends broadcast packets out the ports specified by an external + * implementation of {@link IBroadcastPortSelector}. + */ + EXTERNAL_QUERY + }; + + /** + * Set the {@link BroadcastMode} for this {@link IBroadcastHandler}. + * @param m + */ + void setMode(BroadcastMode m); + + /** + * Safely flood/broadcast a {@link RawPacket} received on a given + * {@link NodeConnector}. + * + * @param pkt + * The packet to flood/broadcast + * @return true if the broadcast is successful, false + * otherwise + */ + boolean broadcastPacket(RawPacket pkt); +} diff --git a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastPortSelector.java b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastPortSelector.java new file mode 100644 index 0000000000..438c9214c6 --- /dev/null +++ b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/IBroadcastPortSelector.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013 IBM 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.samples.simpleforwarding; + +import java.util.Set; + +import org.opendaylight.controller.sal.core.NodeConnector; + +public interface IBroadcastPortSelector { + Set getBroadcastPorts(); +} diff --git a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/Activator.java b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/Activator.java index f3a38ed98f..1a71511ef5 100644 --- a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/Activator.java +++ b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/Activator.java @@ -9,6 +9,9 @@ package org.opendaylight.controller.samples.simpleforwarding.internal; +import java.util.Dictionary; +import java.util.Hashtable; + import org.apache.felix.dm.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,8 +21,12 @@ import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManage import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.IfNewHostNotify; import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; +import org.opendaylight.controller.sal.packet.IDataPacketService; +import org.opendaylight.controller.sal.packet.IListenDataPacket; import org.opendaylight.controller.sal.routing.IListenRoutingUpdates; import org.opendaylight.controller.sal.routing.IRouting; +import org.opendaylight.controller.samples.simpleforwarding.IBroadcastHandler; +import org.opendaylight.controller.samples.simpleforwarding.IBroadcastPortSelector; import org.opendaylight.controller.switchmanager.IInventoryListener; import org.opendaylight.controller.switchmanager.ISwitchManager; import org.opendaylight.controller.topologymanager.ITopologyManager; @@ -39,7 +46,8 @@ public class Activator extends ComponentActivatorAbstractBase { * Object */ public Object[] getImplementations() { - Object[] res = { SimpleForwardingImpl.class }; + Object[] res = { SimpleForwardingImpl.class, + SimpleBroadcastHandlerImpl.class }; return res; } @@ -88,6 +96,29 @@ public class Activator extends ComponentActivatorAbstractBase { c.add(createContainerServiceDependency(containerName).setService( IRouting.class).setCallbacks("setRouting", "unsetRouting") .setRequired(false)); + }else if (imp.equals(SimpleBroadcastHandlerImpl.class)) { + Dictionary props = new Hashtable(); + props.put("salListenerName", "simplebroadcasthandler"); + + // export the service + c.setInterface(new String[] { IBroadcastHandler.class.getName(), + IListenDataPacket.class.getName() }, props); + + c.add(createContainerServiceDependency(containerName).setService( + IDataPacketService.class).setCallbacks("setDataPacketService", + "unsetDataPacketService").setRequired(false)); + + c.add(createContainerServiceDependency(containerName).setService( + ITopologyManager.class).setCallbacks("setTopologyManager", + "unsetTopologyManager").setRequired(true)); + + c.add(createContainerServiceDependency(containerName).setService( + IBroadcastPortSelector.class).setCallbacks("setBroadcastPortSelector", + "unsetBroadcastPortSelector").setRequired(false)); + + c.add(createContainerServiceDependency(containerName).setService( + ISwitchManager.class).setCallbacks("setSwitchManager", + "unsetSwitchManager").setRequired(false)); } } } diff --git a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java new file mode 100644 index 0000000000..d2016b1f63 --- /dev/null +++ b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2013 IBM 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.samples.simpleforwarding.internal; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +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.core.ConstructionException; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.core.NodeConnector; +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.utils.EtherTypes; +import org.opendaylight.controller.samples.simpleforwarding.IBroadcastHandler; +import org.opendaylight.controller.samples.simpleforwarding.IBroadcastPortSelector; +import org.opendaylight.controller.switchmanager.ISwitchManager; +import org.opendaylight.controller.topologymanager.ITopologyManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The simple broadcast handler simply sends broadcast packets out all ports + * that are not known to belong to an internal, i.e., switch-switch, link. Note + * that this is *not* safe in the general case when an OpenDaylight-controlled + * network has L2 peering with normal a normal L2 network. It is entirely + * possible for a packet to be flooded to a legacy/non-controlled switch and + * then be reflected back into the OpenDaylight-controlled region resulting in a + * loop. + */ +public class SimpleBroadcastHandlerImpl implements IBroadcastHandler, IListenDataPacket { + + private static Logger log = LoggerFactory.getLogger(SimpleBroadcastHandlerImpl.class); + protected IDataPacketService dataPacketService = null; + protected ITopologyManager topoManager = null; + protected ISwitchManager swMgr = null; + protected IBroadcastPortSelector bcastPorts = null; + + protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + BroadcastMode mode = BroadcastMode.DISABLED; + + @Override + public PacketResult receiveDataPacket(RawPacket inPkt) { + /* + * note that this assumes that the protocol plugin will do appropriate + * filtering to ensure that this only receives packets for it's + * container. + */ + + if (mode == BroadcastMode.DISABLED) { + return PacketResult.IGNORED; + } + + Packet decodedPkt = this.dataPacketService.decodeDataPacket(inPkt); + if (decodedPkt instanceof Ethernet) { + Ethernet eth = (Ethernet) decodedPkt; + + // TODO: should we offer an option to not handle ARP since the + // ARPHandler already does that + + // ignore LLDP + if (eth.getEtherType() != EtherTypes.LLDP.shortValue()) { + + if (eth.isBroadcast()) { + broadcastPacket(inPkt); + } else if (eth.isMulticast()) { + // TODO: for now just treat multicast as broadcast + broadcastPacket(inPkt); + } + } + } + + return PacketResult.KEEP_PROCESSING; + } + + @Override + public boolean broadcastPacket(RawPacket pkt) { + Set toPacketOut = new HashSet(); + + // make sure that topoManager/datPacketService aren't pulled out from + // under us + lock.readLock().lock(); + if (topoManager == null || dataPacketService == null + || swMgr == null) { + return false; + } + + // find all non-internal NodeConnectors + switch (mode) { + case DISABLED: + // intentionally blank; don't send the packet anywhere + break; + + case BROADCAST_TO_HOSTS: + toPacketOut.addAll(topoManager.getNodeConnectorWithHost()); + break; + + case BROADCAST_TO_NONINTERNAL: + for (Node n : swMgr.getNodes()) { + // getUpNodeConnectors will filter out NodeConnectors of type "SW" + for (NodeConnector nc : swMgr.getUpNodeConnectors(n)) { + if (!topoManager.isInternal(nc)) { + toPacketOut.add(nc); + } + } + } + break; + + case EXTERNAL_QUERY: + if (bcastPorts != null) { + toPacketOut.addAll(bcastPorts.getBroadcastPorts()); + } else { + log.error("Mode set to " + + BroadcastMode.EXTERNAL_QUERY + + ", but no external source of broadcast ports was provided."); + return false; + } + break; + + default: + log.error("Mode " + mode + " is not supported."); + break; + } + + // remove the NodeConnector it came in on + toPacketOut.remove(pkt.getIncomingNodeConnector()); + + // send it out all the node connectors + for (NodeConnector nc : toPacketOut) { + try { + RawPacket toSend = new RawPacket(pkt); + toSend.setOutgoingNodeConnector(nc); + dataPacketService.transmitDataPacket(toSend); + } catch (ConstructionException e) { + log.error("Could create packet: {}", e); + } + } + + lock.readLock().unlock(); + + return true; + } + + public void setDataPacketService(IDataPacketService s) { + // make sure dataPacketService doesn't change while we're in the middle + // of stuff + lock.writeLock().lock(); + this.dataPacketService = s; + lock.writeLock().unlock(); + } + + public void unsetDataPacketService(IDataPacketService s) { + // make sure dataPacketService doesn't change while we're in the middle + // of stuff + lock.writeLock().lock(); + if (this.dataPacketService == s) { + this.dataPacketService = null; + } + lock.writeLock().unlock(); + } + + public void setTopologyManager(ITopologyManager t) { + // make sure topoManager doesn't change while we're in the middle of + // stuff + lock.writeLock().lock(); + this.topoManager = t; + lock.writeLock().unlock(); + } + + public void unsetTopologyManager(ITopologyManager t) { + // make sure topoManager doesn't change while we're in the middle of + // stuff + lock.writeLock().lock(); + if (this.topoManager == t) { + this.topoManager = null; + } + lock.writeLock().unlock(); + } + + public void setSwitchManager(ISwitchManager i) { + lock.writeLock().lock(); + this.swMgr = i; + lock.writeLock().unlock(); + } + + public void unsetSwitchManager(ISwitchManager i) { + lock.writeLock().lock(); + if (this.swMgr == i) { + this.swMgr = null; + } + lock.writeLock().unlock(); + } + + public void setBroadcastPortSelector(IBroadcastPortSelector bps) { + lock.writeLock().lock(); + bcastPorts = bps; + lock.writeLock().unlock(); + } + + public void unsetBroadcastPortSelector(IBroadcastPortSelector bps) { + lock.writeLock().lock(); + if (bcastPorts == bps) { + this.bcastPorts = null; + } + lock.writeLock().unlock(); + } + + public void setMode(BroadcastMode m) { + lock.writeLock().lock(); + mode = m; + lock.writeLock().unlock(); + } + +} -- 2.36.6