blob: 22baf58ed8356ac85349295c80b13bdeca2cd361 [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;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080021import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.Iterator;
Jonathan Hart299d1132014-06-27 09:25:28 -070027import java.util.LinkedList;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080028import java.util.List;
29import java.util.Map;
30import java.util.Map.Entry;
31import java.util.Set;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080032import java.util.concurrent.ScheduledExecutorService;
33import java.util.concurrent.TimeUnit;
34import java.util.concurrent.locks.ReentrantReadWriteLock;
35
36import net.floodlightcontroller.core.FloodlightContext;
37import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080038import net.floodlightcontroller.core.IOFMessageListener;
39import net.floodlightcontroller.core.IOFSwitch;
40import net.floodlightcontroller.core.IOFSwitchListener;
41import net.floodlightcontroller.core.annotations.LogMessageCategory;
42import net.floodlightcontroller.core.annotations.LogMessageDoc;
43import net.floodlightcontroller.core.annotations.LogMessageDocs;
44import net.floodlightcontroller.core.module.FloodlightModuleContext;
45import net.floodlightcontroller.core.module.FloodlightModuleException;
46import net.floodlightcontroller.core.module.IFloodlightModule;
47import net.floodlightcontroller.core.module.IFloodlightService;
48import net.floodlightcontroller.core.util.SingletonTask;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080049import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080050import net.floodlightcontroller.threadpool.IThreadPoolService;
Jonathan Hart23701d12014-04-03 10:45:48 -070051import net.onrc.onos.core.linkdiscovery.ILinkDiscovery;
Jonathan Harta99ec672014-04-03 11:30:34 -070052import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
53import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.UpdateOperation;
Jonathan Hart23701d12014-04-03 10:45:48 -070054import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
55import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
56import net.onrc.onos.core.linkdiscovery.Link;
57import net.onrc.onos.core.linkdiscovery.LinkInfo;
58import net.onrc.onos.core.linkdiscovery.NodePortTuple;
Jonathan Hart23701d12014-04-03 10:45:48 -070059import net.onrc.onos.core.linkdiscovery.web.LinkDiscoveryWebRoutable;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070060import net.onrc.onos.core.packet.Ethernet;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070061import net.onrc.onos.core.packet.LLDP;
Jonathan Hart299d1132014-06-27 09:25:28 -070062import net.onrc.onos.core.packet.OnosLldp;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070063import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart299d1132014-06-27 09:25:28 -070064import net.onrc.onos.core.util.SwitchPort;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070065
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080066import org.openflow.protocol.OFMessage;
67import org.openflow.protocol.OFPacketIn;
68import org.openflow.protocol.OFPacketOut;
69import org.openflow.protocol.OFPhysicalPort;
70import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
71import org.openflow.protocol.OFPhysicalPort.OFPortState;
72import org.openflow.protocol.OFPort;
73import org.openflow.protocol.OFPortStatus;
74import org.openflow.protocol.OFPortStatus.OFPortReason;
75import org.openflow.protocol.OFType;
76import org.openflow.protocol.action.OFAction;
77import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart299d1132014-06-27 09:25:28 -070078import org.openflow.protocol.action.OFActionType;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080079import org.openflow.util.HexString;
80import org.slf4j.Logger;
81import org.slf4j.LoggerFactory;
82
83/**
84 * This class sends out LLDP messages containing the sending switch's datapath
Jonathan Hart299d1132014-06-27 09:25:28 -070085 * id as well as the outgoing port number. Received LLDP messages that
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080086 * match a known switch cause a new LinkTuple to be created according to the
87 * invariant rules listed below. This new LinkTuple is also passed to routing
88 * if it exists to trigger updates.
Ray Milkey269ffb92014-04-03 14:43:30 -070089 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080090 * This class also handles removing links that are associated to switch ports
91 * that go down, and switches that are disconnected.
Ray Milkey269ffb92014-04-03 14:43:30 -070092 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080093 * Invariants:
Ray Milkey269ffb92014-04-03 14:43:30 -070094 * -portLinks and switchLinks will not contain empty Sets outside of
Ray Milkeyb41100a2014-04-10 10:42:15 -070095 * critical sections.
Ray Milkey269ffb92014-04-03 14:43:30 -070096 * -portLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -070097 * SwitchPortTuple matches the map key.
Ray Milkey269ffb92014-04-03 14:43:30 -070098 * -switchLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -070099 * SwitchPortTuple's id matches the switch id.
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 * -Each LinkTuple will be indexed into switchLinks for both
Ray Milkeyb41100a2014-04-10 10:42:15 -0700101 * src.id and dst.id, and portLinks for each src and dst.
102 * -The updates queue is only added to from within a held write lock.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800103 */
104@LogMessageCategory("Network Topology")
105public class LinkDiscoveryManager
Ray Milkey269ffb92014-04-03 14:43:30 -0700106 implements IOFMessageListener, IOFSwitchListener,
107 ILinkDiscoveryService, IFloodlightModule {
108 protected IFloodlightProviderService controller;
Ray Milkeyec838942014-04-09 11:28:43 -0700109 private static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800110
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800111 protected IFloodlightProviderService floodlightProvider;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800112 protected IThreadPoolService threadPool;
113 protected IRestApiService restApi;
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700114 // Registry Service for ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700115 protected IControllerRegistryService registryService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800116
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700117
Jonathan Hartba354e02014-06-30 19:18:16 -0700118 // LLDP fields
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800119 private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800120 HexString.fromHexString("01:80:c2:00:00:0e");
Ray Milkey269ffb92014-04-03 14:43:30 -0700121 private static final long LINK_LOCAL_MASK = 0xfffffffffff0L;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800122 private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
123
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800124 // Link discovery task details.
125 protected SingletonTask discoveryTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700126 protected static final int DISCOVERY_TASK_INTERVAL = 1;
127 protected static final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
128 protected static final int LLDP_TO_ALL_INTERVAL = 15; //original 15 seconds, aggressive 2 secs.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800129 protected long lldpClock = 0;
130 // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
131 // If we want to identify link failures faster, we could decrease this
132 // value to a small number, say 1 or 2 sec.
Ray Milkey2476cac2014-04-08 11:03:21 -0700133 protected static final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known links
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800134
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800135 protected ReentrantReadWriteLock lock;
136 int lldpTimeCount = 0;
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700137
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800138 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700139 * Map from link to the most recent time it was verified functioning.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800140 */
141 protected Map<Link, LinkInfo> links;
142
143 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700144 * Map from switch id to a set of all links with it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800145 */
146 protected Map<Long, Set<Link>> switchLinks;
147
148 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700149 * Map from a id:port to the set of links containing it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800150 */
151 protected Map<NodePortTuple, Set<Link>> portLinks;
152
153 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700154 * Topology aware components are called in the order they were added to the
155 * the array.
156 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800157 protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800158
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700159 protected class LinkUpdate extends LDUpdate {
160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 public LinkUpdate(LDUpdate old) {
162 super(old);
163 }
164
165 @LogMessageDoc(level = "ERROR",
166 message = "Error in link discovery updates loop",
167 explanation = "An unknown error occured while dispatching " +
168 "link update notifications",
169 recommendation = LogMessageDoc.GENERIC_ACTION)
170 @Override
171 public void dispatch() {
172 if (linkDiscoveryAware != null) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800173 if (log.isTraceEnabled()) {
174 log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 new Object[]{this.getOperation(),
176 HexString.toHexString(this.getSrc()), this.getSrcPort(),
177 HexString.toHexString(this.getDst()), this.getDstPort(),
178 linkDiscoveryAware});
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800179 }
180 try {
181 for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
182 lda.linkDiscoveryUpdate(this);
183 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 } catch (Exception e) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800185 log.error("Error in link discovery updates loop", e);
186 }
187 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700188 }
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700189 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800190
191 /**
192 * List of ports through which LLDP/BDDPs are not sent.
193 */
194 protected Set<NodePortTuple> suppressLinkDiscovery;
195
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 /**
197 * A list of ports that are quarantined for discovering links through
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800198 * them. Data traffic from these ports are not allowed until the ports
199 * are released from quarantine.
200 */
Jonathan Hartba354e02014-06-30 19:18:16 -0700201 //protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
202 //protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800203
204 /**
205 * Map of broadcast domain ports and the last time a BDDP was either
206 * sent or received on that port.
207 */
208 protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap;
209
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800210 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800211 * Get the LLDP sending period in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800213 * @return LLDP sending period in seconds.
214 */
215 public int getLldpFrequency() {
216 return LLDP_TO_KNOWN_INTERVAL;
217 }
218
219 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700220 * Get the LLDP timeout value in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800222 * @return LLDP timeout value in seconds
223 */
224 public int getLldpTimeout() {
225 return LINK_TIMEOUT;
226 }
227
228 public Map<NodePortTuple, Set<Link>> getPortLinks() {
229 return portLinks;
230 }
231
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800232 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800233 public Set<NodePortTuple> getSuppressLLDPsInfo() {
234 return suppressLinkDiscovery;
235 }
236
237 /**
238 * Add a switch port to the suppressed LLDP list.
239 * Remove any known links on the switch port.
240 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800241 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700242 public void addToSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800243 NodePortTuple npt = new NodePortTuple(sw, port);
244 this.suppressLinkDiscovery.add(npt);
245 deleteLinksOnPort(npt, "LLDP suppressed.");
246 }
247
248 /**
249 * Remove a switch port from the suppressed LLDP list.
250 * Discover links on that switchport.
251 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800252 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700253 public void removeFromSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800254 NodePortTuple npt = new NodePortTuple(sw, port);
255 this.suppressLinkDiscovery.remove(npt);
256 discover(npt);
257 }
258
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800259 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800260 public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
261 if (info.getUnicastValidTime() != null) {
262 return ILinkDiscovery.LinkType.DIRECT_LINK;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800263 }
264 return ILinkDiscovery.LinkType.INVALID_LINK;
265 }
266
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800267
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800268 private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
269 return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
270 }
271
272 protected void discoverLinks() {
273
274 // timeout known links.
275 timeoutLinks();
276
277 //increment LLDP clock
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800279
280 if (lldpClock == 0) {
281 log.debug("Sending LLDP out on all ports.");
282 discoverOnAllPorts();
283 }
284 }
285
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800286 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700287 * Send LLDP on known ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800288 */
289 protected void discoverOnKnownLinkPorts() {
290 // Copy the port set.
291 Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
292 nptSet.addAll(portLinks.keySet());
293
294 // Send LLDP from each of them.
Ray Milkey269ffb92014-04-03 14:43:30 -0700295 for (NodePortTuple npt : nptSet) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800296 discover(npt);
297 }
298 }
299
300 protected void discover(NodePortTuple npt) {
301 discover(npt.getNodeId(), npt.getPortId());
302 }
303
304 protected void discover(long sw, short port) {
Jonathan Hartba354e02014-06-30 19:18:16 -0700305 sendDiscoveryMessage(sw, port, false);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800306 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800307
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800308 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800309 * Send link discovery message out of a given switch port.
310 * The discovery message may be a standard LLDP or a modified
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800311 * LLDP, where the dst mac address is set to :ff.
Ray Milkey269ffb92014-04-03 14:43:30 -0700312 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800313 * TODO: The modified LLDP will updated in the future and may
314 * use a different eth-type.
Ray Milkey269ffb92014-04-03 14:43:30 -0700315 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800316 * @param sw
317 * @param port
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 * @param isStandard indicates standard or modified LLDP
319 * @param isReverse indicates whether the LLDP was sent as a response
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800320 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700321 @LogMessageDoc(level = "ERROR",
322 message = "Failure sending LLDP out port {port} on switch {switch}",
323 explanation = "An I/O error occured while sending LLDP message " +
324 "to the switch.",
325 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800326 protected void sendDiscoveryMessage(long sw, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700327 boolean isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800328
329 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
330 if (iofSwitch == null) {
331 return;
332 }
333
Ray Milkeyb29e6262014-04-09 16:02:14 -0700334 if (port == OFPort.OFPP_LOCAL.getValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800335 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700336 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800337
338 OFPhysicalPort ofpPort = iofSwitch.getPort(port);
339
340 if (ofpPort == null) {
341 if (log.isTraceEnabled()) {
342 log.trace("Null physical port. sw={}, port={}", sw, port);
343 }
344 return;
345 }
346
347 if (isLinkDiscoverySuppressed(sw, port)) {
348 /* Dont send LLDPs out of this port as suppressLLDPs set
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800349 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800350 */
351 return;
352 }
353
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800354 if (log.isTraceEnabled()) {
355 log.trace("Sending LLDP packet out of swich: {}, port: {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 sw, port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800357 }
358
Jonathan Hart299d1132014-06-27 09:25:28 -0700359 OFPacketOut po = createLLDPPacketOut(sw, ofpPort, isReverse);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800360
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800361 try {
362 iofSwitch.write(po, null);
363 iofSwitch.flush();
364 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 log.error("Failure sending LLDP out port " + port + " on switch " + iofSwitch.getStringId(), e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800366 }
367
368 }
369
370 /**
Jonathan Hart299d1132014-06-27 09:25:28 -0700371 * Creates packet_out LLDP for specified output port.
372 *
373 * @param dpid the dpid of the outgoing switch
374 * @param port the outgoing port
375 * @param isReverse whether this is a reverse LLDP or not
376 * @return Packet_out message with LLDP data
377 */
378 private OFPacketOut createLLDPPacketOut(long dpid,
379 final OFPhysicalPort port, boolean isReverse) {
380 // Set up packets
381 // TODO optimize by not creating new packets each time
382 OnosLldp lldpPacket = new OnosLldp();
383
384 Ethernet ethPacket = new Ethernet();
385 ethPacket.setEtherType(Ethernet.TYPE_LLDP);
386 ethPacket.setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING);
387 ethPacket.setPayload(lldpPacket);
388 ethPacket.setPad(true);
389
390 final OFPacketOut packetOut = (OFPacketOut) floodlightProvider.getOFMessageFactory()
391 .getMessage(OFType.PACKET_OUT);
392 packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
393
394 final List<OFAction> actionsList = new LinkedList<OFAction>();
395 final OFActionOutput out = (OFActionOutput) floodlightProvider.getOFMessageFactory()
396 .getAction(OFActionType.OUTPUT);
397 out.setPort(port.getPortNumber());
398 actionsList.add(out);
399 packetOut.setActions(actionsList);
400 final short alen = (short) OFActionOutput.MINIMUM_LENGTH;
401
402 lldpPacket.setSwitch(dpid);
403 lldpPacket.setPort(port.getPortNumber());
404 lldpPacket.setReverse(isReverse);
405 ethPacket.setSourceMACAddress(port.getHardwareAddress());
406
407 final byte[] lldp = ethPacket.serialize();
408 packetOut.setActionsLength(alen);
409 packetOut.setPacketData(lldp);
410 packetOut
411 .setLength((short) (OFPacketOut.MINIMUM_LENGTH + alen + lldp.length));
412 return packetOut;
413 }
414
415 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700416 * Send LLDPs to all switch-ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800417 */
418 protected void discoverOnAllPorts() {
419 if (log.isTraceEnabled()) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800420 log.trace("Sending LLDP packets out of all the enabled ports on switch");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800421 }
422 Set<Long> switches = floodlightProvider.getSwitches().keySet();
423 // Send standard LLDPs
Ray Milkey269ffb92014-04-03 14:43:30 -0700424 for (long sw : switches) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800425 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700426 if (iofSwitch == null) {
427 continue;
428 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800429 if (iofSwitch.getEnabledPorts() != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700430 for (OFPhysicalPort ofp : iofSwitch.getEnabledPorts()) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700431 if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800432 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700433 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800434
435 // sends forward LLDP only non-fastports.
Jonathan Hartba354e02014-06-30 19:18:16 -0700436 sendDiscoveryMessage(sw, ofp.getPortNumber(), false);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800437 }
438 }
439 }
440 }
441
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800442 @Override
443 public String getName() {
444 return "linkdiscovery";
445 }
446
447 @Override
448 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
449 switch (msg.getType()) {
450 case PACKET_IN:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700451 if (msg instanceof OFPacketIn) {
452 return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
453 cntx);
454 }
455 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800456 case PORT_STATUS:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700457 if (msg instanceof OFPortStatus) {
458 return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
459 }
460 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800461 default:
462 break;
463 }
464 return Command.CONTINUE;
465 }
466
Jonathan Hartba354e02014-06-30 19:18:16 -0700467 private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800468 // If LLDP is suppressed on this port, ignore received packet as well
469 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
470 if (iofSwitch == null) {
471 return Command.STOP;
472 }
473
Ray Milkeyb29e6262014-04-09 16:02:14 -0700474 if (isLinkDiscoverySuppressed(sw, pi.getInPort())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800475 return Command.STOP;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700476 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800477
478 // If this is a malformed LLDP, or not from us, exit
Ray Milkeyb29e6262014-04-09 16:02:14 -0700479 if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800480 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700481 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800482
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800483 // Verify this LLDP packet matches what we're looking for
Jonathan Hart299d1132014-06-27 09:25:28 -0700484 byte[] packetData = pi.getPacketData();
485 if (!OnosLldp.isOnosLldp(packetData)) {
486 log.trace("Dropping LLDP that wasn't sent by ONOS");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800487 return Command.STOP;
488 }
489
Jonathan Hart299d1132014-06-27 09:25:28 -0700490 SwitchPort switchPort = OnosLldp.extractSwitchPort(packetData);
491 long remoteDpid = switchPort.dpid().value();
492 short remotePort = switchPort.port().value();
493 IOFSwitch remoteSwitch = floodlightProvider.getSwitches().get(switchPort.dpid().value());
494
495
496 OFPhysicalPort physicalPort = null;
497 if (remoteSwitch != null) {
498 physicalPort = remoteSwitch.getPort(remotePort);
499 if (!remoteSwitch.portEnabled(remotePort)) {
500 if (log.isTraceEnabled()) {
501 log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
502 }
503 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800504 }
Jonathan Hart299d1132014-06-27 09:25:28 -0700505 if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(),
506 remotePort))) {
507 if (log.isTraceEnabled()) {
508 log.trace("Ignoring link with suppressed src port: switch {} port {}",
509 remoteSwitch, remotePort);
510 }
511 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800512 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800513 }
514 if (!iofSwitch.portEnabled(pi.getInPort())) {
515 if (log.isTraceEnabled()) {
516 log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
517 }
518 return Command.STOP;
519 }
520
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800521 int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
522 physicalPort = iofSwitch.getPort(pi.getInPort());
523 int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
524
525 // Store the time of update to this link, and push it out to routingEngine
Jonathan Hart299d1132014-06-27 09:25:28 -0700526 Link lt = new Link(remoteDpid, remotePort, iofSwitch.getId(), pi.getInPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800527
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800528 Long firstSeenTime = System.currentTimeMillis();
529
Jonathan Hartba354e02014-06-30 19:18:16 -0700530 Long lastLldpTime = System.currentTimeMillis();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800531
532 LinkInfo newLinkInfo =
Jonathan Hartba354e02014-06-30 19:18:16 -0700533 new LinkInfo(firstSeenTime, lastLldpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700534 srcPortState, dstPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800535
536 addOrUpdateLink(lt, newLinkInfo);
537
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800538 // Check if reverse link exists.
539 // If it doesn't exist and if the forward link was seen
540 // first seen within a small interval, send probe on the
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800541 // reverse link.
542
Jonathan Hart299d1132014-06-27 09:25:28 -0700543 boolean isReverse = OnosLldp.isReverse(lldp);
544
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800545 newLinkInfo = links.get(lt);
Jonathan Hartba354e02014-06-30 19:18:16 -0700546 if (newLinkInfo != null && !isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800547 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800549 LinkInfo reverseInfo = links.get(reverseLink);
550 if (reverseInfo == null) {
551 // the reverse link does not exist.
552 if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) {
Jonathan Hartba354e02014-06-30 19:18:16 -0700553 this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), true);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800554 }
555 }
556 }
557
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800558 // Consume this message
559 return Command.STOP;
560 }
561
562 protected Command handlePacketIn(long sw, OFPacketIn pi,
563 FloodlightContext cntx) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800564 Ethernet eth =
565 IFloodlightProviderService.bcStore.get(cntx,
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800567
Jonathan Hartba354e02014-06-30 19:18:16 -0700568 if (eth.getEtherType() == Ethernet.TYPE_LLDP) {
569 return handleLldp((LLDP) eth.getPayload(), sw, pi);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800570 } else if (eth.getEtherType() < 1500) {
571 long destMac = eth.getDestinationMAC().toLong();
Ray Milkey269ffb92014-04-03 14:43:30 -0700572 if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800573 if (log.isTraceEnabled()) {
574 log.trace("Ignoring packet addressed to 802.1D/Q " +
575 "reserved address.");
576 }
577 return Command.STOP;
578 }
579 }
580
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800581 return Command.CONTINUE;
582 }
583
584 protected UpdateOperation getUpdateOperation(int srcPortState,
585 int dstPortState) {
586 boolean added =
587 (((srcPortState &
Ray Milkey269ffb92014-04-03 14:43:30 -0700588 OFPortState.OFPPS_STP_MASK.getValue()) !=
589 OFPortState.OFPPS_STP_BLOCK.getValue()) &&
590 ((dstPortState &
591 OFPortState.OFPPS_STP_MASK.getValue()) !=
592 OFPortState.OFPPS_STP_BLOCK.getValue()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800593
Ray Milkeyb29e6262014-04-09 16:02:14 -0700594 if (added) {
595 return UpdateOperation.LINK_UPDATED;
596 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800597 return UpdateOperation.LINK_REMOVED;
598 }
599
600
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800601 protected UpdateOperation getUpdateOperation(int srcPortState) {
602 boolean portUp = ((srcPortState &
603 OFPortState.OFPPS_STP_MASK.getValue()) !=
604 OFPortState.OFPPS_STP_BLOCK.getValue());
605
Ray Milkeyb29e6262014-04-09 16:02:14 -0700606 if (portUp) {
607 return UpdateOperation.PORT_UP;
608 } else {
609 return UpdateOperation.PORT_DOWN;
610 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800611 }
612
613 protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
614
615 NodePortTuple srcNpt, dstNpt;
616 boolean linkChanged = false;
617
618 lock.writeLock().lock();
619 try {
620 // put the new info. if an old info exists, it will be returned.
621 LinkInfo oldInfo = links.put(lt, newInfo);
622 if (oldInfo != null &&
Ray Milkeyb29e6262014-04-09 16:02:14 -0700623 oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800624 newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700625 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800626
627 if (log.isTraceEnabled()) {
Jonathan Hartba354e02014-06-30 19:18:16 -0700628 log.trace("addOrUpdateLink: {}", lt);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800629 }
630
631 UpdateOperation updateOperation = null;
632 linkChanged = false;
633
634 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
635 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
636
637 if (oldInfo == null) {
638 // index it by switch source
Ray Milkeyb29e6262014-04-09 16:02:14 -0700639 if (!switchLinks.containsKey(lt.getSrc())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800640 switchLinks.put(lt.getSrc(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700641 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800642 switchLinks.get(lt.getSrc()).add(lt);
643
644 // index it by switch dest
Ray Milkeyb29e6262014-04-09 16:02:14 -0700645 if (!switchLinks.containsKey(lt.getDst())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800646 switchLinks.put(lt.getDst(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700647 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800648 switchLinks.get(lt.getDst()).add(lt);
649
650 // index both ends by switch:port
Ray Milkeyb29e6262014-04-09 16:02:14 -0700651 if (!portLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800652 portLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700653 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800654 portLinks.get(srcNpt).add(lt);
655
Ray Milkeyb29e6262014-04-09 16:02:14 -0700656 if (!portLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800657 portLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700658 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800659 portLinks.get(dstNpt).add(lt);
660
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700661 // ONOS: Distinguish added event separately from updated event
Pankaj Berdea41016d2013-06-10 21:18:18 -0700662 updateOperation = UpdateOperation.LINK_ADDED;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800663 linkChanged = true;
664
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800665 } else {
666 // Since the link info is already there, we need to
667 // update the right fields.
668 if (newInfo.getUnicastValidTime() == null) {
669 // This is due to a multicast LLDP, so copy the old unicast
670 // value.
671 if (oldInfo.getUnicastValidTime() != null) {
672 newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
673 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800674 }
675
676 Long oldTime = oldInfo.getUnicastValidTime();
677 Long newTime = newInfo.getUnicastValidTime();
678 // the link has changed its state between openflow and non-openflow
679 // if the unicastValidTimes are null or not null
680 if (oldTime != null & newTime == null) {
681 // openflow -> non-openflow transition
682 // we need to add the link tuple to the portNOFLinks
Jonathan Hartba354e02014-06-30 19:18:16 -0700683 //addLinkToBroadcastDomain(lt);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800684 linkChanged = true;
685 } else if (oldTime == null & newTime != null) {
686 // non-openflow -> openflow transition
687 // we need to remove the link from the portNOFLinks
Jonathan Hartba354e02014-06-30 19:18:16 -0700688 //removeLinkFromBroadcastDomain(lt);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800689 linkChanged = true;
690 }
691
692 // Only update the port states if they've changed
693 if (newInfo.getSrcPortState().intValue() !=
694 oldInfo.getSrcPortState().intValue() ||
695 newInfo.getDstPortState().intValue() !=
Ray Milkeyb29e6262014-04-09 16:02:14 -0700696 oldInfo.getDstPortState().intValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800697 linkChanged = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700698 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800699
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800700 if (linkChanged) {
701 updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700702 newInfo.getDstPortState());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800703 if (log.isTraceEnabled()) {
704 log.trace("Updated link {}", lt);
705 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800706 }
707 }
708
709 if (linkChanged) {
710 // find out if the link was added or removed here.
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700711 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 lt.getDst(), lt.getDstPort(),
713 getLinkType(lt, newInfo),
714 updateOperation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700715 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800716 }
717 } finally {
718 lock.writeLock().unlock();
719 }
720
721 return linkChanged;
722 }
723
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800724 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800725 public Map<Long, Set<Link>> getSwitchLinks() {
726 return this.switchLinks;
727 }
728
729 /**
730 * Removes links from memory and storage.
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 *
Ray Milkey5df613b2014-04-15 10:50:56 -0700732 * @param linksToDelete The List of @LinkTuple to delete.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800733 */
Ray Milkey5df613b2014-04-15 10:50:56 -0700734 protected void deleteLinks(List<Link> linksToDelete, String reason) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800735 NodePortTuple srcNpt, dstNpt;
736
737 lock.writeLock().lock();
738 try {
Ray Milkey5df613b2014-04-15 10:50:56 -0700739 for (Link lt : linksToDelete) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800740 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700741 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800742
743 switchLinks.get(lt.getSrc()).remove(lt);
744 switchLinks.get(lt.getDst()).remove(lt);
745 if (switchLinks.containsKey(lt.getSrc()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -0700746 switchLinks.get(lt.getSrc()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800747 this.switchLinks.remove(lt.getSrc());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700748 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800749 if (this.switchLinks.containsKey(lt.getDst()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -0700750 this.switchLinks.get(lt.getDst()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800751 this.switchLinks.remove(lt.getDst());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700752 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800753
754 if (this.portLinks.get(srcNpt) != null) {
755 this.portLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700756 if (this.portLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800757 this.portLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700758 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800759 }
760 if (this.portLinks.get(dstNpt) != null) {
761 this.portLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700762 if (this.portLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800763 this.portLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700764 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800765 }
766
767 LinkInfo info = this.links.remove(lt);
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700768 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 lt.getDst(), lt.getDstPort(),
770 getLinkType(lt, info),
771 UpdateOperation.LINK_REMOVED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700772 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800773
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800774 // TODO Whenever link is removed, it has to checked if
775 // the switchports must be added to quarantine.
776
777 if (log.isTraceEnabled()) {
778 log.trace("Deleted link {}", lt);
779 }
780 }
781 } finally {
782 lock.writeLock().unlock();
783 }
784 }
785
786 /**
787 * Handles an OFPortStatus message from a switch. We will add or
788 * delete LinkTupes as well re-compute the topology if needed.
Ray Milkey269ffb92014-04-03 14:43:30 -0700789 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800790 * @param sw The IOFSwitch that sent the port status message
791 * @param ps The OFPortStatus message
792 * @return The Command to continue or stop after we process this message
793 */
794 protected Command handlePortStatus(long sw, OFPortStatus ps) {
795
796 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700797 if (iofSwitch == null) {
798 return Command.CONTINUE;
799 }
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -0700800
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700801 // ONOS: If we do not control this switch, then we should not process its port status messages
Ray Milkeyb29e6262014-04-09 16:02:14 -0700802 if (!registryService.hasControl(iofSwitch.getId())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700803 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700804 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800805
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800806 if (log.isTraceEnabled()) {
807 log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
808 "config is {} state is {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700809 new Object[]{iofSwitch.getStringId(),
810 ps.getDesc().getPortNumber(),
811 ps.getReason(),
812 ps.getDesc().getConfig(),
813 ps.getDesc().getState()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800814 }
815
816 short port = ps.getDesc().getPortNumber();
817 NodePortTuple npt = new NodePortTuple(sw, port);
Ray Milkey269ffb92014-04-03 14:43:30 -0700818 boolean linkDeleted = false;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800819 boolean linkInfoChanged = false;
820
821 lock.writeLock().lock();
822 try {
823 // if ps is a delete, or a modify where the port is down or
824 // configured down
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 if ((byte) OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
826 ((byte) OFPortReason.OFPPR_MODIFY.ordinal() ==
827 ps.getReason() && !portEnabled(ps.getDesc()))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800828 deleteLinksOnPort(npt, "Port Status Changed");
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700829 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, UpdateOperation.PORT_DOWN));
830 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800831 linkDeleted = true;
Ray Milkey269ffb92014-04-03 14:43:30 -0700832 } else if (ps.getReason() ==
833 (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800834 // If ps is a port modification and the port state has changed
835 // that affects links in the topology
836
837 if (this.portLinks.containsKey(npt)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700838 for (Link lt : this.portLinks.get(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800839 LinkInfo linkInfo = links.get(lt);
Ray Milkey269ffb92014-04-03 14:43:30 -0700840 assert (linkInfo != null);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800841 Integer updatedSrcPortState = null;
842 Integer updatedDstPortState = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800843 if (lt.getSrc() == npt.getNodeId() &&
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800844 lt.getSrcPort() == npt.getPortId() &&
845 (linkInfo.getSrcPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -0700846 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800847 updatedSrcPortState = ps.getDesc().getState();
848 linkInfo.setSrcPortState(updatedSrcPortState);
849 }
850 if (lt.getDst() == npt.getNodeId() &&
851 lt.getDstPort() == npt.getPortId() &&
852 (linkInfo.getDstPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800854 updatedDstPortState = ps.getDesc().getState();
855 linkInfo.setDstPortState(updatedDstPortState);
856 }
857 if ((updatedSrcPortState != null) ||
858 (updatedDstPortState != null)) {
859 // The link is already known to link discovery
860 // manager and the status has changed, therefore
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700861 // send an LinkUpdate.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800862 UpdateOperation operation =
863 getUpdateOperation(linkInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700864 linkInfo.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700865 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700866 lt.getDst(), lt.getDstPort(),
867 getLinkType(lt, linkInfo),
868 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700869 controller.publishUpdate(update);
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800870
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800871 linkInfoChanged = true;
872 }
873 }
874 }
875
876 UpdateOperation operation =
877 getUpdateOperation(ps.getDesc().getState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700878 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
879 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800880 }
881
Ray Milkey269ffb92014-04-03 14:43:30 -0700882 if (!linkDeleted && !linkInfoChanged) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800883 if (log.isTraceEnabled()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700884 log.trace("handlePortStatus: Switch {} port #{} reason {};" +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800885 " no links to update/remove",
Ray Milkey269ffb92014-04-03 14:43:30 -0700886 new Object[]{HexString.toHexString(sw),
887 ps.getDesc().getPortNumber(),
888 ps.getReason()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800889 }
890 }
891 } finally {
892 lock.writeLock().unlock();
893 }
894
895 if (!linkDeleted) {
896 // Send LLDP right away when port state is changed for faster
897 // cluster-merge. If it is a link delete then there is not need
898 // to send the LLDPs right away and instead we wait for the LLDPs
899 // to be sent on the timer as it is normally done
900 // do it outside the write-lock
901 // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
902 processNewPort(npt.getNodeId(), npt.getPortId());
903 }
904 return Command.CONTINUE;
905 }
906
907 /**
908 * Process a new port.
909 * If link discovery is disabled on the port, then do nothing.
910 * If autoportfast feature is enabled and the port is a fast port, then
911 * do nothing.
912 * Otherwise, send LLDP message. Add the port to quarantine.
Ray Milkey269ffb92014-04-03 14:43:30 -0700913 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800914 * @param sw
915 * @param p
916 */
917 private void processNewPort(long sw, short p) {
918 if (isLinkDiscoverySuppressed(sw, p)) {
919 // Do nothing as link discovery is suppressed.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700920 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700921 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800922 discover(sw, p);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800923 }
924 }
925
926 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700927 * We send out LLDP messages when a switch is added to discover the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800929 * @param sw The IOFSwitch that connected to the controller
930 */
931 @Override
932 public void addedSwitch(IOFSwitch sw) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800933 if (sw.getEnabledPorts() != null) {
934 for (Short p : sw.getEnabledPortNumbers()) {
935 processNewPort(sw.getId(), p);
936 }
937 }
Jonathan Hart6d208022014-06-24 18:56:36 -0700938
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700939 LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), null,
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 UpdateOperation.SWITCH_UPDATED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700941 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800942 }
943
944 /**
945 * When a switch disconnects we remove any links from our map and notify.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800946 */
947 @Override
948 public void removedSwitch(IOFSwitch iofSwitch) {
949 // Update event history
950 long sw = iofSwitch.getId();
Jonathan Hart6d208022014-06-24 18:56:36 -0700951
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800952 List<Link> eraseList = new ArrayList<Link>();
953 lock.writeLock().lock();
954 try {
955 if (switchLinks.containsKey(sw)) {
956 if (log.isTraceEnabled()) {
957 log.trace("Handle switchRemoved. Switch {}; removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700958 HexString.toHexString(sw), switchLinks.get(sw));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800959 }
960 // add all tuples with an endpoint on this switch to erase list
961 eraseList.addAll(switchLinks.get(sw));
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -0700962 deleteLinks(eraseList, "Switch Removed");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800963
964 // Send a switch removed update
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700965 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED));
966 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800967 }
968 } finally {
969 lock.writeLock().unlock();
970 }
971 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800972
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800973 /**
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800974 * We don't react the port changed notifications here. we listen for
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800975 * OFPortStatus messages directly. Might consider using this notifier
976 * instead
977 */
978 @Override
979 public void switchPortChanged(Long switchId) {
980 // no-op
981 }
982
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800983 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800984 * Delete links incident on a given switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800986 * @param npt
987 * @param reason
988 */
989 protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
990 List<Link> eraseList = new ArrayList<Link>();
991 if (this.portLinks.containsKey(npt)) {
992 if (log.isTraceEnabled()) {
993 log.trace("handlePortStatus: Switch {} port #{} " +
994 "removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700995 new Object[]{HexString.toHexString(npt.getNodeId()),
996 npt.getPortId(),
997 this.portLinks.get(npt)});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800998 }
999 eraseList.addAll(this.portLinks.get(npt));
1000 deleteLinks(eraseList, reason);
1001 }
1002 }
1003
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001004 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001005 * Iterates through the list of links and deletes if the
1006 * last discovery message reception time exceeds timeout values.
1007 */
1008 protected void timeoutLinks() {
1009 List<Link> eraseList = new ArrayList<Link>();
1010 Long curTime = System.currentTimeMillis();
1011 boolean linkChanged = false;
1012
1013 // reentrant required here because deleteLink also write locks
1014 lock.writeLock().lock();
1015 try {
1016 Iterator<Entry<Link, LinkInfo>> it =
1017 this.links.entrySet().iterator();
1018 while (it.hasNext()) {
1019 Entry<Link, LinkInfo> entry = it.next();
1020 Link lt = entry.getKey();
1021 LinkInfo info = entry.getValue();
1022
1023 // Timeout the unicast and multicast LLDP valid times
1024 // independently.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001025 if ((info.getUnicastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001026 (info.getUnicastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001027 info.setUnicastValidTime(null);
1028
Jonathan Hartba354e02014-06-30 19:18:16 -07001029 //if (info.getMulticastValidTime() != null) {
1030 //addLinkToBroadcastDomain(lt);
1031 //}
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001032 // Note that even if mTime becomes null later on,
1033 // the link would be deleted, which would trigger updateClusters().
1034 linkChanged = true;
1035 }
Jonathan Hartba354e02014-06-30 19:18:16 -07001036 /*if ((info.getMulticastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001037 (info.getMulticastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001038 info.setMulticastValidTime(null);
1039 // if uTime is not null, then link will remain as openflow
1040 // link. If uTime is null, it will be deleted. So, we
1041 // don't care about linkChanged flag here.
1042 removeLinkFromBroadcastDomain(lt);
1043 linkChanged = true;
Jonathan Hartba354e02014-06-30 19:18:16 -07001044 }*/
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001045 // Add to the erase list only if the unicast
1046 // time is null.
Jonathan Hartba354e02014-06-30 19:18:16 -07001047 if (info.getUnicastValidTime() == null) { //&&
1048 //info.getMulticastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001049 eraseList.add(entry.getKey());
1050 } else if (linkChanged) {
1051 UpdateOperation operation;
1052 operation = getUpdateOperation(info.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 info.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001054 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 lt.getDst(), lt.getDstPort(),
1056 getLinkType(lt, info),
1057 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001058 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001059 }
1060 }
1061
1062 // if any link was deleted or any link was changed.
1063 if ((eraseList.size() > 0) || linkChanged) {
1064 deleteLinks(eraseList, "LLDP timeout");
1065 }
1066 } finally {
1067 lock.writeLock().unlock();
1068 }
1069 }
1070
1071 private boolean portEnabled(OFPhysicalPort port) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001072 if (port == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001073 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001074 }
1075 if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001076 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001077 }
1078 if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001079 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001080 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001081 // Port STP state doesn't work with multiple VLANs, so ignore it for now
1082 // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
1083 // return false;
1084 return true;
1085 }
1086
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001087 @Override
1088 public Map<Link, LinkInfo> getLinks() {
1089 lock.readLock().lock();
1090 Map<Link, LinkInfo> result;
1091 try {
1092 result = new HashMap<Link, LinkInfo>(links);
1093 } finally {
1094 lock.readLock().unlock();
1095 }
1096 return result;
1097 }
1098
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001099 @Override
1100 public void addListener(ILinkDiscoveryListener listener) {
1101 linkDiscoveryAware.add(listener);
1102 }
1103
1104 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001105 * Register a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001106 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001107 * @param linkDiscoveryAwareComponent
1108 */
1109 public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1110 // TODO make this a copy on write set or lock it somehow
1111 this.linkDiscoveryAware.add(linkDiscoveryAwareComponent);
1112 }
1113
1114 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001115 * Deregister a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001117 * @param linkDiscoveryAwareComponent
1118 */
1119 public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1120 // TODO make this a copy on write set or lock it somehow
1121 this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent);
1122 }
1123
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001124 @Override
1125 public boolean isCallbackOrderingPrereq(OFType type, String name) {
1126 return false;
1127 }
1128
1129 @Override
1130 public boolean isCallbackOrderingPostreq(OFType type, String name) {
1131 return false;
1132 }
1133
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001134 // IFloodlightModule classes
1135
1136 @Override
1137 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001138 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001139 new ArrayList<Class<? extends IFloodlightService>>();
1140 l.add(ILinkDiscoveryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001141 return l;
1142 }
1143
1144 @Override
1145 public Map<Class<? extends IFloodlightService>, IFloodlightService>
1146 getServiceImpls() {
1147 Map<Class<? extends IFloodlightService>,
Ray Milkey269ffb92014-04-03 14:43:30 -07001148 IFloodlightService> m =
1149 new HashMap<Class<? extends IFloodlightService>,
1150 IFloodlightService>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001151 // We are the class that implements the service
1152 m.put(ILinkDiscoveryService.class, this);
1153 return m;
1154 }
1155
1156 @Override
1157 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001158 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001159 new ArrayList<Class<? extends IFloodlightService>>();
1160 l.add(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001161 l.add(IThreadPoolService.class);
1162 l.add(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001163 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001164 l.add(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001165 return l;
1166 }
1167
1168 @Override
1169 public void init(FloodlightModuleContext context)
1170 throws FloodlightModuleException {
1171 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001172 threadPool = context.getServiceImpl(IThreadPoolService.class);
1173 restApi = context.getServiceImpl(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001174 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001175 registryService = context.getServiceImpl(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001176
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001177 // We create this here because there is no ordering guarantee
1178 this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
1179 this.lock = new ReentrantReadWriteLock();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001180 this.links = new HashMap<Link, LinkInfo>();
1181 this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
1182 this.suppressLinkDiscovery =
1183 Collections.synchronizedSet(new HashSet<NodePortTuple>());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001184 this.switchLinks = new HashMap<Long, Set<Link>>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001185 }
1186
1187 @Override
1188 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001189 @LogMessageDoc(level = "ERROR",
1190 message = "No storage source found.",
1191 explanation = "Storage source was not initialized; cannot initialize " +
1192 "link discovery.",
1193 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1194 @LogMessageDoc(level = "ERROR",
1195 message = "Error in installing listener for " +
1196 "switch config table {table}",
1197 explanation = "Failed to install storage notification for the " +
1198 "switch config table",
1199 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1200 @LogMessageDoc(level = "ERROR",
1201 message = "No storage source found.",
1202 explanation = "Storage source was not initialized; cannot initialize " +
1203 "link discovery.",
1204 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1205 @LogMessageDoc(level = "ERROR",
1206 message = "Exception in LLDP send timer.",
1207 explanation = "An unknown error occured while sending LLDP " +
1208 "messages to switches.",
1209 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001210 })
1211 public void startUp(FloodlightModuleContext context) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001212 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001213 controller =
1214 context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001215
1216 // To be started by the first switch connection
1217 discoveryTask = new SingletonTask(ses, new Runnable() {
1218 @Override
1219 public void run() {
1220 try {
1221 discoverLinks();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001222 } catch (Exception e) {
1223 log.error("Exception in LLDP send timer.", e);
1224 } finally {
Jonathan Hartba354e02014-06-30 19:18:16 -07001225 log.trace("Rescheduling discovery task");
1226 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
1227 TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001228 }
1229 }
1230 });
1231
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001232 // Always reschedule link discovery as we are never in SLAVE role now
1233 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001234
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001235 // Register for the OpenFlow messages we want to receive
1236 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
1237 floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
1238 // Register for switch updates
1239 floodlightProvider.addOFSwitchListener(this);
Jonathan Hartba354e02014-06-30 19:18:16 -07001240 restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001241 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001242}