blob: 33dbf5732c9966087fc0523ec8f7950d0407303a [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;
Jonathan Hart299d1132014-06-27 09:25:28 -070030import java.util.LinkedList;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080031import java.util.List;
32import java.util.Map;
33import java.util.Map.Entry;
34import java.util.Set;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080035import java.util.concurrent.LinkedBlockingQueue;
36import java.util.concurrent.ScheduledExecutorService;
37import java.util.concurrent.TimeUnit;
38import java.util.concurrent.locks.ReentrantReadWriteLock;
39
40import net.floodlightcontroller.core.FloodlightContext;
41import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080042import net.floodlightcontroller.core.IOFMessageListener;
43import net.floodlightcontroller.core.IOFSwitch;
44import net.floodlightcontroller.core.IOFSwitchListener;
45import net.floodlightcontroller.core.annotations.LogMessageCategory;
46import net.floodlightcontroller.core.annotations.LogMessageDoc;
47import net.floodlightcontroller.core.annotations.LogMessageDocs;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070048import net.floodlightcontroller.core.internal.OFSwitchImpl;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080049import net.floodlightcontroller.core.module.FloodlightModuleContext;
50import net.floodlightcontroller.core.module.FloodlightModuleException;
51import net.floodlightcontroller.core.module.IFloodlightModule;
52import net.floodlightcontroller.core.module.IFloodlightService;
53import net.floodlightcontroller.core.util.SingletonTask;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080054import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080055import net.floodlightcontroller.threadpool.IThreadPoolService;
Jonathan Hart23701d12014-04-03 10:45:48 -070056import net.onrc.onos.core.linkdiscovery.ILinkDiscovery;
Jonathan Harta99ec672014-04-03 11:30:34 -070057import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
58import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.UpdateOperation;
Jonathan Hart23701d12014-04-03 10:45:48 -070059import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
60import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
61import net.onrc.onos.core.linkdiscovery.Link;
62import net.onrc.onos.core.linkdiscovery.LinkInfo;
63import net.onrc.onos.core.linkdiscovery.NodePortTuple;
Jonathan Hart23701d12014-04-03 10:45:48 -070064import net.onrc.onos.core.linkdiscovery.web.LinkDiscoveryWebRoutable;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070065import net.onrc.onos.core.main.IOnosRemoteSwitch;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070066import net.onrc.onos.core.packet.BSN;
67import net.onrc.onos.core.packet.Ethernet;
68import net.onrc.onos.core.packet.IPv4;
69import net.onrc.onos.core.packet.LLDP;
70import net.onrc.onos.core.packet.LLDPTLV;
Jonathan Hart299d1132014-06-27 09:25:28 -070071import net.onrc.onos.core.packet.OnosLldp;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070072import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart299d1132014-06-27 09:25:28 -070073import net.onrc.onos.core.util.SwitchPort;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070074
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080075import org.openflow.protocol.OFMessage;
76import org.openflow.protocol.OFPacketIn;
77import org.openflow.protocol.OFPacketOut;
78import org.openflow.protocol.OFPhysicalPort;
79import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
80import org.openflow.protocol.OFPhysicalPort.OFPortState;
81import org.openflow.protocol.OFPort;
82import org.openflow.protocol.OFPortStatus;
83import org.openflow.protocol.OFPortStatus.OFPortReason;
84import org.openflow.protocol.OFType;
85import org.openflow.protocol.action.OFAction;
86import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart299d1132014-06-27 09:25:28 -070087import org.openflow.protocol.action.OFActionType;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080088import org.openflow.util.HexString;
89import org.slf4j.Logger;
90import org.slf4j.LoggerFactory;
91
92/**
93 * This class sends out LLDP messages containing the sending switch's datapath
Jonathan Hart299d1132014-06-27 09:25:28 -070094 * id as well as the outgoing port number. Received LLDP messages that
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080095 * match a known switch cause a new LinkTuple to be created according to the
96 * invariant rules listed below. This new LinkTuple is also passed to routing
97 * if it exists to trigger updates.
Ray Milkey269ffb92014-04-03 14:43:30 -070098 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080099 * This class also handles removing links that are associated to switch ports
100 * that go down, and switches that are disconnected.
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800102 * Invariants:
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 * -portLinks and switchLinks will not contain empty Sets outside of
Ray Milkeyb41100a2014-04-10 10:42:15 -0700104 * critical sections.
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 * -portLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -0700106 * SwitchPortTuple matches the map key.
Ray Milkey269ffb92014-04-03 14:43:30 -0700107 * -switchLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -0700108 * SwitchPortTuple's id matches the switch id.
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 * -Each LinkTuple will be indexed into switchLinks for both
Ray Milkeyb41100a2014-04-10 10:42:15 -0700110 * src.id and dst.id, and portLinks for each src and dst.
111 * -The updates queue is only added to from within a held write lock.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800112 */
113@LogMessageCategory("Network Topology")
114public class LinkDiscoveryManager
Ray Milkey269ffb92014-04-03 14:43:30 -0700115 implements IOFMessageListener, IOFSwitchListener,
116 ILinkDiscoveryService, IFloodlightModule {
117 protected IFloodlightProviderService controller;
Ray Milkeyec838942014-04-09 11:28:43 -0700118 private static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800119
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800120 protected IFloodlightProviderService floodlightProvider;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800121 protected IThreadPoolService threadPool;
122 protected IRestApiService restApi;
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700123 // Registry Service for ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700124 protected IControllerRegistryService registryService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800125
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700126
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800127 // LLDP and BDDP fields
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800128 private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800129 HexString.fromHexString("01:80:c2:00:00:0e");
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 private static final long LINK_LOCAL_MASK = 0xfffffffffff0L;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800131 private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
132
133 // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
Masayoshi Kobayashi71137362013-07-12 15:54:52 -0700134 // private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01";
135 private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800136
137
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800138 // Direction TLVs are used to indicate if the LLDPs were sent
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800139 // periodically or in response to a recieved LLDP
140 private static final byte TLV_DIRECTION_TYPE = 0x73;
141 private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte
Ray Milkey45614c52014-04-07 16:30:54 -0700142 private static final byte[] TLV_DIRECTION_VALUE_FORWARD = {0x01};
143 private static final byte[] TLV_DIRECTION_VALUE_REVERSE = {0x02};
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700144 private static final LLDPTLV FORWARD_TLV
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 = new LLDPTLV().
146 setType(TLV_DIRECTION_TYPE).
147 setLength(TLV_DIRECTION_LENGTH).
148 setValue(TLV_DIRECTION_VALUE_FORWARD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800149
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700150 private static final LLDPTLV REVERSE_TLV
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 = new LLDPTLV().
152 setType(TLV_DIRECTION_TYPE).
153 setLength(TLV_DIRECTION_LENGTH).
154 setValue(TLV_DIRECTION_VALUE_REVERSE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800155
156 // Link discovery task details.
157 protected SingletonTask discoveryTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700158 protected static final int DISCOVERY_TASK_INTERVAL = 1;
159 protected static final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
160 protected static final int LLDP_TO_ALL_INTERVAL = 15; //original 15 seconds, aggressive 2 secs.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800161 protected long lldpClock = 0;
162 // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
163 // If we want to identify link failures faster, we could decrease this
164 // value to a small number, say 1 or 2 sec.
Ray Milkey2476cac2014-04-08 11:03:21 -0700165 protected static final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known links
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800166
167 protected LLDPTLV controllerTLV;
168 protected ReentrantReadWriteLock lock;
169 int lldpTimeCount = 0;
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700170
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800171 /**
172 * Flag to indicate if automatic port fast is enabled or not.
173 * Default is set to false -- Initialized in the init method as well.
174 */
175 boolean autoPortFastFeature = false;
176
177 /**
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800178 * Map of remote switches that are not connected to this controller. This
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700179 * is used to learn remote switches in a distributed controller ONOS.
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800180 */
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -0700181 protected Map<Long, IOnosRemoteSwitch> remoteSwitches;
HIGUCHI Yuta3d96f652013-06-17 12:07:48 -0700182
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800183 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700184 * Map from link to the most recent time it was verified functioning.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800185 */
186 protected Map<Link, LinkInfo> links;
187
188 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700189 * Map from switch id to a set of all links with it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800190 */
191 protected Map<Long, Set<Link>> switchLinks;
192
193 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700194 * Map from a id:port to the set of links containing it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800195 */
196 protected Map<NodePortTuple, Set<Link>> portLinks;
197
198 /**
199 * Set of link tuples over which multicast LLDPs are received
200 * and unicast LLDPs are not received.
201 */
202 protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
203
204 protected volatile boolean shuttingDown = false;
205
Ray Milkeyb41100a2014-04-10 10:42:15 -0700206 /**
207 * Topology aware components are called in the order they were added to the
208 * the array.
209 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800210 protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800211
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700212 protected class LinkUpdate extends LDUpdate {
213
Ray Milkey269ffb92014-04-03 14:43:30 -0700214 public LinkUpdate(LDUpdate old) {
215 super(old);
216 }
217
218 @LogMessageDoc(level = "ERROR",
219 message = "Error in link discovery updates loop",
220 explanation = "An unknown error occured while dispatching " +
221 "link update notifications",
222 recommendation = LogMessageDoc.GENERIC_ACTION)
223 @Override
224 public void dispatch() {
225 if (linkDiscoveryAware != null) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800226 if (log.isTraceEnabled()) {
227 log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 new Object[]{this.getOperation(),
229 HexString.toHexString(this.getSrc()), this.getSrcPort(),
230 HexString.toHexString(this.getDst()), this.getDstPort(),
231 linkDiscoveryAware});
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800232 }
233 try {
234 for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
235 lda.linkDiscoveryUpdate(this);
236 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 } catch (Exception e) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800238 log.error("Error in link discovery updates loop", e);
239 }
240 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 }
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700242 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800243
244 /**
245 * List of ports through which LLDP/BDDPs are not sent.
246 */
247 protected Set<NodePortTuple> suppressLinkDiscovery;
248
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 /**
250 * A list of ports that are quarantined for discovering links through
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800251 * them. Data traffic from these ports are not allowed until the ports
252 * are released from quarantine.
253 */
254 protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
255 protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
256 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700257 * Quarantine task.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800258 */
Jonathan Hart299d1132014-06-27 09:25:28 -0700259 //protected SingletonTask bddpTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700260 protected static final int BDDP_TASK_INTERVAL = 100; // 100 ms.
261 protected static final int BDDP_TASK_SIZE = 5; // # of ports per iteration
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800262
263 /**
264 * Map of broadcast domain ports and the last time a BDDP was either
265 * sent or received on that port.
266 */
267 protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap;
268
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800269 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800270 * Get the LLDP sending period in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800272 * @return LLDP sending period in seconds.
273 */
274 public int getLldpFrequency() {
275 return LLDP_TO_KNOWN_INTERVAL;
276 }
277
278 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700279 * Get the LLDP timeout value in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800281 * @return LLDP timeout value in seconds
282 */
283 public int getLldpTimeout() {
284 return LINK_TIMEOUT;
285 }
286
287 public Map<NodePortTuple, Set<Link>> getPortLinks() {
288 return portLinks;
289 }
290
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800291 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800292 public Set<NodePortTuple> getSuppressLLDPsInfo() {
293 return suppressLinkDiscovery;
294 }
295
296 /**
297 * Add a switch port to the suppressed LLDP list.
298 * Remove any known links on the switch port.
299 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800300 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700301 public void addToSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800302 NodePortTuple npt = new NodePortTuple(sw, port);
303 this.suppressLinkDiscovery.add(npt);
304 deleteLinksOnPort(npt, "LLDP suppressed.");
305 }
306
307 /**
308 * Remove a switch port from the suppressed LLDP list.
309 * Discover links on that switchport.
310 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800311 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700312 public void removeFromSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800313 NodePortTuple npt = new NodePortTuple(sw, port);
314 this.suppressLinkDiscovery.remove(npt);
315 discover(npt);
316 }
317
318 public boolean isShuttingDown() {
319 return shuttingDown;
320 }
321
322 public boolean isFastPort(long sw, short port) {
323 return false;
324 }
325
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800326 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800327 public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
328 if (info.getUnicastValidTime() != null) {
329 return ILinkDiscovery.LinkType.DIRECT_LINK;
330 } else if (info.getMulticastValidTime() != null) {
331 return ILinkDiscovery.LinkType.MULTIHOP_LINK;
332 }
333 return ILinkDiscovery.LinkType.INVALID_LINK;
334 }
335
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800336
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800337 private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
338 return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
339 }
340
341 protected void discoverLinks() {
342
343 // timeout known links.
344 timeoutLinks();
345
346 //increment LLDP clock
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800348
349 if (lldpClock == 0) {
350 log.debug("Sending LLDP out on all ports.");
351 discoverOnAllPorts();
352 }
353 }
354
355
356 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 * Quarantine Ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800358 */
Jonathan Hart299d1132014-06-27 09:25:28 -0700359 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800360 protected class QuarantineWorker implements Runnable {
361 @Override
362 public void run() {
363 try {
364 processBDDPLists();
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 } catch (Exception e) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800366 log.error("Error in quarantine worker thread", e);
367 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700368 bddpTask.reschedule(BDDP_TASK_INTERVAL,
369 TimeUnit.MILLISECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800370 }
371 }
372 }
Jonathan Hart299d1132014-06-27 09:25:28 -0700373 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800374
375 /**
376 * Add a switch port to the quarantine queue. Schedule the
377 * quarantine task if the quarantine queue was empty before adding
378 * this switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -0700379 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800380 * @param npt
381 */
382 protected void addToQuarantineQueue(NodePortTuple npt) {
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700383 if (!quarantineQueue.contains(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800384 quarantineQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700385 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800386 }
387
388 /**
389 * Remove a switch port from the quarantine queue.
390 */
391 protected void removeFromQuarantineQueue(NodePortTuple npt) {
392 // Remove all occurrences of the node port tuple from the list.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700393 boolean removedSomething;
394
395 do {
396 removedSomething = quarantineQueue.remove(npt);
397 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800398 }
399
400 /**
401 * Add a switch port to maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700402 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800403 * @param npt
404 */
405 protected void addToMaintenanceQueue(NodePortTuple npt) {
406 // TODO We are not checking if the switch port tuple is already
407 // in the maintenance list or not. This will be an issue for
408 // really large number of switch ports in the network.
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700409 if (!maintenanceQueue.contains(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800410 maintenanceQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700411 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800412 }
413
414 /**
415 * Remove a switch port from maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700416 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800417 * @param npt
418 */
419 protected void removeFromMaintenanceQueue(NodePortTuple npt) {
420 // Remove all occurrences of the node port tuple from the queue.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700421 boolean removedSomething;
422 do {
423 removedSomething = maintenanceQueue.remove(npt);
424 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800425 }
426
427 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700428 * This method processes the quarantine list in bursts. The task is
429 * at most once per BDDP_TASK_INTERVAL.
430 * One each call, BDDP_TASK_SIZE number of switch ports are processed.
431 * Once the BDDP packets are sent out through the switch ports, the ports
432 * are removed from the quarantine list.
433 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800434
435 protected void processBDDPLists() {
436 int count = 0;
437 Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
438
Ray Milkey269ffb92014-04-03 14:43:30 -0700439 while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800440 NodePortTuple npt;
441 npt = quarantineQueue.remove();
442 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
443 nptList.add(npt);
444 count++;
445 }
446
447 count = 0;
448 while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
449 NodePortTuple npt;
450 npt = maintenanceQueue.remove();
451 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
452 count++;
453 }
454
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 for (NodePortTuple npt : nptList) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800456 generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
457 }
458 }
459
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800460 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800461 public Set<Short> getQuarantinedPorts(long sw) {
462 Set<Short> qPorts = new HashSet<Short>();
463
464 Iterator<NodePortTuple> iter = quarantineQueue.iterator();
465 while (iter.hasNext()) {
466 NodePortTuple npt = iter.next();
467 if (npt.getNodeId() == sw) {
468 qPorts.add(npt.getPortId());
469 }
470 }
471 return qPorts;
472 }
473
474 private void generateSwitchPortStatusUpdate(long sw, short port) {
475 UpdateOperation operation;
476
477 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700478 if (iofSwitch == null) {
479 return;
480 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800481
482 OFPhysicalPort ofp = iofSwitch.getPort(port);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700483 if (ofp == null) {
484 return;
485 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800486
487 int srcPortState = ofp.getState();
488 boolean portUp = ((srcPortState &
489 OFPortState.OFPPS_STP_MASK.getValue()) !=
490 OFPortState.OFPPS_STP_BLOCK.getValue());
491
Ray Milkeyb29e6262014-04-09 16:02:14 -0700492 if (portUp) {
493 operation = UpdateOperation.PORT_UP;
494 } else {
495 operation = UpdateOperation.PORT_DOWN;
496 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800497
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700498 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800499
500
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700501 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800502 }
503
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800504 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700505 * Send LLDP on known ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800506 */
507 protected void discoverOnKnownLinkPorts() {
508 // Copy the port set.
509 Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
510 nptSet.addAll(portLinks.keySet());
511
512 // Send LLDP from each of them.
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 for (NodePortTuple npt : nptSet) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800514 discover(npt);
515 }
516 }
517
518 protected void discover(NodePortTuple npt) {
519 discover(npt.getNodeId(), npt.getPortId());
520 }
521
522 protected void discover(long sw, short port) {
523 sendDiscoveryMessage(sw, port, true, false);
524 }
525
526 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700527 * Learn remote switches when running as a distributed controller ONOS.
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800528 */
529 protected IOFSwitch addRemoteSwitch(long sw, short port) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 IOnosRemoteSwitch remotesw = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800531
Ray Milkey269ffb92014-04-03 14:43:30 -0700532 // add a switch if we have not seen it before
533 remotesw = remoteSwitches.get(sw);
Jonathan Harte7231052013-01-25 00:01:14 -0800534
Ray Milkey269ffb92014-04-03 14:43:30 -0700535 if (remotesw == null) {
536 remotesw = new OFSwitchImpl();
537 remotesw.setupRemoteSwitch(sw);
538 remoteSwitches.put(remotesw.getId(), remotesw);
539 log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800540 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800541
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800542 // add the port if we have not seen it before
Umesh Krishnaswamy68c118c2013-01-25 11:07:09 -0800543 if (remotesw.getPort(port) == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700544 OFPhysicalPort remoteport = new OFPhysicalPort();
545 remoteport.setPortNumber(port);
546 remoteport.setName("fake_" + port);
547 remoteport.setConfig(0);
548 remoteport.setState(0);
549 remotesw.setPort(remoteport);
550 log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw.getId());
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800551 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800552
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800553 return remotesw;
554 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800555
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800556 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800557 * Send link discovery message out of a given switch port.
558 * The discovery message may be a standard LLDP or a modified
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800559 * LLDP, where the dst mac address is set to :ff.
Ray Milkey269ffb92014-04-03 14:43:30 -0700560 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800561 * TODO: The modified LLDP will updated in the future and may
562 * use a different eth-type.
Ray Milkey269ffb92014-04-03 14:43:30 -0700563 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800564 * @param sw
565 * @param port
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 * @param isStandard indicates standard or modified LLDP
567 * @param isReverse indicates whether the LLDP was sent as a response
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800568 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700569 @LogMessageDoc(level = "ERROR",
570 message = "Failure sending LLDP out port {port} on switch {switch}",
571 explanation = "An I/O error occured while sending LLDP message " +
572 "to the switch.",
573 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800574 protected void sendDiscoveryMessage(long sw, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 boolean isStandard,
576 boolean isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800577
578 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
579 if (iofSwitch == null) {
580 return;
581 }
582
Ray Milkeyb29e6262014-04-09 16:02:14 -0700583 if (port == OFPort.OFPP_LOCAL.getValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800584 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700585 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800586
587 OFPhysicalPort ofpPort = iofSwitch.getPort(port);
588
589 if (ofpPort == null) {
590 if (log.isTraceEnabled()) {
591 log.trace("Null physical port. sw={}, port={}", sw, port);
592 }
593 return;
594 }
595
596 if (isLinkDiscoverySuppressed(sw, port)) {
597 /* Dont send LLDPs out of this port as suppressLLDPs set
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800598 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800599 */
600 return;
601 }
602
603 // For fast ports, do not send forward LLDPs or BDDPs.
Ray Milkeyb29e6262014-04-09 16:02:14 -0700604 if (!isReverse && autoPortFastFeature && isFastPort(sw, port)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800605 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700606 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800607
608 if (log.isTraceEnabled()) {
609 log.trace("Sending LLDP packet out of swich: {}, port: {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 sw, port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800611 }
612
Jonathan Hart299d1132014-06-27 09:25:28 -0700613 OFPacketOut po = createLLDPPacketOut(sw, ofpPort, isReverse);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800614
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800615 try {
616 iofSwitch.write(po, null);
617 iofSwitch.flush();
618 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700619 log.error("Failure sending LLDP out port " + port + " on switch " + iofSwitch.getStringId(), e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800620 }
621
622 }
623
624 /**
Jonathan Hart299d1132014-06-27 09:25:28 -0700625 * Creates packet_out LLDP for specified output port.
626 *
627 * @param dpid the dpid of the outgoing switch
628 * @param port the outgoing port
629 * @param isReverse whether this is a reverse LLDP or not
630 * @return Packet_out message with LLDP data
631 */
632 private OFPacketOut createLLDPPacketOut(long dpid,
633 final OFPhysicalPort port, boolean isReverse) {
634 // Set up packets
635 // TODO optimize by not creating new packets each time
636 OnosLldp lldpPacket = new OnosLldp();
637
638 Ethernet ethPacket = new Ethernet();
639 ethPacket.setEtherType(Ethernet.TYPE_LLDP);
640 ethPacket.setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING);
641 ethPacket.setPayload(lldpPacket);
642 ethPacket.setPad(true);
643
644 final OFPacketOut packetOut = (OFPacketOut) floodlightProvider.getOFMessageFactory()
645 .getMessage(OFType.PACKET_OUT);
646 packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
647
648 final List<OFAction> actionsList = new LinkedList<OFAction>();
649 final OFActionOutput out = (OFActionOutput) floodlightProvider.getOFMessageFactory()
650 .getAction(OFActionType.OUTPUT);
651 out.setPort(port.getPortNumber());
652 actionsList.add(out);
653 packetOut.setActions(actionsList);
654 final short alen = (short) OFActionOutput.MINIMUM_LENGTH;
655
656 lldpPacket.setSwitch(dpid);
657 lldpPacket.setPort(port.getPortNumber());
658 lldpPacket.setReverse(isReverse);
659 ethPacket.setSourceMACAddress(port.getHardwareAddress());
660
661 final byte[] lldp = ethPacket.serialize();
662 packetOut.setActionsLength(alen);
663 packetOut.setPacketData(lldp);
664 packetOut
665 .setLength((short) (OFPacketOut.MINIMUM_LENGTH + alen + lldp.length));
666 return packetOut;
667 }
668
669 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700670 * Send LLDPs to all switch-ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800671 */
672 protected void discoverOnAllPorts() {
673 if (log.isTraceEnabled()) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800674 log.trace("Sending LLDP packets out of all the enabled ports on switch");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800675 }
676 Set<Long> switches = floodlightProvider.getSwitches().keySet();
677 // Send standard LLDPs
Ray Milkey269ffb92014-04-03 14:43:30 -0700678 for (long sw : switches) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800679 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700680 if (iofSwitch == null) {
681 continue;
682 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800683 if (iofSwitch.getEnabledPorts() != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700684 for (OFPhysicalPort ofp : iofSwitch.getEnabledPorts()) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700685 if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800686 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700687 }
688 if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800689 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700690 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800691
692 // sends forward LLDP only non-fastports.
693 sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false);
694
695 // If the switch port is not alreayd in the maintenance
696 // queue, add it.
Jonathan Hart299d1132014-06-27 09:25:28 -0700697 //NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNumber());
698 //addToMaintenanceQueue(npt);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800699 }
700 }
701 }
702 }
703
704 protected void setControllerTLV() {
705 //Setting the controllerTLVValue based on current nano time,
706 //controller's IP address, and the network interface object hash
707 //the corresponding IP address.
708
709 final int prime = 7867;
710 InetAddress localIPAddress = null;
711 NetworkInterface localInterface = null;
712
Ray Milkey269ffb92014-04-03 14:43:30 -0700713 byte[] controllerTLVValue = new byte[]{0, 0, 0, 0, 0, 0, 0, 0}; // 8 byte value.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800714 ByteBuffer bb = ByteBuffer.allocate(10);
715
Ray Milkey269ffb92014-04-03 14:43:30 -0700716 try {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800717 localIPAddress = java.net.InetAddress.getLocalHost();
718 localInterface = NetworkInterface.getByInetAddress(localIPAddress);
719 } catch (Exception e) {
720 e.printStackTrace();
721 }
722
723 long result = System.nanoTime();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700724 if (localIPAddress != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800725 result = result * prime + IPv4.toIPv4Address(localIPAddress.getHostAddress());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700726 }
727 if (localInterface != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800728 result = result * prime + localInterface.hashCode();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700729 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800730 // set the first 4 bits to 0.
731 result = result & (0x0fffffffffffffffL);
732
733 bb.putLong(result);
734
735 bb.rewind();
736 bb.get(controllerTLVValue, 0, 8);
737
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700738 this.controllerTLV = new LLDPTLV()
739 .setType((byte) 0x0c)
740 .setLength((short) controllerTLVValue.length)
741 .setValue(controllerTLVValue);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800742 }
743
744 @Override
745 public String getName() {
746 return "linkdiscovery";
747 }
748
749 @Override
750 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
751 switch (msg.getType()) {
752 case PACKET_IN:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700753 if (msg instanceof OFPacketIn) {
754 return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
755 cntx);
756 }
757 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800758 case PORT_STATUS:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700759 if (msg instanceof OFPortStatus) {
760 return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
761 }
762 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800763 default:
764 break;
765 }
766 return Command.CONTINUE;
767 }
768
769 private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) {
770 // If LLDP is suppressed on this port, ignore received packet as well
771 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
772 if (iofSwitch == null) {
773 return Command.STOP;
774 }
775
Ray Milkeyb29e6262014-04-09 16:02:14 -0700776 if (isLinkDiscoverySuppressed(sw, pi.getInPort())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800777 return Command.STOP;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700778 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800779
780 // If this is a malformed LLDP, or not from us, exit
Ray Milkeyb29e6262014-04-09 16:02:14 -0700781 if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800782 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700783 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800784
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800785 // Verify this LLDP packet matches what we're looking for
Jonathan Hart299d1132014-06-27 09:25:28 -0700786 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800787 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
788 if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 &&
789 lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700790 lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800791 ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
792 remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800793 if (remoteSwitch == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700794 // Added by ONOS
795 // floodlight LLDP coming from a remote switch connected to a different controller
796 // add it to our cache of unconnected remote switches
797 remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800798 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700799 } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800800 otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700801 if (myId == otherId) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800802 myLLDP = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700803 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800804 } else if (lldptlv.getType() == TLV_DIRECTION_TYPE &&
805 lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700806 if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800807 isReverse = false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700808 } else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800809 isReverse = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700810 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800811 }
812 }
Jonathan Hart299d1132014-06-27 09:25:28 -0700813 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800814
Jonathan Hart299d1132014-06-27 09:25:28 -0700815 byte[] packetData = pi.getPacketData();
816 if (!OnosLldp.isOnosLldp(packetData)) {
817 log.trace("Dropping LLDP that wasn't sent by ONOS");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800818 return Command.STOP;
819 }
820
Jonathan Hart299d1132014-06-27 09:25:28 -0700821 SwitchPort switchPort = OnosLldp.extractSwitchPort(packetData);
822 long remoteDpid = switchPort.dpid().value();
823 short remotePort = switchPort.port().value();
824 IOFSwitch remoteSwitch = floodlightProvider.getSwitches().get(switchPort.dpid().value());
825
826
827 OFPhysicalPort physicalPort = null;
828 if (remoteSwitch != null) {
829 physicalPort = remoteSwitch.getPort(remotePort);
830 if (!remoteSwitch.portEnabled(remotePort)) {
831 if (log.isTraceEnabled()) {
832 log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
833 }
834 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800835 }
Jonathan Hart299d1132014-06-27 09:25:28 -0700836 if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(),
837 remotePort))) {
838 if (log.isTraceEnabled()) {
839 log.trace("Ignoring link with suppressed src port: switch {} port {}",
840 remoteSwitch, remotePort);
841 }
842 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800843 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800844 }
845 if (!iofSwitch.portEnabled(pi.getInPort())) {
846 if (log.isTraceEnabled()) {
847 log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
848 }
849 return Command.STOP;
850 }
851
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800852 int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
853 physicalPort = iofSwitch.getPort(pi.getInPort());
854 int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
855
856 // Store the time of update to this link, and push it out to routingEngine
Jonathan Hart299d1132014-06-27 09:25:28 -0700857 Link lt = new Link(remoteDpid, remotePort, iofSwitch.getId(), pi.getInPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800858
859
860 Long lastLldpTime = null;
861 Long lastBddpTime = null;
862
863 Long firstSeenTime = System.currentTimeMillis();
864
Ray Milkeyb29e6262014-04-09 16:02:14 -0700865 if (isStandard) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800866 lastLldpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700867 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800868 lastBddpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700869 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800870
871 LinkInfo newLinkInfo =
872 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700873 srcPortState, dstPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800874
875 addOrUpdateLink(lt, newLinkInfo);
876
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800877 // Check if reverse link exists.
878 // If it doesn't exist and if the forward link was seen
879 // first seen within a small interval, send probe on the
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800880 // reverse link.
881
Jonathan Hart299d1132014-06-27 09:25:28 -0700882 boolean isReverse = OnosLldp.isReverse(lldp);
883
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800884 newLinkInfo = links.get(lt);
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700885 if (newLinkInfo != null && isStandard && !isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800886 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700887 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800888 LinkInfo reverseInfo = links.get(reverseLink);
889 if (reverseInfo == null) {
890 // the reverse link does not exist.
891 if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) {
892 this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), isStandard, true);
893 }
894 }
895 }
896
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800897 // Consume this message
898 return Command.STOP;
899 }
900
901 protected Command handlePacketIn(long sw, OFPacketIn pi,
902 FloodlightContext cntx) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800903 Ethernet eth =
904 IFloodlightProviderService.bcStore.get(cntx,
Ray Milkey269ffb92014-04-03 14:43:30 -0700905 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800906
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 if (eth.getEtherType() == Ethernet.TYPE_BSN) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800908 BSN bsn = (BSN) eth.getPayload();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700909 if (bsn == null) {
910 return Command.STOP;
911 }
912 if (bsn.getPayload() == null) {
913 return Command.STOP;
914 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800915 // It could be a packet other than BSN LLDP, therefore
916 // continue with the regular processing.
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700917 if (!(bsn.getPayload() instanceof LLDP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800918 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700919 }
Ubuntu9cbb4ca2013-02-07 17:19:59 +0000920 return handleLldp((LLDP) bsn.getPayload(), sw, pi, false, cntx);
Ray Milkey269ffb92014-04-03 14:43:30 -0700921 } else if (eth.getEtherType() == Ethernet.TYPE_LLDP) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800922 return handleLldp((LLDP) eth.getPayload(), sw, pi, true, cntx);
923 } else if (eth.getEtherType() < 1500) {
924 long destMac = eth.getDestinationMAC().toLong();
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800926 if (log.isTraceEnabled()) {
927 log.trace("Ignoring packet addressed to 802.1D/Q " +
928 "reserved address.");
929 }
930 return Command.STOP;
931 }
932 }
933
934 // If packet-in is from a quarantine port, stop processing.
935 NodePortTuple npt = new NodePortTuple(sw, pi.getInPort());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700936 if (quarantineQueue.contains(npt)) {
937 return Command.STOP;
938 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800939
940 return Command.CONTINUE;
941 }
942
943 protected UpdateOperation getUpdateOperation(int srcPortState,
944 int dstPortState) {
945 boolean added =
946 (((srcPortState &
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 OFPortState.OFPPS_STP_MASK.getValue()) !=
948 OFPortState.OFPPS_STP_BLOCK.getValue()) &&
949 ((dstPortState &
950 OFPortState.OFPPS_STP_MASK.getValue()) !=
951 OFPortState.OFPPS_STP_BLOCK.getValue()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800952
Ray Milkeyb29e6262014-04-09 16:02:14 -0700953 if (added) {
954 return UpdateOperation.LINK_UPDATED;
955 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800956 return UpdateOperation.LINK_REMOVED;
957 }
958
959
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800960 protected UpdateOperation getUpdateOperation(int srcPortState) {
961 boolean portUp = ((srcPortState &
962 OFPortState.OFPPS_STP_MASK.getValue()) !=
963 OFPortState.OFPPS_STP_BLOCK.getValue());
964
Ray Milkeyb29e6262014-04-09 16:02:14 -0700965 if (portUp) {
966 return UpdateOperation.PORT_UP;
967 } else {
968 return UpdateOperation.PORT_DOWN;
969 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800970 }
971
972 protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
973
974 NodePortTuple srcNpt, dstNpt;
975 boolean linkChanged = false;
976
977 lock.writeLock().lock();
978 try {
979 // put the new info. if an old info exists, it will be returned.
980 LinkInfo oldInfo = links.put(lt, newInfo);
981 if (oldInfo != null &&
Ray Milkeyb29e6262014-04-09 16:02:14 -0700982 oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800983 newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700984 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800985
986 if (log.isTraceEnabled()) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800987 log.trace("addOrUpdateLink: {} {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700988 lt,
989 (newInfo.getMulticastValidTime() != null) ? "multicast" : "unicast");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800990 }
991
992 UpdateOperation updateOperation = null;
993 linkChanged = false;
994
995 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
996 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
997
998 if (oldInfo == null) {
999 // index it by switch source
Ray Milkeyb29e6262014-04-09 16:02:14 -07001000 if (!switchLinks.containsKey(lt.getSrc())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001001 switchLinks.put(lt.getSrc(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001002 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001003 switchLinks.get(lt.getSrc()).add(lt);
1004
1005 // index it by switch dest
Ray Milkeyb29e6262014-04-09 16:02:14 -07001006 if (!switchLinks.containsKey(lt.getDst())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001007 switchLinks.put(lt.getDst(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001008 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001009 switchLinks.get(lt.getDst()).add(lt);
1010
1011 // index both ends by switch:port
Ray Milkeyb29e6262014-04-09 16:02:14 -07001012 if (!portLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001013 portLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001014 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001015 portLinks.get(srcNpt).add(lt);
1016
Ray Milkeyb29e6262014-04-09 16:02:14 -07001017 if (!portLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001018 portLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001019 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001020 portLinks.get(dstNpt).add(lt);
1021
1022 // Add to portNOFLinks if the unicast valid time is null
Ray Milkeyb29e6262014-04-09 16:02:14 -07001023 if (newInfo.getUnicastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001024 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001025 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001026
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001027 // ONOS: Distinguish added event separately from updated event
Pankaj Berdea41016d2013-06-10 21:18:18 -07001028 updateOperation = UpdateOperation.LINK_ADDED;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001029 linkChanged = true;
1030
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001031 } else {
1032 // Since the link info is already there, we need to
1033 // update the right fields.
1034 if (newInfo.getUnicastValidTime() == null) {
1035 // This is due to a multicast LLDP, so copy the old unicast
1036 // value.
1037 if (oldInfo.getUnicastValidTime() != null) {
1038 newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
1039 }
1040 } else if (newInfo.getMulticastValidTime() == null) {
1041 // This is due to a unicast LLDP, so copy the old multicast
1042 // value.
1043 if (oldInfo.getMulticastValidTime() != null) {
1044 newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
1045 }
1046 }
1047
1048 Long oldTime = oldInfo.getUnicastValidTime();
1049 Long newTime = newInfo.getUnicastValidTime();
1050 // the link has changed its state between openflow and non-openflow
1051 // if the unicastValidTimes are null or not null
1052 if (oldTime != null & newTime == null) {
1053 // openflow -> non-openflow transition
1054 // we need to add the link tuple to the portNOFLinks
1055 addLinkToBroadcastDomain(lt);
1056 linkChanged = true;
1057 } else if (oldTime == null & newTime != null) {
1058 // non-openflow -> openflow transition
1059 // we need to remove the link from the portNOFLinks
1060 removeLinkFromBroadcastDomain(lt);
1061 linkChanged = true;
1062 }
1063
1064 // Only update the port states if they've changed
1065 if (newInfo.getSrcPortState().intValue() !=
1066 oldInfo.getSrcPortState().intValue() ||
1067 newInfo.getDstPortState().intValue() !=
Ray Milkeyb29e6262014-04-09 16:02:14 -07001068 oldInfo.getDstPortState().intValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001069 linkChanged = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001070 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001071
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001072 if (linkChanged) {
1073 updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001074 newInfo.getDstPortState());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001075 if (log.isTraceEnabled()) {
1076 log.trace("Updated link {}", lt);
1077 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001078 }
1079 }
1080
1081 if (linkChanged) {
1082 // find out if the link was added or removed here.
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001083 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001084 lt.getDst(), lt.getDstPort(),
1085 getLinkType(lt, newInfo),
1086 updateOperation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001087 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001088 }
1089 } finally {
1090 lock.writeLock().unlock();
1091 }
1092
1093 return linkChanged;
1094 }
1095
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001096 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001097 public Map<Long, Set<Link>> getSwitchLinks() {
1098 return this.switchLinks;
1099 }
1100
1101 /**
1102 * Removes links from memory and storage.
Ray Milkey269ffb92014-04-03 14:43:30 -07001103 *
Ray Milkey5df613b2014-04-15 10:50:56 -07001104 * @param linksToDelete The List of @LinkTuple to delete.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001105 */
Ray Milkey5df613b2014-04-15 10:50:56 -07001106 protected void deleteLinks(List<Link> linksToDelete, String reason) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001107 NodePortTuple srcNpt, dstNpt;
1108
1109 lock.writeLock().lock();
1110 try {
Ray Milkey5df613b2014-04-15 10:50:56 -07001111 for (Link lt : linksToDelete) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001112 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001113 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001114
1115 switchLinks.get(lt.getSrc()).remove(lt);
1116 switchLinks.get(lt.getDst()).remove(lt);
1117 if (switchLinks.containsKey(lt.getSrc()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001118 switchLinks.get(lt.getSrc()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001119 this.switchLinks.remove(lt.getSrc());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001120 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001121 if (this.switchLinks.containsKey(lt.getDst()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001122 this.switchLinks.get(lt.getDst()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001123 this.switchLinks.remove(lt.getDst());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001124 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001125
1126 if (this.portLinks.get(srcNpt) != null) {
1127 this.portLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001128 if (this.portLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001129 this.portLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001130 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001131 }
1132 if (this.portLinks.get(dstNpt) != null) {
1133 this.portLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001134 if (this.portLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001135 this.portLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001136 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001137 }
1138
1139 LinkInfo info = this.links.remove(lt);
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001140 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001141 lt.getDst(), lt.getDstPort(),
1142 getLinkType(lt, info),
1143 UpdateOperation.LINK_REMOVED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001144 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001145
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001146 // TODO Whenever link is removed, it has to checked if
1147 // the switchports must be added to quarantine.
1148
1149 if (log.isTraceEnabled()) {
1150 log.trace("Deleted link {}", lt);
1151 }
1152 }
1153 } finally {
1154 lock.writeLock().unlock();
1155 }
1156 }
1157
1158 /**
1159 * Handles an OFPortStatus message from a switch. We will add or
1160 * delete LinkTupes as well re-compute the topology if needed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001162 * @param sw The IOFSwitch that sent the port status message
1163 * @param ps The OFPortStatus message
1164 * @return The Command to continue or stop after we process this message
1165 */
1166 protected Command handlePortStatus(long sw, OFPortStatus ps) {
1167
1168 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001169 if (iofSwitch == null) {
1170 return Command.CONTINUE;
1171 }
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001172
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001173 // ONOS: If we do not control this switch, then we should not process its port status messages
Ray Milkeyb29e6262014-04-09 16:02:14 -07001174 if (!registryService.hasControl(iofSwitch.getId())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001175 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001176 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001177
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001178 if (log.isTraceEnabled()) {
1179 log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
1180 "config is {} state is {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001181 new Object[]{iofSwitch.getStringId(),
1182 ps.getDesc().getPortNumber(),
1183 ps.getReason(),
1184 ps.getDesc().getConfig(),
1185 ps.getDesc().getState()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001186 }
1187
1188 short port = ps.getDesc().getPortNumber();
1189 NodePortTuple npt = new NodePortTuple(sw, port);
Ray Milkey269ffb92014-04-03 14:43:30 -07001190 boolean linkDeleted = false;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001191 boolean linkInfoChanged = false;
1192
1193 lock.writeLock().lock();
1194 try {
1195 // if ps is a delete, or a modify where the port is down or
1196 // configured down
Ray Milkey269ffb92014-04-03 14:43:30 -07001197 if ((byte) OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
1198 ((byte) OFPortReason.OFPPR_MODIFY.ordinal() ==
1199 ps.getReason() && !portEnabled(ps.getDesc()))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001200 deleteLinksOnPort(npt, "Port Status Changed");
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001201 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, UpdateOperation.PORT_DOWN));
1202 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001203 linkDeleted = true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001204 } else if (ps.getReason() ==
1205 (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001206 // If ps is a port modification and the port state has changed
1207 // that affects links in the topology
1208
1209 if (this.portLinks.containsKey(npt)) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001210 for (Link lt : this.portLinks.get(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001211 LinkInfo linkInfo = links.get(lt);
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 assert (linkInfo != null);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001213 Integer updatedSrcPortState = null;
1214 Integer updatedDstPortState = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001215 if (lt.getSrc() == npt.getNodeId() &&
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001216 lt.getSrcPort() == npt.getPortId() &&
1217 (linkInfo.getSrcPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001218 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001219 updatedSrcPortState = ps.getDesc().getState();
1220 linkInfo.setSrcPortState(updatedSrcPortState);
1221 }
1222 if (lt.getDst() == npt.getNodeId() &&
1223 lt.getDstPort() == npt.getPortId() &&
1224 (linkInfo.getDstPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001225 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001226 updatedDstPortState = ps.getDesc().getState();
1227 linkInfo.setDstPortState(updatedDstPortState);
1228 }
1229 if ((updatedSrcPortState != null) ||
1230 (updatedDstPortState != null)) {
1231 // The link is already known to link discovery
1232 // manager and the status has changed, therefore
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001233 // send an LinkUpdate.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001234 UpdateOperation operation =
1235 getUpdateOperation(linkInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001236 linkInfo.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001237 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001238 lt.getDst(), lt.getDstPort(),
1239 getLinkType(lt, linkInfo),
1240 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001241 controller.publishUpdate(update);
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001242
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001243 linkInfoChanged = true;
1244 }
1245 }
1246 }
1247
1248 UpdateOperation operation =
1249 getUpdateOperation(ps.getDesc().getState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001250 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
1251 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001252 }
1253
Ray Milkey269ffb92014-04-03 14:43:30 -07001254 if (!linkDeleted && !linkInfoChanged) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001255 if (log.isTraceEnabled()) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001256 log.trace("handlePortStatus: Switch {} port #{} reason {};" +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001257 " no links to update/remove",
Ray Milkey269ffb92014-04-03 14:43:30 -07001258 new Object[]{HexString.toHexString(sw),
1259 ps.getDesc().getPortNumber(),
1260 ps.getReason()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001261 }
1262 }
1263 } finally {
1264 lock.writeLock().unlock();
1265 }
1266
1267 if (!linkDeleted) {
1268 // Send LLDP right away when port state is changed for faster
1269 // cluster-merge. If it is a link delete then there is not need
1270 // to send the LLDPs right away and instead we wait for the LLDPs
1271 // to be sent on the timer as it is normally done
1272 // do it outside the write-lock
1273 // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
1274 processNewPort(npt.getNodeId(), npt.getPortId());
1275 }
1276 return Command.CONTINUE;
1277 }
1278
1279 /**
1280 * Process a new port.
1281 * If link discovery is disabled on the port, then do nothing.
1282 * If autoportfast feature is enabled and the port is a fast port, then
1283 * do nothing.
1284 * Otherwise, send LLDP message. Add the port to quarantine.
Ray Milkey269ffb92014-04-03 14:43:30 -07001285 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001286 * @param sw
1287 * @param p
1288 */
1289 private void processNewPort(long sw, short p) {
1290 if (isLinkDiscoverySuppressed(sw, p)) {
1291 // Do nothing as link discovery is suppressed.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001292 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001293 } else if (autoPortFastFeature && isFastPort(sw, p)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001294 // Do nothing as the port is a fast port.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001295 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001297 NodePortTuple npt = new NodePortTuple(sw, p);
1298 discover(sw, p);
1299 // if it is not a fast port, add it to quarantine.
1300 if (!isFastPort(sw, p)) {
1301 addToQuarantineQueue(npt);
1302 } else {
1303 // Add to maintenance queue to ensure that BDDP packets
1304 // are sent out.
1305 addToMaintenanceQueue(npt);
1306 }
1307 }
1308 }
1309
1310 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001311 * We send out LLDP messages when a switch is added to discover the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001312 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001313 * @param sw The IOFSwitch that connected to the controller
1314 */
1315 @Override
1316 public void addedSwitch(IOFSwitch sw) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001317 if (sw.getEnabledPorts() != null) {
1318 for (Short p : sw.getEnabledPortNumbers()) {
1319 processNewPort(sw.getId(), p);
1320 }
1321 }
Jonathan Hart6d208022014-06-24 18:56:36 -07001322
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001323 LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), null,
Ray Milkey269ffb92014-04-03 14:43:30 -07001324 UpdateOperation.SWITCH_UPDATED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001325 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001326 }
1327
1328 /**
1329 * When a switch disconnects we remove any links from our map and notify.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001330 */
1331 @Override
1332 public void removedSwitch(IOFSwitch iofSwitch) {
1333 // Update event history
1334 long sw = iofSwitch.getId();
Jonathan Hart6d208022014-06-24 18:56:36 -07001335
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001336 List<Link> eraseList = new ArrayList<Link>();
1337 lock.writeLock().lock();
1338 try {
1339 if (switchLinks.containsKey(sw)) {
1340 if (log.isTraceEnabled()) {
1341 log.trace("Handle switchRemoved. Switch {}; removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001342 HexString.toHexString(sw), switchLinks.get(sw));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001343 }
1344 // add all tuples with an endpoint on this switch to erase list
1345 eraseList.addAll(switchLinks.get(sw));
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001346 deleteLinks(eraseList, "Switch Removed");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001347
1348 // Send a switch removed update
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001349 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED));
1350 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001351 }
1352 } finally {
1353 lock.writeLock().unlock();
1354 }
1355 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001356
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001357 /**
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001358 * We don't react the port changed notifications here. we listen for
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001359 * OFPortStatus messages directly. Might consider using this notifier
1360 * instead
1361 */
1362 @Override
1363 public void switchPortChanged(Long switchId) {
1364 // no-op
1365 }
1366
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001367 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001368 * Delete links incident on a given switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -07001369 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001370 * @param npt
1371 * @param reason
1372 */
1373 protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
1374 List<Link> eraseList = new ArrayList<Link>();
1375 if (this.portLinks.containsKey(npt)) {
1376 if (log.isTraceEnabled()) {
1377 log.trace("handlePortStatus: Switch {} port #{} " +
1378 "removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001379 new Object[]{HexString.toHexString(npt.getNodeId()),
1380 npt.getPortId(),
1381 this.portLinks.get(npt)});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001382 }
1383 eraseList.addAll(this.portLinks.get(npt));
1384 deleteLinks(eraseList, reason);
1385 }
1386 }
1387
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001388 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001389 * Iterates through the list of links and deletes if the
1390 * last discovery message reception time exceeds timeout values.
1391 */
1392 protected void timeoutLinks() {
1393 List<Link> eraseList = new ArrayList<Link>();
1394 Long curTime = System.currentTimeMillis();
1395 boolean linkChanged = false;
1396
1397 // reentrant required here because deleteLink also write locks
1398 lock.writeLock().lock();
1399 try {
1400 Iterator<Entry<Link, LinkInfo>> it =
1401 this.links.entrySet().iterator();
1402 while (it.hasNext()) {
1403 Entry<Link, LinkInfo> entry = it.next();
1404 Link lt = entry.getKey();
1405 LinkInfo info = entry.getValue();
1406
1407 // Timeout the unicast and multicast LLDP valid times
1408 // independently.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001409 if ((info.getUnicastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001410 (info.getUnicastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001411 info.setUnicastValidTime(null);
1412
Ray Milkeyb29e6262014-04-09 16:02:14 -07001413 if (info.getMulticastValidTime() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001414 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001415 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001416 // Note that even if mTime becomes null later on,
1417 // the link would be deleted, which would trigger updateClusters().
1418 linkChanged = true;
1419 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001420 if ((info.getMulticastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001421 (info.getMulticastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001422 info.setMulticastValidTime(null);
1423 // if uTime is not null, then link will remain as openflow
1424 // link. If uTime is null, it will be deleted. So, we
1425 // don't care about linkChanged flag here.
1426 removeLinkFromBroadcastDomain(lt);
1427 linkChanged = true;
1428 }
1429 // Add to the erase list only if the unicast
1430 // time is null.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001431 if (info.getUnicastValidTime() == null &&
Ray Milkey269ffb92014-04-03 14:43:30 -07001432 info.getMulticastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001433 eraseList.add(entry.getKey());
1434 } else if (linkChanged) {
1435 UpdateOperation operation;
1436 operation = getUpdateOperation(info.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001437 info.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001438 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001439 lt.getDst(), lt.getDstPort(),
1440 getLinkType(lt, info),
1441 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001442 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001443 }
1444 }
1445
1446 // if any link was deleted or any link was changed.
1447 if ((eraseList.size() > 0) || linkChanged) {
1448 deleteLinks(eraseList, "LLDP timeout");
1449 }
1450 } finally {
1451 lock.writeLock().unlock();
1452 }
1453 }
1454
1455 private boolean portEnabled(OFPhysicalPort port) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001456 if (port == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001457 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001458 }
1459 if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001460 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001461 }
1462 if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001463 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001464 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001465 // Port STP state doesn't work with multiple VLANs, so ignore it for now
1466 // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
1467 // return false;
1468 return true;
1469 }
1470
1471 public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
1472 return portBroadcastDomainLinks;
1473 }
1474
1475 @Override
1476 public Map<Link, LinkInfo> getLinks() {
1477 lock.readLock().lock();
1478 Map<Link, LinkInfo> result;
1479 try {
1480 result = new HashMap<Link, LinkInfo>(links);
1481 } finally {
1482 lock.readLock().unlock();
1483 }
1484 return result;
1485 }
1486
1487 protected void addLinkToBroadcastDomain(Link lt) {
1488
1489 NodePortTuple srcNpt, dstNpt;
1490 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1491 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1492
Ray Milkeyb29e6262014-04-09 16:02:14 -07001493 if (!portBroadcastDomainLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001494 portBroadcastDomainLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001495 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001496 portBroadcastDomainLinks.get(srcNpt).add(lt);
1497
Ray Milkeyb29e6262014-04-09 16:02:14 -07001498 if (!portBroadcastDomainLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001499 portBroadcastDomainLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001500 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001501 portBroadcastDomainLinks.get(dstNpt).add(lt);
1502 }
1503
1504 protected void removeLinkFromBroadcastDomain(Link lt) {
1505
1506 NodePortTuple srcNpt, dstNpt;
1507 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1508 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1509
1510 if (portBroadcastDomainLinks.containsKey(srcNpt)) {
1511 portBroadcastDomainLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001512 if (portBroadcastDomainLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001513 portBroadcastDomainLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001514 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001515 }
1516
1517 if (portBroadcastDomainLinks.containsKey(dstNpt)) {
1518 portBroadcastDomainLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001519 if (portBroadcastDomainLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001520 portBroadcastDomainLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001521 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001522 }
1523 }
1524
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001525 @Override
1526 public void addListener(ILinkDiscoveryListener listener) {
1527 linkDiscoveryAware.add(listener);
1528 }
1529
1530 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001531 * Register a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001532 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001533 * @param linkDiscoveryAwareComponent
1534 */
1535 public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1536 // TODO make this a copy on write set or lock it somehow
1537 this.linkDiscoveryAware.add(linkDiscoveryAwareComponent);
1538 }
1539
1540 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001541 * Deregister a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001542 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001543 * @param linkDiscoveryAwareComponent
1544 */
1545 public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1546 // TODO make this a copy on write set or lock it somehow
1547 this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent);
1548 }
1549
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001550 @Override
1551 public boolean isCallbackOrderingPrereq(OFType type, String name) {
1552 return false;
1553 }
1554
1555 @Override
1556 public boolean isCallbackOrderingPostreq(OFType type, String name) {
1557 return false;
1558 }
1559
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001560 // IFloodlightModule classes
1561
1562 @Override
1563 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001564 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001565 new ArrayList<Class<? extends IFloodlightService>>();
1566 l.add(ILinkDiscoveryService.class);
1567 //l.add(ITopologyService.class);
1568 return l;
1569 }
1570
1571 @Override
1572 public Map<Class<? extends IFloodlightService>, IFloodlightService>
1573 getServiceImpls() {
1574 Map<Class<? extends IFloodlightService>,
Ray Milkey269ffb92014-04-03 14:43:30 -07001575 IFloodlightService> m =
1576 new HashMap<Class<? extends IFloodlightService>,
1577 IFloodlightService>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001578 // We are the class that implements the service
1579 m.put(ILinkDiscoveryService.class, this);
1580 return m;
1581 }
1582
1583 @Override
1584 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001585 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001586 new ArrayList<Class<? extends IFloodlightService>>();
1587 l.add(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001588 l.add(IThreadPoolService.class);
1589 l.add(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001590 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001591 l.add(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001592 return l;
1593 }
1594
1595 @Override
1596 public void init(FloodlightModuleContext context)
1597 throws FloodlightModuleException {
1598 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001599 threadPool = context.getServiceImpl(IThreadPoolService.class);
1600 restApi = context.getServiceImpl(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001601 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001602 registryService = context.getServiceImpl(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001603
1604 // Set the autoportfast feature to false.
1605 this.autoPortFastFeature = false;
1606
1607 // We create this here because there is no ordering guarantee
1608 this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
1609 this.lock = new ReentrantReadWriteLock();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001610 this.links = new HashMap<Link, LinkInfo>();
1611 this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
1612 this.suppressLinkDiscovery =
1613 Collections.synchronizedSet(new HashSet<NodePortTuple>());
1614 this.portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
1615 this.switchLinks = new HashMap<Long, Set<Link>>();
1616 this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
1617 this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001618 // Added by ONOS
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -07001619 this.remoteSwitches = new HashMap<Long, IOnosRemoteSwitch>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001620 }
1621
1622 @Override
1623 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001624 @LogMessageDoc(level = "ERROR",
1625 message = "No storage source found.",
1626 explanation = "Storage source was not initialized; cannot initialize " +
1627 "link discovery.",
1628 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1629 @LogMessageDoc(level = "ERROR",
1630 message = "Error in installing listener for " +
1631 "switch config table {table}",
1632 explanation = "Failed to install storage notification for the " +
1633 "switch config table",
1634 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1635 @LogMessageDoc(level = "ERROR",
1636 message = "No storage source found.",
1637 explanation = "Storage source was not initialized; cannot initialize " +
1638 "link discovery.",
1639 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1640 @LogMessageDoc(level = "ERROR",
1641 message = "Exception in LLDP send timer.",
1642 explanation = "An unknown error occured while sending LLDP " +
1643 "messages to switches.",
1644 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001645 })
1646 public void startUp(FloodlightModuleContext context) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001647 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001648 controller =
1649 context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001650
1651 // To be started by the first switch connection
1652 discoveryTask = new SingletonTask(ses, new Runnable() {
1653 @Override
1654 public void run() {
1655 try {
1656 discoverLinks();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001657 } catch (Exception e) {
1658 log.error("Exception in LLDP send timer.", e);
1659 } finally {
1660 if (!shuttingDown) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001661 // Always reschedule link discovery if we're not
1662 // shutting down (no chance of SLAVE role now)
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001663 log.trace("Rescheduling discovery task");
1664 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
Ray Milkey269ffb92014-04-03 14:43:30 -07001665 TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001666 }
1667 }
1668 }
1669 });
1670
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001671 // Always reschedule link discovery as we are never in SLAVE role now
1672 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001673
1674 // Setup the BDDP task. It is invoked whenever switch port tuples
1675 // are added to the quarantine list.
Jonathan Hart299d1132014-06-27 09:25:28 -07001676 //bddpTask = new SingletonTask(ses, new QuarantineWorker());
1677 //bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001678
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001679
1680 // Register for the OpenFlow messages we want to receive
1681 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
1682 floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
1683 // Register for switch updates
1684 floodlightProvider.addOFSwitchListener(this);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001685 if (restApi != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001686 restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001687 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001688 setControllerTLV();
1689 }
1690
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001691 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001692 public boolean isAutoPortFastFeature() {
1693 return autoPortFastFeature;
1694 }
1695
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001696 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001697 public void setAutoPortFastFeature(boolean autoPortFastFeature) {
1698 this.autoPortFastFeature = autoPortFastFeature;
1699 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001700}