Do not catch Throwables, but rather Exceptions
[controller.git] / opendaylight / samples / simpleforwarding / src / main / java / org / opendaylight / controller / samples / simpleforwarding / internal / SimpleBroadcastHandlerImpl.java
1 /*
2  * Copyright (c) 2013 IBM and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.samples.simpleforwarding.internal;
10
11 import java.util.HashSet;
12 import java.util.Set;
13 import java.util.concurrent.locks.ReentrantReadWriteLock;
14
15 import org.opendaylight.controller.sal.packet.Ethernet;
16 import org.opendaylight.controller.sal.packet.IDataPacketService;
17 import org.opendaylight.controller.sal.packet.IListenDataPacket;
18 import org.opendaylight.controller.sal.core.ConstructionException;
19 import org.opendaylight.controller.sal.core.Node;
20 import org.opendaylight.controller.sal.core.NodeConnector;
21 import org.opendaylight.controller.sal.packet.Packet;
22 import org.opendaylight.controller.sal.packet.PacketResult;
23 import org.opendaylight.controller.sal.packet.RawPacket;
24 import org.opendaylight.controller.sal.utils.EtherTypes;
25 import org.opendaylight.controller.samples.simpleforwarding.IBroadcastHandler;
26 import org.opendaylight.controller.samples.simpleforwarding.IBroadcastPortSelector;
27 import org.opendaylight.controller.switchmanager.ISwitchManager;
28 import org.opendaylight.controller.topologymanager.ITopologyManager;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * The simple broadcast handler simply sends broadcast packets out all ports
34  * that are not known to belong to an internal, i.e., switch-switch, link. Note
35  * that this is *not* safe in the general case when an OpenDaylight-controlled
36  * network has L2 peering with normal a normal L2 network. It is entirely
37  * possible for a packet to be flooded to a legacy/non-controlled switch and
38  * then be reflected back into the OpenDaylight-controlled region resulting in a
39  * loop.
40  */
41 public class SimpleBroadcastHandlerImpl implements IBroadcastHandler, IListenDataPacket {
42
43     private static Logger log = LoggerFactory.getLogger(SimpleBroadcastHandlerImpl.class);
44     protected IDataPacketService dataPacketService = null;
45     protected ITopologyManager topoManager = null;
46     protected ISwitchManager swMgr = null;
47     protected IBroadcastPortSelector bcastPorts = null;
48
49     protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
50
51     BroadcastMode mode = BroadcastMode.DISABLED;
52
53     @Override
54     public PacketResult receiveDataPacket(RawPacket inPkt) {
55         /*
56          * note that this assumes that the protocol plugin will do appropriate
57          * filtering to ensure that this only receives packets for it's
58          * container.
59          */
60
61         if (mode == BroadcastMode.DISABLED) {
62             return PacketResult.IGNORED;
63         }
64
65         Packet decodedPkt = this.dataPacketService.decodeDataPacket(inPkt);
66         if (decodedPkt instanceof Ethernet) {
67             Ethernet eth = (Ethernet) decodedPkt;
68
69             // TODO: should we offer an option to not handle ARP since the
70             // ARPHandler already does that
71
72             // ignore LLDP
73             if (eth.getEtherType() != EtherTypes.LLDP.shortValue()) {
74
75                 if (eth.isBroadcast()) {
76                     broadcastPacket(inPkt);
77                 } else if (eth.isMulticast()) {
78                     // TODO: for now just treat multicast as broadcast
79                     broadcastPacket(inPkt);
80                 }
81             }
82         }
83
84         return PacketResult.KEEP_PROCESSING;
85     }
86
87     @Override
88     public boolean broadcastPacket(RawPacket pkt) {
89         Set<NodeConnector> toPacketOut = new HashSet<NodeConnector>();
90
91         // make sure that topoManager/datPacketService aren't pulled out from
92         // under us
93         lock.readLock().lock();
94         if (topoManager == null || dataPacketService == null
95             || swMgr == null) {
96             return false;
97         }
98
99         // find all non-internal NodeConnectors
100         switch (mode) {
101             case DISABLED:
102                 // intentionally blank; don't send the packet anywhere
103                 break;
104
105             case BROADCAST_TO_HOSTS:
106                 toPacketOut.addAll(topoManager.getNodeConnectorWithHost());
107                 break;
108
109             case BROADCAST_TO_NONINTERNAL:
110                 for (Node n : swMgr.getNodes()) {
111                     // getUpNodeConnectors will filter out NodeConnectors of type "SW"
112                     for (NodeConnector nc : swMgr.getUpNodeConnectors(n)) {
113                         if (!topoManager.isInternal(nc)) {
114                             toPacketOut.add(nc);
115                         }
116                     }
117                 }
118                 break;
119
120             case EXTERNAL_QUERY:
121                 if (bcastPorts != null) {
122                     toPacketOut.addAll(bcastPorts.getBroadcastPorts());
123                 } else {
124                     log.error("Mode set to "
125                               + BroadcastMode.EXTERNAL_QUERY
126                               + ", but no external source of broadcast ports was provided.");
127                     return false;
128                 }
129                 break;
130
131             default:
132                 log.error("Mode " + mode + " is not supported.");
133                 break;
134         }
135
136         // remove the NodeConnector it came in on
137         toPacketOut.remove(pkt.getIncomingNodeConnector());
138
139         // send it out all the node connectors
140         for (NodeConnector nc : toPacketOut) {
141             try {
142                 RawPacket toSend = new RawPacket(pkt);
143                 toSend.setOutgoingNodeConnector(nc);
144                 dataPacketService.transmitDataPacket(toSend);
145             } catch (ConstructionException e) {
146                 log.error("Could create packet: {}", e);
147             }
148         }
149
150         lock.readLock().unlock();
151
152         return true;
153     }
154
155     public void setDataPacketService(IDataPacketService s) {
156         // make sure dataPacketService doesn't change while we're in the middle
157         // of stuff
158         lock.writeLock().lock();
159         this.dataPacketService = s;
160         lock.writeLock().unlock();
161     }
162
163     public void unsetDataPacketService(IDataPacketService s) {
164         // make sure dataPacketService doesn't change while we're in the middle
165         // of stuff
166         lock.writeLock().lock();
167         if (this.dataPacketService == s) {
168             this.dataPacketService = null;
169         }
170         lock.writeLock().unlock();
171     }
172
173     public void setTopologyManager(ITopologyManager t) {
174         // make sure topoManager doesn't change while we're in the middle of
175         // stuff
176         lock.writeLock().lock();
177         this.topoManager = t;
178         lock.writeLock().unlock();
179     }
180
181     public void unsetTopologyManager(ITopologyManager t) {
182         // make sure topoManager doesn't change while we're in the middle of
183         // stuff
184         lock.writeLock().lock();
185         if (this.topoManager == t) {
186             this.topoManager = null;
187         }
188         lock.writeLock().unlock();
189     }
190
191     public void setSwitchManager(ISwitchManager i) {
192         lock.writeLock().lock();
193         this.swMgr = i;
194         lock.writeLock().unlock();
195     }
196
197     public void unsetSwitchManager(ISwitchManager i) {
198         lock.writeLock().lock();
199         if (this.swMgr == i) {
200             this.swMgr = null;
201         }
202         lock.writeLock().unlock();
203     }
204
205     public void setBroadcastPortSelector(IBroadcastPortSelector bps) {
206         lock.writeLock().lock();
207         bcastPorts = bps;
208         lock.writeLock().unlock();
209     }
210
211     public void unsetBroadcastPortSelector(IBroadcastPortSelector bps) {
212         lock.writeLock().lock();
213         if (bcastPorts == bps) {
214             this.bcastPorts = null;
215         }
216         lock.writeLock().unlock();
217     }
218
219     public void setMode(BroadcastMode m) {
220         lock.writeLock().lock();
221         mode = m;
222         lock.writeLock().unlock();
223     }
224
225 }