blob: ed575867411f046796f4c3d183a9c5c85f36f677 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
17
Jonathan Hart23701d12014-04-03 10:45:48 -070018package net.onrc.onos.core.linkdiscovery.internal;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080019
20import java.io.IOException;
21import java.net.InetAddress;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080022import java.net.NetworkInterface;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080023import java.nio.ByteBuffer;
24import java.util.ArrayList;
25import java.util.Collection;
26import java.util.Collections;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.Iterator;
30import java.util.List;
31import java.util.Map;
32import java.util.Map.Entry;
33import java.util.Set;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080034import java.util.concurrent.LinkedBlockingQueue;
35import java.util.concurrent.ScheduledExecutorService;
36import java.util.concurrent.TimeUnit;
37import java.util.concurrent.locks.ReentrantReadWriteLock;
38
39import net.floodlightcontroller.core.FloodlightContext;
40import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080041import net.floodlightcontroller.core.IOFMessageListener;
42import net.floodlightcontroller.core.IOFSwitch;
43import net.floodlightcontroller.core.IOFSwitchListener;
44import net.floodlightcontroller.core.annotations.LogMessageCategory;
45import net.floodlightcontroller.core.annotations.LogMessageDoc;
46import net.floodlightcontroller.core.annotations.LogMessageDocs;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070047import net.floodlightcontroller.core.internal.OFSwitchImpl;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080048import net.floodlightcontroller.core.module.FloodlightModuleContext;
49import net.floodlightcontroller.core.module.FloodlightModuleException;
50import net.floodlightcontroller.core.module.IFloodlightModule;
51import net.floodlightcontroller.core.module.IFloodlightService;
52import net.floodlightcontroller.core.util.SingletonTask;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080053import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080054import net.floodlightcontroller.threadpool.IThreadPoolService;
Jonathan Hart23701d12014-04-03 10:45:48 -070055import net.onrc.onos.core.linkdiscovery.ILinkDiscovery;
Jonathan Harta99ec672014-04-03 11:30:34 -070056import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
57import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.UpdateOperation;
Jonathan Hart23701d12014-04-03 10:45:48 -070058import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
59import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
60import net.onrc.onos.core.linkdiscovery.Link;
61import net.onrc.onos.core.linkdiscovery.LinkInfo;
62import net.onrc.onos.core.linkdiscovery.NodePortTuple;
Jonathan Hart23701d12014-04-03 10:45:48 -070063import net.onrc.onos.core.linkdiscovery.web.LinkDiscoveryWebRoutable;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070064import net.onrc.onos.core.main.IOnosRemoteSwitch;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070065import net.onrc.onos.core.packet.BSN;
66import net.onrc.onos.core.packet.Ethernet;
67import net.onrc.onos.core.packet.IPv4;
68import net.onrc.onos.core.packet.LLDP;
69import net.onrc.onos.core.packet.LLDPTLV;
70import net.onrc.onos.core.registry.IControllerRegistryService;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070071
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080072import org.openflow.protocol.OFMessage;
73import org.openflow.protocol.OFPacketIn;
74import org.openflow.protocol.OFPacketOut;
75import org.openflow.protocol.OFPhysicalPort;
76import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
77import org.openflow.protocol.OFPhysicalPort.OFPortState;
78import org.openflow.protocol.OFPort;
79import org.openflow.protocol.OFPortStatus;
80import org.openflow.protocol.OFPortStatus.OFPortReason;
81import org.openflow.protocol.OFType;
82import org.openflow.protocol.action.OFAction;
83import org.openflow.protocol.action.OFActionOutput;
84import org.openflow.util.HexString;
85import org.slf4j.Logger;
86import org.slf4j.LoggerFactory;
87
88/**
89 * This class sends out LLDP messages containing the sending switch's datapath
90 * id as well as the outgoing port number. Received LLrescDP messages that
91 * match a known switch cause a new LinkTuple to be created according to the
92 * invariant rules listed below. This new LinkTuple is also passed to routing
93 * if it exists to trigger updates.
Ray Milkey269ffb92014-04-03 14:43:30 -070094 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080095 * This class also handles removing links that are associated to switch ports
96 * that go down, and switches that are disconnected.
Ray Milkey269ffb92014-04-03 14:43:30 -070097 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080098 * Invariants:
Ray Milkey269ffb92014-04-03 14:43:30 -070099 * -portLinks and switchLinks will not contain empty Sets outside of
Ray Milkeyb41100a2014-04-10 10:42:15 -0700100 * critical sections.
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 * -portLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -0700102 * SwitchPortTuple matches the map key.
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 * -switchLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -0700104 * SwitchPortTuple's id matches the switch id.
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 * -Each LinkTuple will be indexed into switchLinks for both
Ray Milkeyb41100a2014-04-10 10:42:15 -0700106 * src.id and dst.id, and portLinks for each src and dst.
107 * -The updates queue is only added to from within a held write lock.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800108 */
109@LogMessageCategory("Network Topology")
110public class LinkDiscoveryManager
Ray Milkey269ffb92014-04-03 14:43:30 -0700111 implements IOFMessageListener, IOFSwitchListener,
112 ILinkDiscoveryService, IFloodlightModule {
113 protected IFloodlightProviderService controller;
Ray Milkeyec838942014-04-09 11:28:43 -0700114 private static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800115
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800116 protected IFloodlightProviderService floodlightProvider;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800117 protected IThreadPoolService threadPool;
118 protected IRestApiService restApi;
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700119 // Registry Service for ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700120 protected IControllerRegistryService registryService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800121
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700122
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800123 // LLDP and BDDP fields
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800124 private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800125 HexString.fromHexString("01:80:c2:00:00:0e");
Ray Milkey269ffb92014-04-03 14:43:30 -0700126 private static final long LINK_LOCAL_MASK = 0xfffffffffff0L;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800127 private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
128
129 // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
Masayoshi Kobayashi71137362013-07-12 15:54:52 -0700130 // private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01";
131 private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800132
133
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800134 // Direction TLVs are used to indicate if the LLDPs were sent
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800135 // periodically or in response to a recieved LLDP
136 private static final byte TLV_DIRECTION_TYPE = 0x73;
137 private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte
Ray Milkey45614c52014-04-07 16:30:54 -0700138 private static final byte[] TLV_DIRECTION_VALUE_FORWARD = {0x01};
139 private static final byte[] TLV_DIRECTION_VALUE_REVERSE = {0x02};
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700140 private static final LLDPTLV FORWARD_TLV
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 = new LLDPTLV().
142 setType(TLV_DIRECTION_TYPE).
143 setLength(TLV_DIRECTION_LENGTH).
144 setValue(TLV_DIRECTION_VALUE_FORWARD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800145
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700146 private static final LLDPTLV REVERSE_TLV
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 = new LLDPTLV().
148 setType(TLV_DIRECTION_TYPE).
149 setLength(TLV_DIRECTION_LENGTH).
150 setValue(TLV_DIRECTION_VALUE_REVERSE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800151
152 // Link discovery task details.
153 protected SingletonTask discoveryTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700154 protected static final int DISCOVERY_TASK_INTERVAL = 1;
155 protected static final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
156 protected static final int LLDP_TO_ALL_INTERVAL = 15; //original 15 seconds, aggressive 2 secs.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800157 protected long lldpClock = 0;
158 // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
159 // If we want to identify link failures faster, we could decrease this
160 // value to a small number, say 1 or 2 sec.
Ray Milkey2476cac2014-04-08 11:03:21 -0700161 protected static final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known links
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800162
163 protected LLDPTLV controllerTLV;
164 protected ReentrantReadWriteLock lock;
165 int lldpTimeCount = 0;
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700166
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800167 /**
168 * Flag to indicate if automatic port fast is enabled or not.
169 * Default is set to false -- Initialized in the init method as well.
170 */
171 boolean autoPortFastFeature = false;
172
173 /**
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800174 * Map of remote switches that are not connected to this controller. This
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700175 * is used to learn remote switches in a distributed controller ONOS.
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800176 */
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -0700177 protected Map<Long, IOnosRemoteSwitch> remoteSwitches;
HIGUCHI Yuta3d96f652013-06-17 12:07:48 -0700178
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800179 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700180 * Map from link to the most recent time it was verified functioning.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800181 */
182 protected Map<Link, LinkInfo> links;
183
184 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700185 * Map from switch id to a set of all links with it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800186 */
187 protected Map<Long, Set<Link>> switchLinks;
188
189 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700190 * Map from a id:port to the set of links containing it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800191 */
192 protected Map<NodePortTuple, Set<Link>> portLinks;
193
194 /**
195 * Set of link tuples over which multicast LLDPs are received
196 * and unicast LLDPs are not received.
197 */
198 protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
199
200 protected volatile boolean shuttingDown = false;
201
Ray Milkeyb41100a2014-04-10 10:42:15 -0700202 /**
203 * Topology aware components are called in the order they were added to the
204 * the array.
205 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800206 protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800207
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700208 protected class LinkUpdate extends LDUpdate {
209
Ray Milkey269ffb92014-04-03 14:43:30 -0700210 public LinkUpdate(LDUpdate old) {
211 super(old);
212 }
213
214 @LogMessageDoc(level = "ERROR",
215 message = "Error in link discovery updates loop",
216 explanation = "An unknown error occured while dispatching " +
217 "link update notifications",
218 recommendation = LogMessageDoc.GENERIC_ACTION)
219 @Override
220 public void dispatch() {
221 if (linkDiscoveryAware != null) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800222 if (log.isTraceEnabled()) {
223 log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 new Object[]{this.getOperation(),
225 HexString.toHexString(this.getSrc()), this.getSrcPort(),
226 HexString.toHexString(this.getDst()), this.getDstPort(),
227 linkDiscoveryAware});
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800228 }
229 try {
230 for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
231 lda.linkDiscoveryUpdate(this);
232 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 } catch (Exception e) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800234 log.error("Error in link discovery updates loop", e);
235 }
236 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 }
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700238 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800239
240 /**
241 * List of ports through which LLDP/BDDPs are not sent.
242 */
243 protected Set<NodePortTuple> suppressLinkDiscovery;
244
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 /**
246 * A list of ports that are quarantined for discovering links through
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800247 * them. Data traffic from these ports are not allowed until the ports
248 * are released from quarantine.
249 */
250 protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
251 protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
252 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700253 * Quarantine task.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800254 */
255 protected SingletonTask bddpTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700256 protected static final int BDDP_TASK_INTERVAL = 100; // 100 ms.
257 protected static final int BDDP_TASK_SIZE = 5; // # of ports per iteration
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800258
259 /**
260 * Map of broadcast domain ports and the last time a BDDP was either
261 * sent or received on that port.
262 */
263 protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap;
264
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800265 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800266 * Get the LLDP sending period in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800268 * @return LLDP sending period in seconds.
269 */
270 public int getLldpFrequency() {
271 return LLDP_TO_KNOWN_INTERVAL;
272 }
273
274 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700275 * Get the LLDP timeout value in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700276 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800277 * @return LLDP timeout value in seconds
278 */
279 public int getLldpTimeout() {
280 return LINK_TIMEOUT;
281 }
282
283 public Map<NodePortTuple, Set<Link>> getPortLinks() {
284 return portLinks;
285 }
286
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800287 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800288 public Set<NodePortTuple> getSuppressLLDPsInfo() {
289 return suppressLinkDiscovery;
290 }
291
292 /**
293 * Add a switch port to the suppressed LLDP list.
294 * Remove any known links on the switch port.
295 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800296 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700297 public void addToSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800298 NodePortTuple npt = new NodePortTuple(sw, port);
299 this.suppressLinkDiscovery.add(npt);
300 deleteLinksOnPort(npt, "LLDP suppressed.");
301 }
302
303 /**
304 * Remove a switch port from the suppressed LLDP list.
305 * Discover links on that switchport.
306 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800307 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700308 public void removeFromSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800309 NodePortTuple npt = new NodePortTuple(sw, port);
310 this.suppressLinkDiscovery.remove(npt);
311 discover(npt);
312 }
313
314 public boolean isShuttingDown() {
315 return shuttingDown;
316 }
317
318 public boolean isFastPort(long sw, short port) {
319 return false;
320 }
321
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800322 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800323 public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
324 if (info.getUnicastValidTime() != null) {
325 return ILinkDiscovery.LinkType.DIRECT_LINK;
326 } else if (info.getMulticastValidTime() != null) {
327 return ILinkDiscovery.LinkType.MULTIHOP_LINK;
328 }
329 return ILinkDiscovery.LinkType.INVALID_LINK;
330 }
331
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800332
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800333 private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
334 return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
335 }
336
337 protected void discoverLinks() {
338
339 // timeout known links.
340 timeoutLinks();
341
342 //increment LLDP clock
Ray Milkey269ffb92014-04-03 14:43:30 -0700343 lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800344
345 if (lldpClock == 0) {
346 log.debug("Sending LLDP out on all ports.");
347 discoverOnAllPorts();
348 }
349 }
350
351
352 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 * Quarantine Ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800354 */
355 protected class QuarantineWorker implements Runnable {
356 @Override
357 public void run() {
358 try {
359 processBDDPLists();
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 } catch (Exception e) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800361 log.error("Error in quarantine worker thread", e);
362 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700363 bddpTask.reschedule(BDDP_TASK_INTERVAL,
364 TimeUnit.MILLISECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800365 }
366 }
367 }
368
369 /**
370 * Add a switch port to the quarantine queue. Schedule the
371 * quarantine task if the quarantine queue was empty before adding
372 * this switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -0700373 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800374 * @param npt
375 */
376 protected void addToQuarantineQueue(NodePortTuple npt) {
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700377 if (!quarantineQueue.contains(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800378 quarantineQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700379 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800380 }
381
382 /**
383 * Remove a switch port from the quarantine queue.
384 */
385 protected void removeFromQuarantineQueue(NodePortTuple npt) {
386 // Remove all occurrences of the node port tuple from the list.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700387 boolean removedSomething;
388
389 do {
390 removedSomething = quarantineQueue.remove(npt);
391 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800392 }
393
394 /**
395 * Add a switch port to maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700396 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800397 * @param npt
398 */
399 protected void addToMaintenanceQueue(NodePortTuple npt) {
400 // TODO We are not checking if the switch port tuple is already
401 // in the maintenance list or not. This will be an issue for
402 // really large number of switch ports in the network.
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700403 if (!maintenanceQueue.contains(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800404 maintenanceQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700405 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800406 }
407
408 /**
409 * Remove a switch port from maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700410 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800411 * @param npt
412 */
413 protected void removeFromMaintenanceQueue(NodePortTuple npt) {
414 // Remove all occurrences of the node port tuple from the queue.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700415 boolean removedSomething;
416 do {
417 removedSomething = maintenanceQueue.remove(npt);
418 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800419 }
420
421 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700422 * This method processes the quarantine list in bursts. The task is
423 * at most once per BDDP_TASK_INTERVAL.
424 * One each call, BDDP_TASK_SIZE number of switch ports are processed.
425 * Once the BDDP packets are sent out through the switch ports, the ports
426 * are removed from the quarantine list.
427 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800428
429 protected void processBDDPLists() {
430 int count = 0;
431 Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
432
Ray Milkey269ffb92014-04-03 14:43:30 -0700433 while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800434 NodePortTuple npt;
435 npt = quarantineQueue.remove();
436 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
437 nptList.add(npt);
438 count++;
439 }
440
441 count = 0;
442 while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
443 NodePortTuple npt;
444 npt = maintenanceQueue.remove();
445 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
446 count++;
447 }
448
Ray Milkey269ffb92014-04-03 14:43:30 -0700449 for (NodePortTuple npt : nptList) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800450 generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
451 }
452 }
453
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800454 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800455 public Set<Short> getQuarantinedPorts(long sw) {
456 Set<Short> qPorts = new HashSet<Short>();
457
458 Iterator<NodePortTuple> iter = quarantineQueue.iterator();
459 while (iter.hasNext()) {
460 NodePortTuple npt = iter.next();
461 if (npt.getNodeId() == sw) {
462 qPorts.add(npt.getPortId());
463 }
464 }
465 return qPorts;
466 }
467
468 private void generateSwitchPortStatusUpdate(long sw, short port) {
469 UpdateOperation operation;
470
471 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700472 if (iofSwitch == null) {
473 return;
474 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800475
476 OFPhysicalPort ofp = iofSwitch.getPort(port);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700477 if (ofp == null) {
478 return;
479 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800480
481 int srcPortState = ofp.getState();
482 boolean portUp = ((srcPortState &
483 OFPortState.OFPPS_STP_MASK.getValue()) !=
484 OFPortState.OFPPS_STP_BLOCK.getValue());
485
Ray Milkeyb29e6262014-04-09 16:02:14 -0700486 if (portUp) {
487 operation = UpdateOperation.PORT_UP;
488 } else {
489 operation = UpdateOperation.PORT_DOWN;
490 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800491
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700492 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800493
494
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700495 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800496 }
497
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800498 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700499 * Send LLDP on known ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800500 */
501 protected void discoverOnKnownLinkPorts() {
502 // Copy the port set.
503 Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
504 nptSet.addAll(portLinks.keySet());
505
506 // Send LLDP from each of them.
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 for (NodePortTuple npt : nptSet) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800508 discover(npt);
509 }
510 }
511
512 protected void discover(NodePortTuple npt) {
513 discover(npt.getNodeId(), npt.getPortId());
514 }
515
516 protected void discover(long sw, short port) {
517 sendDiscoveryMessage(sw, port, true, false);
518 }
519
520 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700521 * Learn remote switches when running as a distributed controller ONOS.
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800522 */
523 protected IOFSwitch addRemoteSwitch(long sw, short port) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 IOnosRemoteSwitch remotesw = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800525
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 // add a switch if we have not seen it before
527 remotesw = remoteSwitches.get(sw);
Jonathan Harte7231052013-01-25 00:01:14 -0800528
Ray Milkey269ffb92014-04-03 14:43:30 -0700529 if (remotesw == null) {
530 remotesw = new OFSwitchImpl();
531 remotesw.setupRemoteSwitch(sw);
532 remoteSwitches.put(remotesw.getId(), remotesw);
533 log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800534 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800535
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800536 // add the port if we have not seen it before
Umesh Krishnaswamy68c118c2013-01-25 11:07:09 -0800537 if (remotesw.getPort(port) == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 OFPhysicalPort remoteport = new OFPhysicalPort();
539 remoteport.setPortNumber(port);
540 remoteport.setName("fake_" + port);
541 remoteport.setConfig(0);
542 remoteport.setState(0);
543 remotesw.setPort(remoteport);
544 log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw.getId());
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800545 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800546
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800547 return remotesw;
548 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800549
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800550 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800551 * Send link discovery message out of a given switch port.
552 * The discovery message may be a standard LLDP or a modified
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800553 * LLDP, where the dst mac address is set to :ff.
Ray Milkey269ffb92014-04-03 14:43:30 -0700554 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800555 * TODO: The modified LLDP will updated in the future and may
556 * use a different eth-type.
Ray Milkey269ffb92014-04-03 14:43:30 -0700557 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800558 * @param sw
559 * @param port
Ray Milkey269ffb92014-04-03 14:43:30 -0700560 * @param isStandard indicates standard or modified LLDP
561 * @param isReverse indicates whether the LLDP was sent as a response
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800562 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700563 @LogMessageDoc(level = "ERROR",
564 message = "Failure sending LLDP out port {port} on switch {switch}",
565 explanation = "An I/O error occured while sending LLDP message " +
566 "to the switch.",
567 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800568 protected void sendDiscoveryMessage(long sw, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700569 boolean isStandard,
570 boolean isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800571
572 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
573 if (iofSwitch == null) {
574 return;
575 }
576
Ray Milkeyb29e6262014-04-09 16:02:14 -0700577 if (port == OFPort.OFPP_LOCAL.getValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800578 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700579 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800580
581 OFPhysicalPort ofpPort = iofSwitch.getPort(port);
582
583 if (ofpPort == null) {
584 if (log.isTraceEnabled()) {
585 log.trace("Null physical port. sw={}, port={}", sw, port);
586 }
587 return;
588 }
589
590 if (isLinkDiscoverySuppressed(sw, port)) {
591 /* Dont send LLDPs out of this port as suppressLLDPs set
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800592 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800593 */
594 return;
595 }
596
597 // For fast ports, do not send forward LLDPs or BDDPs.
Ray Milkeyb29e6262014-04-09 16:02:14 -0700598 if (!isReverse && autoPortFastFeature && isFastPort(sw, port)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800599 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700600 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800601
602 if (log.isTraceEnabled()) {
603 log.trace("Sending LLDP packet out of swich: {}, port: {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700604 sw, port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800605 }
606
607 // using "nearest customer bridge" MAC address for broadest possible propagation
608 // through provider and TPMR bridges (see IEEE 802.1AB-2009 and 802.1Q-2011),
609 // in particular the Linux bridge which behaves mostly like a provider bridge
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 byte[] chassisId = new byte[]{4, 0, 0, 0, 0, 0, 0}; // filled in later
611 byte[] portId = new byte[]{2, 0, 0}; // filled in later
612 byte[] ttlValue = new byte[]{0, 0x78};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800613 // OpenFlow OUI - 00-26-E1
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 byte[] dpidTLVValue = new byte[]{0x0, 0x26, (byte) 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800615
616 byte[] dpidArray = new byte[8];
617 ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
618 ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
619
620 Long dpid = sw;
621 dpidBB.putLong(dpid);
622 // set the ethernet source mac to last 6 bytes of dpid
Jonathan Hart1f6c7a22014-04-16 16:06:27 -0700623 byte[] hardwareAddress = new byte[6];
624 System.arraycopy(dpidArray, 2, hardwareAddress, 0, 6);
625 ofpPort.setHardwareAddress(hardwareAddress);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800626 // set the chassis id's value to last 6 bytes of dpid
627 System.arraycopy(dpidArray, 2, chassisId, 1, 6);
628 // set the optional tlv to the full dpid
629 System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
Jonathan Hart1f6c7a22014-04-16 16:06:27 -0700630 LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127)
631 .setLength((short) dpidTLVValue.length).setValue(dpidTLVValue);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800632
633 // set the portId to the outgoing port
634 portBB.putShort(port);
635 if (log.isTraceEnabled()) {
636 log.trace("Sending LLDP out of interface: {}/{}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 HexString.toHexString(sw), port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800638 }
639
640 LLDP lldp = new LLDP();
641 lldp.setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) chassisId.length).setValue(chassisId));
642 lldp.setPortId(new LLDPTLV().setType((byte) 2).setLength((short) portId.length).setValue(portId));
643 lldp.setTtl(new LLDPTLV().setType((byte) 3).setLength((short) ttlValue.length).setValue(ttlValue));
644 lldp.getOptionalTLVList().add(dpidTLV);
645
646 // Add the controller identifier to the TLV value.
647 lldp.getOptionalTLVList().add(controllerTLV);
648 if (isReverse) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700649 lldp.getOptionalTLVList().add(REVERSE_TLV);
Ray Milkey269ffb92014-04-03 14:43:30 -0700650 } else {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700651 lldp.getOptionalTLVList().add(FORWARD_TLV);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800652 }
653
654 Ethernet ethernet;
655 if (isStandard) {
656 ethernet = new Ethernet()
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 .setSourceMACAddress(ofpPort.getHardwareAddress())
658 .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING)
659 .setEtherType(Ethernet.TYPE_LLDP);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800660 ethernet.setPayload(lldp);
661 } else {
662 BSN bsn = new BSN(BSN.BSN_TYPE_BDDP);
663 bsn.setPayload(lldp);
664
665 ethernet = new Ethernet()
Ray Milkey269ffb92014-04-03 14:43:30 -0700666 .setSourceMACAddress(ofpPort.getHardwareAddress())
667 .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING)
668 .setEtherType(Ethernet.TYPE_BSN);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800669 ethernet.setPayload(bsn);
670 }
671
672
673 // serialize and wrap in a packet out
674 byte[] data = ethernet.serialize();
675 OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
676 po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
677 po.setInPort(OFPort.OFPP_NONE);
678
679 // set actions
680 List<OFAction> actions = new ArrayList<OFAction>();
681 actions.add(new OFActionOutput(port, (short) 0));
682 po.setActions(actions);
683 po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
684
685 // set data
686 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + data.length);
687 po.setPacketData(data);
688
689 // send
690 try {
691 iofSwitch.write(po, null);
692 iofSwitch.flush();
693 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 log.error("Failure sending LLDP out port " + port + " on switch " + iofSwitch.getStringId(), e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800695 }
696
697 }
698
699 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700700 * Send LLDPs to all switch-ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800701 */
702 protected void discoverOnAllPorts() {
703 if (log.isTraceEnabled()) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800704 log.trace("Sending LLDP packets out of all the enabled ports on switch");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800705 }
706 Set<Long> switches = floodlightProvider.getSwitches().keySet();
707 // Send standard LLDPs
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 for (long sw : switches) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800709 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700710 if (iofSwitch == null) {
711 continue;
712 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800713 if (iofSwitch.getEnabledPorts() != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 for (OFPhysicalPort ofp : iofSwitch.getEnabledPorts()) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700715 if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800716 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700717 }
718 if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800719 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700720 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800721
722 // sends forward LLDP only non-fastports.
723 sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false);
724
725 // If the switch port is not alreayd in the maintenance
726 // queue, add it.
727 NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNumber());
728 addToMaintenanceQueue(npt);
729 }
730 }
731 }
732 }
733
734 protected void setControllerTLV() {
735 //Setting the controllerTLVValue based on current nano time,
736 //controller's IP address, and the network interface object hash
737 //the corresponding IP address.
738
739 final int prime = 7867;
740 InetAddress localIPAddress = null;
741 NetworkInterface localInterface = null;
742
Ray Milkey269ffb92014-04-03 14:43:30 -0700743 byte[] controllerTLVValue = new byte[]{0, 0, 0, 0, 0, 0, 0, 0}; // 8 byte value.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800744 ByteBuffer bb = ByteBuffer.allocate(10);
745
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 try {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800747 localIPAddress = java.net.InetAddress.getLocalHost();
748 localInterface = NetworkInterface.getByInetAddress(localIPAddress);
749 } catch (Exception e) {
750 e.printStackTrace();
751 }
752
753 long result = System.nanoTime();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700754 if (localIPAddress != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800755 result = result * prime + IPv4.toIPv4Address(localIPAddress.getHostAddress());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700756 }
757 if (localInterface != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800758 result = result * prime + localInterface.hashCode();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700759 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800760 // set the first 4 bits to 0.
761 result = result & (0x0fffffffffffffffL);
762
763 bb.putLong(result);
764
765 bb.rewind();
766 bb.get(controllerTLVValue, 0, 8);
767
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700768 this.controllerTLV = new LLDPTLV()
769 .setType((byte) 0x0c)
770 .setLength((short) controllerTLVValue.length)
771 .setValue(controllerTLVValue);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800772 }
773
774 @Override
775 public String getName() {
776 return "linkdiscovery";
777 }
778
779 @Override
780 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
781 switch (msg.getType()) {
782 case PACKET_IN:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700783 if (msg instanceof OFPacketIn) {
784 return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
785 cntx);
786 }
787 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800788 case PORT_STATUS:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700789 if (msg instanceof OFPortStatus) {
790 return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
791 }
792 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800793 default:
794 break;
795 }
796 return Command.CONTINUE;
797 }
798
799 private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) {
800 // If LLDP is suppressed on this port, ignore received packet as well
801 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
802 if (iofSwitch == null) {
803 return Command.STOP;
804 }
805
Ray Milkeyb29e6262014-04-09 16:02:14 -0700806 if (isLinkDiscoverySuppressed(sw, pi.getInPort())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800807 return Command.STOP;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700808 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800809
810 // If this is a malformed LLDP, or not from us, exit
Ray Milkeyb29e6262014-04-09 16:02:14 -0700811 if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800812 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700813 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800814
815 long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong();
816 long otherId = 0;
817 boolean myLLDP = false;
818 Boolean isReverse = null;
819
820 ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue());
821 portBB.position(1);
822
823 Short remotePort = portBB.getShort();
824 IOFSwitch remoteSwitch = null;
825
826 // Verify this LLDP packet matches what we're looking for
827 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
828 if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 &&
829 lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700830 lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800831 ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
832 remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800833 if (remoteSwitch == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 // Added by ONOS
835 // floodlight LLDP coming from a remote switch connected to a different controller
836 // add it to our cache of unconnected remote switches
837 remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800838 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800840 otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700841 if (myId == otherId) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800842 myLLDP = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700843 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800844 } else if (lldptlv.getType() == TLV_DIRECTION_TYPE &&
845 lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700846 if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800847 isReverse = false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700848 } else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800849 isReverse = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700850 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800851 }
852 }
853
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700854 if (!myLLDP) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800855 // This is not the LLDP sent by this controller.
856 // If the LLDP message has multicast bit set, then we need to broadcast
857 // the packet as a regular packet.
858 if (isStandard) {
859 if (log.isTraceEnabled()) {
860 log.trace("Getting standard LLDP from a different controller and quelching it.");
861 }
862 return Command.STOP;
Jonathan Hart121a0242014-06-06 15:53:42 -0700863 }
864 // XXX ONOS: Don't disregard any BDDP messages from other
865 // controllers because they're used for inter-instance link detection
866
867 /*else if (sw <= remoteSwitch.getId()) {
Teru Ub7246af2014-01-13 13:24:38 -0800868 if (log.isTraceEnabled()) {
869 log.trace("Getting BBDP from a different controller. myId {}: remoteId {}", myId, otherId);
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700870 log.trace("and my controller id is smaller than the other, so quelching it. myPort {}: rPort {}",
871 pi.getInPort(), remotePort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700872 }
873 //XXX ONOS: Fix the BDDP broadcast issue
874 //return Command.CONTINUE;
875 return Command.STOP;
Jonathan Hart121a0242014-06-06 15:53:42 -0700876 }*/
Teru Ub7246af2014-01-13 13:24:38 -0800877 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800878 else if (myId < otherId) {
879 if (log.isTraceEnabled()) {
880 log.trace("Getting BDDP packets from a different controller" +
881 "and letting it go through normal processing chain.");
882 }
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700883 //XXX ONOS: Fix the BDDP broadcast issue
Jonathan Hart0b2c76a2013-02-27 17:09:33 -0800884 //return Command.CONTINUE;
885 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800886 }
Teru Ub7246af2014-01-13 13:24:38 -0800887 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800888 }
889
890
891 if (remoteSwitch == null) {
892 // Ignore LLDPs not generated by Floodlight, or from a switch that has recently
893 // disconnected, or from a switch connected to another Floodlight instance
894 if (log.isTraceEnabled()) {
895 log.trace("Received LLDP from remote switch not connected to the controller");
896 }
897 return Command.STOP;
898 }
899
900 if (!remoteSwitch.portEnabled(remotePort)) {
901 if (log.isTraceEnabled()) {
902 log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
903 }
904 return Command.STOP;
905 }
906 if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 remotePort))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800908 if (log.isTraceEnabled()) {
909 log.trace("Ignoring link with suppressed src port: switch {} port {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700910 remoteSwitch, remotePort);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800911 }
912 return Command.STOP;
913 }
914 if (!iofSwitch.portEnabled(pi.getInPort())) {
915 if (log.isTraceEnabled()) {
916 log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
917 }
918 return Command.STOP;
919 }
920
921 OFPhysicalPort physicalPort = remoteSwitch.getPort(remotePort);
922 int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
923 physicalPort = iofSwitch.getPort(pi.getInPort());
924 int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
925
926 // Store the time of update to this link, and push it out to routingEngine
927 Link lt = new Link(remoteSwitch.getId(), remotePort, iofSwitch.getId(), pi.getInPort());
928
929
930 Long lastLldpTime = null;
931 Long lastBddpTime = null;
932
933 Long firstSeenTime = System.currentTimeMillis();
934
Ray Milkeyb29e6262014-04-09 16:02:14 -0700935 if (isStandard) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800936 lastLldpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700937 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800938 lastBddpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700939 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800940
941 LinkInfo newLinkInfo =
942 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700943 srcPortState, dstPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800944
945 addOrUpdateLink(lt, newLinkInfo);
946
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800947 // Check if reverse link exists.
948 // If it doesn't exist and if the forward link was seen
949 // first seen within a small interval, send probe on the
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800950 // reverse link.
951
952 newLinkInfo = links.get(lt);
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700953 if (newLinkInfo != null && isStandard && !isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800954 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700955 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800956 LinkInfo reverseInfo = links.get(reverseLink);
957 if (reverseInfo == null) {
958 // the reverse link does not exist.
959 if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) {
960 this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), isStandard, true);
961 }
962 }
963 }
964
Jonathan Hart121a0242014-06-06 15:53:42 -0700965 // XXX ONOS: Don't do this:
966 // If the received packet is a BDDP packet, then create a reverse BDDP
967 // link as well.
968 // We want to preserve our semantic of the instance that controls the
969 // destination switch is the one who adds the link to the database.
970 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800971 if (!isStandard) {
972 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700973 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800974
975 // srcPortState and dstPort state are reversed.
976 LinkInfo reverseInfo =
977 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700978 dstPortState, srcPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800979
980 addOrUpdateLink(reverseLink, reverseInfo);
981 }
Jonathan Hart121a0242014-06-06 15:53:42 -0700982 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800983
984 // Remove the node ports from the quarantine and maintenance queues.
985 NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
986 NodePortTuple nptDst = new NodePortTuple(lt.getDst(), lt.getDstPort());
987 removeFromQuarantineQueue(nptSrc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800988 removeFromQuarantineQueue(nptDst);
Jonathan Hart5337fb82014-06-11 17:31:50 -0700989
990 // XXX ONOS: Don't remove the port from the maintenance queue here
991 // because it sometimes prevents BDDPs from being sent and causes
992 // links to flap
993 // removeFromMaintenanceQueue(nptSrc);
994 // removeFromMaintenanceQueue(nptDst);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800995
996 // Consume this message
997 return Command.STOP;
998 }
999
1000 protected Command handlePacketIn(long sw, OFPacketIn pi,
1001 FloodlightContext cntx) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001002 Ethernet eth =
1003 IFloodlightProviderService.bcStore.get(cntx,
Ray Milkey269ffb92014-04-03 14:43:30 -07001004 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001005
Ray Milkey269ffb92014-04-03 14:43:30 -07001006 if (eth.getEtherType() == Ethernet.TYPE_BSN) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001007 BSN bsn = (BSN) eth.getPayload();
Ray Milkeyb29e6262014-04-09 16:02:14 -07001008 if (bsn == null) {
1009 return Command.STOP;
1010 }
1011 if (bsn.getPayload() == null) {
1012 return Command.STOP;
1013 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001014 // It could be a packet other than BSN LLDP, therefore
1015 // continue with the regular processing.
Ray Milkey6c4f2fe2014-04-11 09:47:23 -07001016 if (!(bsn.getPayload() instanceof LLDP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001017 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001018 }
Ubuntu9cbb4ca2013-02-07 17:19:59 +00001019 return handleLldp((LLDP) bsn.getPayload(), sw, pi, false, cntx);
Ray Milkey269ffb92014-04-03 14:43:30 -07001020 } else if (eth.getEtherType() == Ethernet.TYPE_LLDP) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001021 return handleLldp((LLDP) eth.getPayload(), sw, pi, true, cntx);
1022 } else if (eth.getEtherType() < 1500) {
1023 long destMac = eth.getDestinationMAC().toLong();
Ray Milkey269ffb92014-04-03 14:43:30 -07001024 if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001025 if (log.isTraceEnabled()) {
1026 log.trace("Ignoring packet addressed to 802.1D/Q " +
1027 "reserved address.");
1028 }
1029 return Command.STOP;
1030 }
1031 }
1032
1033 // If packet-in is from a quarantine port, stop processing.
1034 NodePortTuple npt = new NodePortTuple(sw, pi.getInPort());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001035 if (quarantineQueue.contains(npt)) {
1036 return Command.STOP;
1037 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001038
1039 return Command.CONTINUE;
1040 }
1041
1042 protected UpdateOperation getUpdateOperation(int srcPortState,
1043 int dstPortState) {
1044 boolean added =
1045 (((srcPortState &
Ray Milkey269ffb92014-04-03 14:43:30 -07001046 OFPortState.OFPPS_STP_MASK.getValue()) !=
1047 OFPortState.OFPPS_STP_BLOCK.getValue()) &&
1048 ((dstPortState &
1049 OFPortState.OFPPS_STP_MASK.getValue()) !=
1050 OFPortState.OFPPS_STP_BLOCK.getValue()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001051
Ray Milkeyb29e6262014-04-09 16:02:14 -07001052 if (added) {
1053 return UpdateOperation.LINK_UPDATED;
1054 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001055 return UpdateOperation.LINK_REMOVED;
1056 }
1057
1058
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001059 protected UpdateOperation getUpdateOperation(int srcPortState) {
1060 boolean portUp = ((srcPortState &
1061 OFPortState.OFPPS_STP_MASK.getValue()) !=
1062 OFPortState.OFPPS_STP_BLOCK.getValue());
1063
Ray Milkeyb29e6262014-04-09 16:02:14 -07001064 if (portUp) {
1065 return UpdateOperation.PORT_UP;
1066 } else {
1067 return UpdateOperation.PORT_DOWN;
1068 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001069 }
1070
1071 protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
1072
1073 NodePortTuple srcNpt, dstNpt;
1074 boolean linkChanged = false;
1075
1076 lock.writeLock().lock();
1077 try {
1078 // put the new info. if an old info exists, it will be returned.
1079 LinkInfo oldInfo = links.put(lt, newInfo);
1080 if (oldInfo != null &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001081 oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001082 newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001083 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001084
1085 if (log.isTraceEnabled()) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001086 log.trace("addOrUpdateLink: {} {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001087 lt,
1088 (newInfo.getMulticastValidTime() != null) ? "multicast" : "unicast");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001089 }
1090
1091 UpdateOperation updateOperation = null;
1092 linkChanged = false;
1093
1094 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1095 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1096
1097 if (oldInfo == null) {
1098 // index it by switch source
Ray Milkeyb29e6262014-04-09 16:02:14 -07001099 if (!switchLinks.containsKey(lt.getSrc())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001100 switchLinks.put(lt.getSrc(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001101 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001102 switchLinks.get(lt.getSrc()).add(lt);
1103
1104 // index it by switch dest
Ray Milkeyb29e6262014-04-09 16:02:14 -07001105 if (!switchLinks.containsKey(lt.getDst())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001106 switchLinks.put(lt.getDst(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001107 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001108 switchLinks.get(lt.getDst()).add(lt);
1109
1110 // index both ends by switch:port
Ray Milkeyb29e6262014-04-09 16:02:14 -07001111 if (!portLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001112 portLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001113 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001114 portLinks.get(srcNpt).add(lt);
1115
Ray Milkeyb29e6262014-04-09 16:02:14 -07001116 if (!portLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001117 portLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001118 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001119 portLinks.get(dstNpt).add(lt);
1120
1121 // Add to portNOFLinks if the unicast valid time is null
Ray Milkeyb29e6262014-04-09 16:02:14 -07001122 if (newInfo.getUnicastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001123 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001124 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001125
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001126 // ONOS: Distinguish added event separately from updated event
Pankaj Berdea41016d2013-06-10 21:18:18 -07001127 updateOperation = UpdateOperation.LINK_ADDED;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001128 linkChanged = true;
1129
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001130 } else {
1131 // Since the link info is already there, we need to
1132 // update the right fields.
1133 if (newInfo.getUnicastValidTime() == null) {
1134 // This is due to a multicast LLDP, so copy the old unicast
1135 // value.
1136 if (oldInfo.getUnicastValidTime() != null) {
1137 newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
1138 }
1139 } else if (newInfo.getMulticastValidTime() == null) {
1140 // This is due to a unicast LLDP, so copy the old multicast
1141 // value.
1142 if (oldInfo.getMulticastValidTime() != null) {
1143 newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
1144 }
1145 }
1146
1147 Long oldTime = oldInfo.getUnicastValidTime();
1148 Long newTime = newInfo.getUnicastValidTime();
1149 // the link has changed its state between openflow and non-openflow
1150 // if the unicastValidTimes are null or not null
1151 if (oldTime != null & newTime == null) {
1152 // openflow -> non-openflow transition
1153 // we need to add the link tuple to the portNOFLinks
1154 addLinkToBroadcastDomain(lt);
1155 linkChanged = true;
1156 } else if (oldTime == null & newTime != null) {
1157 // non-openflow -> openflow transition
1158 // we need to remove the link from the portNOFLinks
1159 removeLinkFromBroadcastDomain(lt);
1160 linkChanged = true;
1161 }
1162
1163 // Only update the port states if they've changed
1164 if (newInfo.getSrcPortState().intValue() !=
1165 oldInfo.getSrcPortState().intValue() ||
1166 newInfo.getDstPortState().intValue() !=
Ray Milkeyb29e6262014-04-09 16:02:14 -07001167 oldInfo.getDstPortState().intValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001168 linkChanged = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001169 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001170
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001171 if (linkChanged) {
1172 updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001173 newInfo.getDstPortState());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001174 if (log.isTraceEnabled()) {
1175 log.trace("Updated link {}", lt);
1176 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001177 }
1178 }
1179
1180 if (linkChanged) {
1181 // find out if the link was added or removed here.
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001182 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001183 lt.getDst(), lt.getDstPort(),
1184 getLinkType(lt, newInfo),
1185 updateOperation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001186 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001187 }
1188 } finally {
1189 lock.writeLock().unlock();
1190 }
1191
1192 return linkChanged;
1193 }
1194
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001195 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001196 public Map<Long, Set<Link>> getSwitchLinks() {
1197 return this.switchLinks;
1198 }
1199
1200 /**
1201 * Removes links from memory and storage.
Ray Milkey269ffb92014-04-03 14:43:30 -07001202 *
Ray Milkey5df613b2014-04-15 10:50:56 -07001203 * @param linksToDelete The List of @LinkTuple to delete.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001204 */
Ray Milkey5df613b2014-04-15 10:50:56 -07001205 protected void deleteLinks(List<Link> linksToDelete, String reason) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001206 NodePortTuple srcNpt, dstNpt;
1207
1208 lock.writeLock().lock();
1209 try {
Ray Milkey5df613b2014-04-15 10:50:56 -07001210 for (Link lt : linksToDelete) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001211 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001213
1214 switchLinks.get(lt.getSrc()).remove(lt);
1215 switchLinks.get(lt.getDst()).remove(lt);
1216 if (switchLinks.containsKey(lt.getSrc()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001217 switchLinks.get(lt.getSrc()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001218 this.switchLinks.remove(lt.getSrc());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001219 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001220 if (this.switchLinks.containsKey(lt.getDst()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001221 this.switchLinks.get(lt.getDst()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001222 this.switchLinks.remove(lt.getDst());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001223 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001224
1225 if (this.portLinks.get(srcNpt) != null) {
1226 this.portLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001227 if (this.portLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001228 this.portLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001229 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001230 }
1231 if (this.portLinks.get(dstNpt) != null) {
1232 this.portLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001233 if (this.portLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001234 this.portLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001235 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001236 }
1237
1238 LinkInfo info = this.links.remove(lt);
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001239 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001240 lt.getDst(), lt.getDstPort(),
1241 getLinkType(lt, info),
1242 UpdateOperation.LINK_REMOVED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001243 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001244
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001245 // TODO Whenever link is removed, it has to checked if
1246 // the switchports must be added to quarantine.
1247
1248 if (log.isTraceEnabled()) {
1249 log.trace("Deleted link {}", lt);
1250 }
1251 }
1252 } finally {
1253 lock.writeLock().unlock();
1254 }
1255 }
1256
1257 /**
1258 * Handles an OFPortStatus message from a switch. We will add or
1259 * delete LinkTupes as well re-compute the topology if needed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001260 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001261 * @param sw The IOFSwitch that sent the port status message
1262 * @param ps The OFPortStatus message
1263 * @return The Command to continue or stop after we process this message
1264 */
1265 protected Command handlePortStatus(long sw, OFPortStatus ps) {
1266
1267 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001268 if (iofSwitch == null) {
1269 return Command.CONTINUE;
1270 }
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001271
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001272 // ONOS: If we do not control this switch, then we should not process its port status messages
Ray Milkeyb29e6262014-04-09 16:02:14 -07001273 if (!registryService.hasControl(iofSwitch.getId())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001274 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001275 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001276
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001277 if (log.isTraceEnabled()) {
1278 log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
1279 "config is {} state is {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001280 new Object[]{iofSwitch.getStringId(),
1281 ps.getDesc().getPortNumber(),
1282 ps.getReason(),
1283 ps.getDesc().getConfig(),
1284 ps.getDesc().getState()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001285 }
1286
1287 short port = ps.getDesc().getPortNumber();
1288 NodePortTuple npt = new NodePortTuple(sw, port);
Ray Milkey269ffb92014-04-03 14:43:30 -07001289 boolean linkDeleted = false;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001290 boolean linkInfoChanged = false;
1291
1292 lock.writeLock().lock();
1293 try {
1294 // if ps is a delete, or a modify where the port is down or
1295 // configured down
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 if ((byte) OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
1297 ((byte) OFPortReason.OFPPR_MODIFY.ordinal() ==
1298 ps.getReason() && !portEnabled(ps.getDesc()))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001299 deleteLinksOnPort(npt, "Port Status Changed");
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001300 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, UpdateOperation.PORT_DOWN));
1301 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001302 linkDeleted = true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001303 } else if (ps.getReason() ==
1304 (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001305 // If ps is a port modification and the port state has changed
1306 // that affects links in the topology
1307
1308 if (this.portLinks.containsKey(npt)) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001309 for (Link lt : this.portLinks.get(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001310 LinkInfo linkInfo = links.get(lt);
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 assert (linkInfo != null);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001312 Integer updatedSrcPortState = null;
1313 Integer updatedDstPortState = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001314 if (lt.getSrc() == npt.getNodeId() &&
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001315 lt.getSrcPort() == npt.getPortId() &&
1316 (linkInfo.getSrcPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001317 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001318 updatedSrcPortState = ps.getDesc().getState();
1319 linkInfo.setSrcPortState(updatedSrcPortState);
1320 }
1321 if (lt.getDst() == npt.getNodeId() &&
1322 lt.getDstPort() == npt.getPortId() &&
1323 (linkInfo.getDstPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001324 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001325 updatedDstPortState = ps.getDesc().getState();
1326 linkInfo.setDstPortState(updatedDstPortState);
1327 }
1328 if ((updatedSrcPortState != null) ||
1329 (updatedDstPortState != null)) {
1330 // The link is already known to link discovery
1331 // manager and the status has changed, therefore
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001332 // send an LinkUpdate.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001333 UpdateOperation operation =
1334 getUpdateOperation(linkInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001335 linkInfo.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001336 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001337 lt.getDst(), lt.getDstPort(),
1338 getLinkType(lt, linkInfo),
1339 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001340 controller.publishUpdate(update);
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001341
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001342 linkInfoChanged = true;
1343 }
1344 }
1345 }
1346
1347 UpdateOperation operation =
1348 getUpdateOperation(ps.getDesc().getState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001349 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
1350 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001351 }
1352
Ray Milkey269ffb92014-04-03 14:43:30 -07001353 if (!linkDeleted && !linkInfoChanged) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001354 if (log.isTraceEnabled()) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001355 log.trace("handlePortStatus: Switch {} port #{} reason {};" +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001356 " no links to update/remove",
Ray Milkey269ffb92014-04-03 14:43:30 -07001357 new Object[]{HexString.toHexString(sw),
1358 ps.getDesc().getPortNumber(),
1359 ps.getReason()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001360 }
1361 }
1362 } finally {
1363 lock.writeLock().unlock();
1364 }
1365
1366 if (!linkDeleted) {
1367 // Send LLDP right away when port state is changed for faster
1368 // cluster-merge. If it is a link delete then there is not need
1369 // to send the LLDPs right away and instead we wait for the LLDPs
1370 // to be sent on the timer as it is normally done
1371 // do it outside the write-lock
1372 // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
1373 processNewPort(npt.getNodeId(), npt.getPortId());
1374 }
1375 return Command.CONTINUE;
1376 }
1377
1378 /**
1379 * Process a new port.
1380 * If link discovery is disabled on the port, then do nothing.
1381 * If autoportfast feature is enabled and the port is a fast port, then
1382 * do nothing.
1383 * Otherwise, send LLDP message. Add the port to quarantine.
Ray Milkey269ffb92014-04-03 14:43:30 -07001384 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001385 * @param sw
1386 * @param p
1387 */
1388 private void processNewPort(long sw, short p) {
1389 if (isLinkDiscoverySuppressed(sw, p)) {
1390 // Do nothing as link discovery is suppressed.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001391 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001392 } else if (autoPortFastFeature && isFastPort(sw, p)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001393 // Do nothing as the port is a fast port.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001394 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001395 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001396 NodePortTuple npt = new NodePortTuple(sw, p);
1397 discover(sw, p);
1398 // if it is not a fast port, add it to quarantine.
1399 if (!isFastPort(sw, p)) {
1400 addToQuarantineQueue(npt);
1401 } else {
1402 // Add to maintenance queue to ensure that BDDP packets
1403 // are sent out.
1404 addToMaintenanceQueue(npt);
1405 }
1406 }
1407 }
1408
1409 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001410 * We send out LLDP messages when a switch is added to discover the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001411 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001412 * @param sw The IOFSwitch that connected to the controller
1413 */
1414 @Override
1415 public void addedSwitch(IOFSwitch sw) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001416 if (sw.getEnabledPorts() != null) {
1417 for (Short p : sw.getEnabledPortNumbers()) {
1418 processNewPort(sw.getId(), p);
1419 }
1420 }
Jonathan Hart6d208022014-06-24 18:56:36 -07001421
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001422 LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), null,
Ray Milkey269ffb92014-04-03 14:43:30 -07001423 UpdateOperation.SWITCH_UPDATED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001424 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001425 }
1426
1427 /**
1428 * When a switch disconnects we remove any links from our map and notify.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001429 */
1430 @Override
1431 public void removedSwitch(IOFSwitch iofSwitch) {
1432 // Update event history
1433 long sw = iofSwitch.getId();
Jonathan Hart6d208022014-06-24 18:56:36 -07001434
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001435 List<Link> eraseList = new ArrayList<Link>();
1436 lock.writeLock().lock();
1437 try {
1438 if (switchLinks.containsKey(sw)) {
1439 if (log.isTraceEnabled()) {
1440 log.trace("Handle switchRemoved. Switch {}; removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001441 HexString.toHexString(sw), switchLinks.get(sw));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001442 }
1443 // add all tuples with an endpoint on this switch to erase list
1444 eraseList.addAll(switchLinks.get(sw));
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001445 deleteLinks(eraseList, "Switch Removed");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001446
1447 // Send a switch removed update
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001448 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED));
1449 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001450 }
1451 } finally {
1452 lock.writeLock().unlock();
1453 }
1454 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001455
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001456 /**
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001457 * We don't react the port changed notifications here. we listen for
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001458 * OFPortStatus messages directly. Might consider using this notifier
1459 * instead
1460 */
1461 @Override
1462 public void switchPortChanged(Long switchId) {
1463 // no-op
1464 }
1465
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001466 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001467 * Delete links incident on a given switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -07001468 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001469 * @param npt
1470 * @param reason
1471 */
1472 protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
1473 List<Link> eraseList = new ArrayList<Link>();
1474 if (this.portLinks.containsKey(npt)) {
1475 if (log.isTraceEnabled()) {
1476 log.trace("handlePortStatus: Switch {} port #{} " +
1477 "removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001478 new Object[]{HexString.toHexString(npt.getNodeId()),
1479 npt.getPortId(),
1480 this.portLinks.get(npt)});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001481 }
1482 eraseList.addAll(this.portLinks.get(npt));
1483 deleteLinks(eraseList, reason);
1484 }
1485 }
1486
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001487 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001488 * Iterates through the list of links and deletes if the
1489 * last discovery message reception time exceeds timeout values.
1490 */
1491 protected void timeoutLinks() {
1492 List<Link> eraseList = new ArrayList<Link>();
1493 Long curTime = System.currentTimeMillis();
1494 boolean linkChanged = false;
1495
1496 // reentrant required here because deleteLink also write locks
1497 lock.writeLock().lock();
1498 try {
1499 Iterator<Entry<Link, LinkInfo>> it =
1500 this.links.entrySet().iterator();
1501 while (it.hasNext()) {
1502 Entry<Link, LinkInfo> entry = it.next();
1503 Link lt = entry.getKey();
1504 LinkInfo info = entry.getValue();
1505
1506 // Timeout the unicast and multicast LLDP valid times
1507 // independently.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001508 if ((info.getUnicastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001509 (info.getUnicastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001510 info.setUnicastValidTime(null);
1511
Ray Milkeyb29e6262014-04-09 16:02:14 -07001512 if (info.getMulticastValidTime() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001513 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001514 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001515 // Note that even if mTime becomes null later on,
1516 // the link would be deleted, which would trigger updateClusters().
1517 linkChanged = true;
1518 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001519 if ((info.getMulticastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001520 (info.getMulticastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001521 info.setMulticastValidTime(null);
1522 // if uTime is not null, then link will remain as openflow
1523 // link. If uTime is null, it will be deleted. So, we
1524 // don't care about linkChanged flag here.
1525 removeLinkFromBroadcastDomain(lt);
1526 linkChanged = true;
1527 }
1528 // Add to the erase list only if the unicast
1529 // time is null.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001530 if (info.getUnicastValidTime() == null &&
Ray Milkey269ffb92014-04-03 14:43:30 -07001531 info.getMulticastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001532 eraseList.add(entry.getKey());
1533 } else if (linkChanged) {
1534 UpdateOperation operation;
1535 operation = getUpdateOperation(info.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001536 info.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001537 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001538 lt.getDst(), lt.getDstPort(),
1539 getLinkType(lt, info),
1540 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001541 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001542 }
1543 }
1544
1545 // if any link was deleted or any link was changed.
1546 if ((eraseList.size() > 0) || linkChanged) {
1547 deleteLinks(eraseList, "LLDP timeout");
1548 }
1549 } finally {
1550 lock.writeLock().unlock();
1551 }
1552 }
1553
1554 private boolean portEnabled(OFPhysicalPort port) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001555 if (port == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001556 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001557 }
1558 if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001559 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001560 }
1561 if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001562 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001563 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001564 // Port STP state doesn't work with multiple VLANs, so ignore it for now
1565 // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
1566 // return false;
1567 return true;
1568 }
1569
1570 public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
1571 return portBroadcastDomainLinks;
1572 }
1573
1574 @Override
1575 public Map<Link, LinkInfo> getLinks() {
1576 lock.readLock().lock();
1577 Map<Link, LinkInfo> result;
1578 try {
1579 result = new HashMap<Link, LinkInfo>(links);
1580 } finally {
1581 lock.readLock().unlock();
1582 }
1583 return result;
1584 }
1585
1586 protected void addLinkToBroadcastDomain(Link lt) {
1587
1588 NodePortTuple srcNpt, dstNpt;
1589 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1590 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1591
Ray Milkeyb29e6262014-04-09 16:02:14 -07001592 if (!portBroadcastDomainLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001593 portBroadcastDomainLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001594 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001595 portBroadcastDomainLinks.get(srcNpt).add(lt);
1596
Ray Milkeyb29e6262014-04-09 16:02:14 -07001597 if (!portBroadcastDomainLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001598 portBroadcastDomainLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001599 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001600 portBroadcastDomainLinks.get(dstNpt).add(lt);
1601 }
1602
1603 protected void removeLinkFromBroadcastDomain(Link lt) {
1604
1605 NodePortTuple srcNpt, dstNpt;
1606 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1607 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1608
1609 if (portBroadcastDomainLinks.containsKey(srcNpt)) {
1610 portBroadcastDomainLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001611 if (portBroadcastDomainLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001612 portBroadcastDomainLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001613 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001614 }
1615
1616 if (portBroadcastDomainLinks.containsKey(dstNpt)) {
1617 portBroadcastDomainLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001618 if (portBroadcastDomainLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001619 portBroadcastDomainLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001620 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001621 }
1622 }
1623
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001624 @Override
1625 public void addListener(ILinkDiscoveryListener listener) {
1626 linkDiscoveryAware.add(listener);
1627 }
1628
1629 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001630 * Register a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001631 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001632 * @param linkDiscoveryAwareComponent
1633 */
1634 public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1635 // TODO make this a copy on write set or lock it somehow
1636 this.linkDiscoveryAware.add(linkDiscoveryAwareComponent);
1637 }
1638
1639 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001640 * Deregister a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001641 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001642 * @param linkDiscoveryAwareComponent
1643 */
1644 public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1645 // TODO make this a copy on write set or lock it somehow
1646 this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent);
1647 }
1648
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001649 @Override
1650 public boolean isCallbackOrderingPrereq(OFType type, String name) {
1651 return false;
1652 }
1653
1654 @Override
1655 public boolean isCallbackOrderingPostreq(OFType type, String name) {
1656 return false;
1657 }
1658
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001659 // IFloodlightModule classes
1660
1661 @Override
1662 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001663 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001664 new ArrayList<Class<? extends IFloodlightService>>();
1665 l.add(ILinkDiscoveryService.class);
1666 //l.add(ITopologyService.class);
1667 return l;
1668 }
1669
1670 @Override
1671 public Map<Class<? extends IFloodlightService>, IFloodlightService>
1672 getServiceImpls() {
1673 Map<Class<? extends IFloodlightService>,
Ray Milkey269ffb92014-04-03 14:43:30 -07001674 IFloodlightService> m =
1675 new HashMap<Class<? extends IFloodlightService>,
1676 IFloodlightService>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001677 // We are the class that implements the service
1678 m.put(ILinkDiscoveryService.class, this);
1679 return m;
1680 }
1681
1682 @Override
1683 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001684 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001685 new ArrayList<Class<? extends IFloodlightService>>();
1686 l.add(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001687 l.add(IThreadPoolService.class);
1688 l.add(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001689 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001690 l.add(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001691 return l;
1692 }
1693
1694 @Override
1695 public void init(FloodlightModuleContext context)
1696 throws FloodlightModuleException {
1697 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001698 threadPool = context.getServiceImpl(IThreadPoolService.class);
1699 restApi = context.getServiceImpl(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001700 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001701 registryService = context.getServiceImpl(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001702
1703 // Set the autoportfast feature to false.
1704 this.autoPortFastFeature = false;
1705
1706 // We create this here because there is no ordering guarantee
1707 this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
1708 this.lock = new ReentrantReadWriteLock();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001709 this.links = new HashMap<Link, LinkInfo>();
1710 this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
1711 this.suppressLinkDiscovery =
1712 Collections.synchronizedSet(new HashSet<NodePortTuple>());
1713 this.portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
1714 this.switchLinks = new HashMap<Long, Set<Link>>();
1715 this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
1716 this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001717 // Added by ONOS
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -07001718 this.remoteSwitches = new HashMap<Long, IOnosRemoteSwitch>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001719 }
1720
1721 @Override
1722 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001723 @LogMessageDoc(level = "ERROR",
1724 message = "No storage source found.",
1725 explanation = "Storage source was not initialized; cannot initialize " +
1726 "link discovery.",
1727 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1728 @LogMessageDoc(level = "ERROR",
1729 message = "Error in installing listener for " +
1730 "switch config table {table}",
1731 explanation = "Failed to install storage notification for the " +
1732 "switch config table",
1733 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1734 @LogMessageDoc(level = "ERROR",
1735 message = "No storage source found.",
1736 explanation = "Storage source was not initialized; cannot initialize " +
1737 "link discovery.",
1738 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1739 @LogMessageDoc(level = "ERROR",
1740 message = "Exception in LLDP send timer.",
1741 explanation = "An unknown error occured while sending LLDP " +
1742 "messages to switches.",
1743 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001744 })
1745 public void startUp(FloodlightModuleContext context) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001746 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001747 controller =
1748 context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001749
1750 // To be started by the first switch connection
1751 discoveryTask = new SingletonTask(ses, new Runnable() {
1752 @Override
1753 public void run() {
1754 try {
1755 discoverLinks();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001756 } catch (Exception e) {
1757 log.error("Exception in LLDP send timer.", e);
1758 } finally {
1759 if (!shuttingDown) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001760 // Always reschedule link discovery if we're not
1761 // shutting down (no chance of SLAVE role now)
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001762 log.trace("Rescheduling discovery task");
1763 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
Ray Milkey269ffb92014-04-03 14:43:30 -07001764 TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001765 }
1766 }
1767 }
1768 });
1769
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001770 // Always reschedule link discovery as we are never in SLAVE role now
1771 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001772
1773 // Setup the BDDP task. It is invoked whenever switch port tuples
1774 // are added to the quarantine list.
1775 bddpTask = new SingletonTask(ses, new QuarantineWorker());
1776 bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
1777
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001778
1779 // Register for the OpenFlow messages we want to receive
1780 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
1781 floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
1782 // Register for switch updates
1783 floodlightProvider.addOFSwitchListener(this);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001784 if (restApi != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001785 restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001786 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001787 setControllerTLV();
1788 }
1789
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001790 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001791 public boolean isAutoPortFastFeature() {
1792 return autoPortFastFeature;
1793 }
1794
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001795 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001796 public void setAutoPortFastFeature(boolean autoPortFastFeature) {
1797 this.autoPortFastFeature = autoPortFastFeature;
1798 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001799}