blob: 58384838ffc07a3a01bded653698900f538305ba [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08002
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -07003import java.nio.ByteBuffer;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavov24409672014-08-20 16:45:11 -07006import java.util.HashMap;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -07007import java.util.LinkedList;
Jonathan Hart369875b2014-02-13 10:00:31 -08008import java.util.List;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08009import java.util.Map;
Saurav Dasfb93c252014-08-18 20:40:13 -070010import java.util.Map.Entry;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070012import java.util.concurrent.ConcurrentHashMap;
13import java.util.concurrent.ConcurrentMap;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070014import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart369875b2014-02-13 10:00:31 -080015import java.util.concurrent.TimeUnit;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080016
17import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070018import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080019import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070020import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
21import net.floodlightcontroller.core.IOFSwitchListener;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080026import net.floodlightcontroller.core.util.SingletonTask;
27import net.floodlightcontroller.threadpool.IThreadPoolService;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070028import net.onrc.onos.api.batchoperation.BatchOperationEntry;
Saurav Dasfb93c252014-08-18 20:40:13 -070029import net.onrc.onos.core.configmanager.INetworkConfigService;
30import net.onrc.onos.core.configmanager.INetworkConfigService.LinkConfigStatus;
31import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
32import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070033import net.onrc.onos.core.datagrid.IDatagridService;
34import net.onrc.onos.core.datagrid.IEventChannel;
Jonathan Hart03102132014-07-01 23:22:04 -070035import net.onrc.onos.core.hostmanager.Host;
36import net.onrc.onos.core.hostmanager.IHostListener;
37import net.onrc.onos.core.hostmanager.IHostService;
Jonathan Hart23701d12014-04-03 10:45:48 -070038import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
39import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart284e70f2014-07-05 12:32:51 -070040import net.onrc.onos.core.linkdiscovery.Link;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070041import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070042import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070043import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070044import net.onrc.onos.core.util.Dpid;
Jonathan Hart8c802b42014-09-08 15:40:48 -070045import net.onrc.onos.core.util.LinkTuple;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070046import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -070047import net.onrc.onos.core.util.PortNumberUtils;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070048import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080049
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070050import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070051import org.projectfloodlight.openflow.protocol.OFPortDesc;
52import org.projectfloodlight.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080055
Jonathan Hart88770672014-04-02 18:08:30 -070056/**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070057 * Class for publishing topology-related events.
58 *
59 * The events are received from the discovery modules, reformatted and
60 * published to the other ONOS instances.
61 *
62 * TODO: Add a synchronization mechanism when publishing the events to
63 * preserve the ordering and to avoid mismatch in the local "published" state,
64 * because each of the caller (the discovery modules) might be running
65 * on a different thread.
Jonathan Hart88770672014-04-02 18:08:30 -070066 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070067public class TopologyPublisher implements IOFSwitchListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070068 ILinkDiscoveryListener,
69 IFloodlightModule,
Pavlin Radoslavov24409672014-08-20 16:45:11 -070070 IHostListener,
71 ITopologyPublisherService {
Jonathan Hart88770672014-04-02 18:08:30 -070072 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070073 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080074
Jonathan Hart88770672014-04-02 18:08:30 -070075 private IFloodlightProviderService floodlightProvider;
76 private ILinkDiscoveryService linkDiscovery;
77 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070078 private ITopologyService topologyService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070079 private IDatagridService datagridService;
Toshio Koide2f570c12014-02-06 16:55:32 -080080
Jonathan Hart03102132014-07-01 23:22:04 -070081 private IHostService hostService;
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -070082 private MutableTopology mutableTopology;
Saurav Dasfb93c252014-08-18 20:40:13 -070083 private INetworkConfigService networkConfigService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070084
Jonathan Hart88770672014-04-02 18:08:30 -070085 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
86 private boolean cleanupEnabled = true;
87 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
88 private SingletonTask cleanupTask;
Pavlin Radoslavov24409672014-08-20 16:45:11 -070089 private DelayedOperationsHandler delayedOperationsHandler =
90 new DelayedOperationsHandler();
Toshio Koide2f570c12014-02-06 16:55:32 -080091
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070092 private IEventChannel<byte[], TopologyEvent> eventChannel;
93
94 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070095 // Local state for keeping track of locally published events so we can
96 // cleanup properly when an entry is removed.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070097 //
98 // We keep all Port, (incoming) Link and Host events per Switch DPID:
99 // - If a switch goes down, we remove all corresponding Port, Link and
100 // Host events.
101 // - If a port on a switch goes down, we remove all corresponding Link
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700102 // and Host events attached to this port.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700103 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700104 // TODO: What to do if the Mastership changes?
105 // - Cleanup state from publishedFoo maps, but do not send REMOVE events?
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700106 //
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700107 private ConcurrentMap<Dpid, MastershipData> publishedMastershipDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700108 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700109 private ConcurrentMap<Dpid, SwitchData> publishedSwitchDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700110 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700111 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, PortData>>
112 publishedPortDataEntries = new ConcurrentHashMap<>();
113 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, LinkData>>
114 publishedLinkDataEntries = new ConcurrentHashMap<>();
115 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, HostData>>
116 publishedHostDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700117
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700118 private BlockingQueue<TopologyBatchOperation> delayedOperations =
119 new LinkedBlockingQueue<>();
120
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700121
Jonathan Hart369875b2014-02-13 10:00:31 -0800122 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700123 * Gets the ONOS Instance ID.
124 *
125 * @return the ONOS Instance ID.
126 */
127 private OnosInstanceId getOnosInstanceId() {
128 return registryService.getOnosInstanceId();
129 }
130
131 /**
132 * Cleanup old switches from the topology. Old switches are those which
133 * have no controller in the registry.
134 *
135 * TODO: The overall switch cleanup mechanism needs refactoring/redesign.
Jonathan Hart369875b2014-02-13 10:00:31 -0800136 */
137 private class SwitchCleanup implements ControlChangeCallback, Runnable {
138 @Override
139 public void run() {
140 String old = Thread.currentThread().getName();
141 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700142
Jonathan Hart369875b2014-02-13 10:00:31 -0800143 try {
Jonathan Hart88770672014-04-02 18:08:30 -0700144 if (log.isTraceEnabled()) {
145 log.trace("Running cleanup thread");
146 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800147 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -0800148 } finally {
149 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -0700150 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -0800151 Thread.currentThread().setName(old);
152 }
153 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700154
Jonathan Hart88770672014-04-02 18:08:30 -0700155 /**
156 * First half of the switch cleanup operation. This method will attempt
157 * to get control of any switch it sees without a controller via the
158 * registry.
159 */
Jonathan Hart369875b2014-02-13 10:00:31 -0800160 private void switchCleanup() {
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700161 Iterable<Switch> switches = mutableTopology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -0800162
Jonathan Hart88770672014-04-02 18:08:30 -0700163 if (log.isTraceEnabled()) {
164 log.trace("Checking for inactive switches");
165 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700166 // For each switch check if a controller exists in controller
167 // registry
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 for (Switch sw : switches) {
Praseed Balakrishnane82adc62014-08-04 10:59:24 -0700169 // FIXME How to handle case where Switch has never been
170 // registered to ZK
171 if (sw.getConfigState() == ConfigState.CONFIGURED) {
172 continue;
173 }
Jonathan Hart88770672014-04-02 18:08:30 -0700174 try {
175 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700176 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700177 if (controller == null) {
178 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700179 sw.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700180 registryService.requestControl(sw.getDpid().value(),
181 this);
Jonathan Hart88770672014-04-02 18:08:30 -0700182 }
183 } catch (RegistryException e) {
184 log.error("Caught RegistryException in cleanup thread", e);
185 }
186 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800187 }
188
Jonathan Hart88770672014-04-02 18:08:30 -0700189 /**
190 * Second half of the switch cleanup operation. If the registry grants
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700191 * control of a switch, we can be sure no other instance is writing
192 * this switch to the topology, so we can remove it now.
193 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700194 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700195 * @param hasControl whether we got control or not
196 */
197 @Override
198 public void controlChanged(long dpid, boolean hasControl) {
199 if (hasControl) {
200 log.debug("Got control to set switch {} INACTIVE",
201 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700202
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700203 SwitchData switchData = new SwitchData(new Dpid(dpid));
204 publishRemoveSwitchEvent(switchData);
Jonathan Hart88770672014-04-02 18:08:30 -0700205 registryService.releaseControl(dpid);
206 }
207 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800208 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800209
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700210 /**
211 * A class to deal with Topology Operations that couldn't be pushed
212 * to the Global Log writer, because they need to be delayed.
213 * For example, a link cannot be pushed before the switches on both
214 * ends are in the Global Log.
215 *
216 * TODO: This is an ugly hack that should go away: right now we have to
217 * keep trying periodically.
218 * TODO: Currently, we retry only ADD Link Events, everything else
219 * is thrown away.
220 */
221 private class DelayedOperationsHandler extends Thread {
222 private static final long RETRY_INTERVAL_MS = 10; // 10ms
223
224 @Override
225 public void run() {
226 List<TopologyBatchOperation> operations = new LinkedList<>();
227
228 this.setName("TopologyPublisher.DelayedOperationsHandler " +
229 this.getId());
230 //
231 // The main loop
232 //
233 while (true) {
234 try {
235 //
236 // Block-waiting for an operation to be added, sleep
237 // and try to publish it again.
238 //
239 TopologyBatchOperation firstTbo = delayedOperations.take();
240 Thread.sleep(RETRY_INTERVAL_MS);
241 operations.add(firstTbo);
242 delayedOperations.drainTo(operations);
243
244 // Retry only the appropriate operations
245 for (TopologyBatchOperation tbo : operations) {
246 for (BatchOperationEntry<
247 TopologyBatchOperation.Operator,
248 TopologyEvent> boe : tbo.getOperations()) {
249 TopologyBatchOperation.Operator oper =
250 boe.getOperator();
251 switch (oper) {
252 case ADD:
253 TopologyEvent topologyEvent = boe.getTarget();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700254 LinkData linkData =
255 topologyEvent.getLinkData();
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700256 //
257 // Test whether the Link Event still can be
258 // published.
259 // TODO: The implementation below has a bug:
260 // If it happens that the same Link Event was
261 // removed in the middle of checking, we might
262 // incorrectly publish it again from here.
263 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700264 if (linkData == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700265 break;
266 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700267 ConcurrentMap<ByteBuffer, LinkData>
268 linkDataEntries = publishedLinkDataEntries.get(
269 linkData.getDst().getDpid());
270 if (linkDataEntries == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700271 break;
272 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700273 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700274 break;
275 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700276 publishAddLinkEvent(linkData);
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700277 break;
278 case REMOVE:
279 break;
280 default:
281 log.error("Unknown Topology Batch Operation {}", oper);
282 break;
283 }
284 }
285 }
286 } catch (InterruptedException exception) {
287 log.debug("Exception processing delayed operations: ",
288 exception);
289 }
290 }
291 }
292 }
293
Jonathan Hart88770672014-04-02 18:08:30 -0700294 @Override
Jonathan Hart284e70f2014-07-05 12:32:51 -0700295 public void linkAdded(Link link) {
Jonathan Hart8c802b42014-09-08 15:40:48 -0700296 LinkTuple linkTuple = new LinkTuple(
297 new SwitchPort(link.getSrc(), link.getSrcPort()),
298 new SwitchPort(link.getDst(), link.getDstPort()));
299
300 LinkConfigStatus ret = networkConfigService.checkLinkConfig(linkTuple);
Saurav Dasfb93c252014-08-18 20:40:13 -0700301 if (ret.getConfigState() == NetworkConfigState.DENY) {
302 log.warn("Discovered {} denied by configuration. {} "
303 + "Not allowing it to proceed.", link, ret.getMsg());
304 return;
305 }
306
Jonathan Hart8c802b42014-09-08 15:40:48 -0700307 LinkData linkData = new LinkData(linkTuple);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700308
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700309 // FIXME should be merging, with existing attrs, etc..
310 // TODO define attr name as constant somewhere.
311 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700312 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700313 TopologyElement.TYPE_PACKET_LAYER);
Saurav Dasfb93c252014-08-18 20:40:13 -0700314 if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
315 Map<String, String> attr = ret.getLinkConfig().getPublishAttributes();
316 for (Entry<String, String> e : attr.entrySet()) {
317 linkData.createStringAttribute(e.getKey(), e.getValue());
318 }
319 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
320 ConfigState.CONFIGURED.toString());
321 } else {
322 linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
323 ConfigState.NOT_CONFIGURED.toString());
324 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700325 linkData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700326 AdminStatus.ACTIVE.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700327 linkData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700328
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700329 publishAddLinkEvent(linkData);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700330 }
331
332 @Override
333 public void linkRemoved(Link link) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700334 LinkData linkData = new LinkData(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700335 new SwitchPort(link.getSrc(), link.getSrcPort()),
336 new SwitchPort(link.getDst(), link.getDstPort()));
337
338 // FIXME should be merging, with existing attrs, etc..
339 // TODO define attr name as constant somewhere.
340 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700341 linkData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700342 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700343 linkData.freeze();
Jonathan Hart284e70f2014-07-05 12:32:51 -0700344
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700345 publishRemoveLinkEvent(linkData);
Jonathan Hart88770672014-04-02 18:08:30 -0700346 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800347
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700348 /* *****************
349 * IOFSwitchListener
350 * *****************/
351
Jonathan Hart88770672014-04-02 18:08:30 -0700352 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700353 public void switchActivatedMaster(long swId) {
354 IOFSwitch sw = floodlightProvider.getSwitch(swId);
355 final Dpid dpid = new Dpid(swId);
356 if (sw == null) {
357 log.warn("Added switch not available {} ", dpid);
358 return;
359 }
360
Saurav Dasfb93c252014-08-18 20:40:13 -0700361 SwitchConfigStatus ret = networkConfigService.checkSwitchConfig(dpid);
362 if (ret.getConfigState() == NetworkConfigState.DENY) {
363 log.warn("Activated switch {} denied by network configuration. {} "
364 + "Not allowing it to proceed.", dpid, ret.getMsg());
365 return;
366 }
367
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700368 controllerRoleChanged(dpid, Role.MASTER);
369
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700370 SwitchData switchData = new SwitchData(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700371 // FIXME should be merging, with existing attrs, etc..
372 // TODO define attr name as constant somewhere.
373 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700374 switchData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700375 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700376 switchData.createStringAttribute("ConnectedSince",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700377 sw.getConnectedSince().toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700378 switchData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700379 AdminStatus.ACTIVE.toString());
Saurav Dasfb93c252014-08-18 20:40:13 -0700380 if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
381 Map<String, String> attr = ret.getSwitchConfig().getPublishAttributes();
382 for (Entry<String, String> e : attr.entrySet()) {
383 switchData.createStringAttribute(e.getKey(), e.getValue());
384 }
385 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
386 ConfigState.CONFIGURED.toString());
387 } else {
388 switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
389 ConfigState.NOT_CONFIGURED.toString());
390 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700391 switchData.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700392 // The Port events
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700393 List<PortData> portDataEntries = new ArrayList<PortData>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700394 for (OFPortDesc port : sw.getPorts()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700395 PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700396 PortNumberUtils.openFlow(port));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700397 // FIXME should be merging, with existing attrs, etc..
398 // TODO define attr name as constant somewhere.
399 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700400 portData.createStringAttribute("name", port.getName());
401 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700402 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700403 portData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700404 ConfigState.NOT_CONFIGURED.toString());
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700405 portData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700406 AdminStatus.ACTIVE.toString());
407
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700408 portData.freeze();
409 portDataEntries.add(portData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700410 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700411 publishAddSwitchEvent(switchData, portDataEntries);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700412 }
413
414 @Override
415 public void switchActivatedEqual(long swId) {
416 final Dpid dpid = new Dpid(swId);
417 controllerRoleChanged(dpid, Role.EQUAL);
418 }
419
420 @Override
421 public void switchMasterToEqual(long swId) {
422 final Dpid dpid = new Dpid(swId);
423 controllerRoleChanged(dpid, Role.EQUAL);
424 }
425
426 @Override
427 public void switchEqualToMaster(long swId) {
428 // for now treat as switchActivatedMaster
429 switchActivatedMaster(swId);
430 }
431
432 @Override
433 public void switchDisconnected(long swId) {
434 final Dpid dpid = new Dpid(swId);
435
436 log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
437
438 Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
439
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700440 MastershipData mastershipData =
441 new MastershipData(dpid, getOnosInstanceId(), role);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700442 // FIXME should be merging, with existing attrs, etc..
443 // TODO define attr name as constant somewhere.
444 // TODO populate appropriate attributes.
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700445 mastershipData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700446 TopologyElement.TYPE_ALL_LAYERS);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700447 mastershipData.freeze();
448 publishRemoveSwitchMastershipEvent(mastershipData);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700449 }
450
451 @Override
452 public void switchPortChanged(long swId, OFPortDesc port,
453 PortChangeType changeType) {
454 switch (changeType) {
455 case ADD:
456 switchPortAdded(swId, port);
457 break;
458 case DELETE:
459 switchPortRemoved(swId, port);
460 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700461 case UP:
Pavlin Radoslavov7946c612014-08-13 15:06:00 -0700462 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
463 switchPortAdded(swId, port);
464 break;
465 case DOWN:
466 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
467 switchPortRemoved(swId, port);
468 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700469 case OTHER_UPDATE:
470 default:
471 // XXX S what is the right set of port change handlers?
472 log.debug("Topology publisher does not handle these port updates: {}",
473 changeType);
474 }
475 }
476
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700477 /**
478 * Prepares an event for adding a port on a switch.
479 *
480 * @param switchId the switch ID (DPID)
481 * @param port the port to add
482 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700483 private void switchPortAdded(long switchId, OFPortDesc port) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700484 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700485 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700486 PortNumberUtils.openFlow(port));
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700487 // FIXME should be merging, with existing attrs, etc..
488 // TODO define attr name as constant somewhere.
489 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700490 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700491 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700492 portData.createStringAttribute("name", port.getName());
493 portData.freeze();
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700494
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700495 publishAddPortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700496 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800497
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700498 /**
499 * Prepares an event for removing a port on a switch.
500 *
501 * @param switchId the switch ID (DPID)
502 * @param port the port to remove
503 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700504 private void switchPortRemoved(long switchId, OFPortDesc port) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700505 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700506
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700507 final PortData portData = new PortData(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700508 PortNumberUtils.openFlow(port));
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700509 // FIXME should be merging, with existing attrs, etc..
510 // TODO define attr name as constant somewhere.
511 // TODO populate appropriate attributes.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700512 portData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700513 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700514 portData.createStringAttribute("name", port.getName());
515 portData.freeze();
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700516
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700517 publishRemovePortEvent(portData);
Jonathan Hart88770672014-04-02 18:08:30 -0700518 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800519
Jonathan Hart88770672014-04-02 18:08:30 -0700520 @Override
Jonathan Hart88770672014-04-02 18:08:30 -0700521 public String getName() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700522 return "topologyPublisher";
Jonathan Hart88770672014-04-02 18:08:30 -0700523 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800524
Jonathan Hart88770672014-04-02 18:08:30 -0700525 /* *****************
526 * IFloodlightModule
527 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800528
Jonathan Hart88770672014-04-02 18:08:30 -0700529 @Override
530 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700531 List<Class<? extends IFloodlightService>> services =
532 new ArrayList<Class<? extends IFloodlightService>>();
533 services.add(ITopologyPublisherService.class);
534 return services;
Jonathan Hart88770672014-04-02 18:08:30 -0700535 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800536
Jonathan Hart88770672014-04-02 18:08:30 -0700537 @Override
538 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700539 getServiceImpls() {
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700540 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
541 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
542 impls.put(ITopologyPublisherService.class, this);
543 return impls;
Jonathan Hart88770672014-04-02 18:08:30 -0700544 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800545
Jonathan Hart88770672014-04-02 18:08:30 -0700546 @Override
547 public Collection<Class<? extends IFloodlightService>>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700548 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700549 Collection<Class<? extends IFloodlightService>> l =
550 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800551 l.add(IFloodlightProviderService.class);
552 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800553 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800554 l.add(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700555 l.add(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700556 l.add(ITopologyService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700557 l.add(IHostService.class);
Saurav Dasfb93c252014-08-18 20:40:13 -0700558 l.add(INetworkConfigService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800559 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700560 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800561
Jonathan Hart88770672014-04-02 18:08:30 -0700562 @Override
563 public void init(FloodlightModuleContext context)
564 throws FloodlightModuleException {
565 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
566 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
567 registryService = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700568 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700569 hostService = context.getServiceImpl(IHostService.class);
Saurav Dasfb93c252014-08-18 20:40:13 -0700570 networkConfigService = context.getServiceImpl(INetworkConfigService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700571 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700572 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800573
Jonathan Hart88770672014-04-02 18:08:30 -0700574 @Override
575 public void startUp(FloodlightModuleContext context) {
576 floodlightProvider.addOFSwitchListener(this);
577 linkDiscovery.addListener(this);
Jonathan Hart03102132014-07-01 23:22:04 -0700578 hostService.addHostListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800579
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700580 eventChannel = datagridService.createChannel(
581 TopologyManager.EVENT_CHANNEL_NAME,
582 byte[].class,
583 TopologyEvent.class);
584
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700585 mutableTopology = topologyService.getTopology();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700586
Jonathan Hart88770672014-04-02 18:08:30 -0700587 // Run the cleanup thread
588 String enableCleanup =
589 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
590 if (enableCleanup != null
591 && enableCleanup.equalsIgnoreCase("false")) {
592 cleanupEnabled = false;
593 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700594
Jonathan Hart88770672014-04-02 18:08:30 -0700595 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700596
Jonathan Hart88770672014-04-02 18:08:30 -0700597 if (cleanupEnabled) {
598 IThreadPoolService threadPool =
599 context.getServiceImpl(IThreadPoolService.class);
600 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
601 new SwitchCleanup());
602 // Run the cleanup task immediately on startup
603 cleanupTask.reschedule(0, TimeUnit.SECONDS);
604 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700605
606 // Run the Delayed Operations Handler thread
607 delayedOperationsHandler.start();
Jonathan Hart88770672014-04-02 18:08:30 -0700608 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700609
Jonathan Hart88770672014-04-02 18:08:30 -0700610 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700611 public void hostAdded(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700612 log.debug("Host added with MAC {}", host.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700613
Jonathan Hart03102132014-07-01 23:22:04 -0700614 SwitchPort sp = new SwitchPort(host.getSwitchDPID(), host.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700615 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
616 spLists.add(sp);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700617 HostData hostData = new HostData(host.getMacAddress());
618 hostData.setAttachmentPoints(spLists);
619 hostData.setLastSeenTime(host.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700620 // Does not use vlan info now.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700621 hostData.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700622
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700623 publishAddHostEvent(hostData);
Jonathan Hart88770672014-04-02 18:08:30 -0700624 }
TeruUd1c5b652014-03-24 13:58:46 -0700625
Jonathan Hart88770672014-04-02 18:08:30 -0700626 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700627 public void hostRemoved(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700628 log.debug("Host removed with MAC {}", host.getMacAddress());
629
630 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700631 // Remove all previously added HostData for this MAC address
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700632 //
633 // TODO: Currently, the caller of hostRemoved() might not include
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700634 // the correct set of Attachment Points in the HostData entry itself.
635 // Also, we might have multiple HostData entries for the same
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700636 // host (MAC address), each containing a single (different) Attachment
637 // Point.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700638 // Hence, here we have to cleanup all HostData entries for this
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700639 // particular host, based on its MAC address.
640 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700641 List<HostData> removeHostDataEntries = new LinkedList<>();
642 for (ConcurrentMap<ByteBuffer, HostData> cm : publishedHostDataEntries.values()) {
643 for (HostData hostData : cm.values()) {
644 if (hostData.getMac().equals(host.getMacAddress())) {
645 removeHostDataEntries.add(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700646 }
647 }
648 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700649 for (HostData hostData : removeHostDataEntries) {
650 publishRemoveHostEvent(hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700651 }
Jonathan Hart88770672014-04-02 18:08:30 -0700652 }
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700653
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700654 @Override
655 public boolean publish(TopologyBatchOperation tbo) {
656 publishTopologyOperations(tbo);
657 return true;
658 }
659
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700660 /**
661 * Prepares the Controller role changed event for a switch.
662 *
663 * @param dpid the switch DPID
664 * @param role the new role of the controller
665 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700666 private void controllerRoleChanged(Dpid dpid, Role role) {
667 log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
668 dpid, role);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700669 MastershipData mastershipData =
670 new MastershipData(dpid, getOnosInstanceId(), role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700671 // FIXME should be merging, with existing attrs, etc..
672 // TODO define attr name as constant somewhere.
673 // TODO populate appropriate attributes.
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700674 mastershipData.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700675 TopologyElement.TYPE_ALL_LAYERS);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700676 mastershipData.freeze();
677 publishAddSwitchMastershipEvent(mastershipData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700678 }
679
680 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700681 * Publishes ADD Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700682 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700683 * @param mastershipData the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700684 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700685 private void publishAddSwitchMastershipEvent(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700686 MastershipData mastershipData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700687 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700688 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700689 TopologyEvent topologyEvent =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700690 new TopologyEvent(mastershipData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700691 tbo.appendAddOperation(topologyEvent);
692 publishTopologyOperations(tbo);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700693 publishedMastershipDataEntries.put(mastershipData.getDpid(),
694 mastershipData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700695 }
696
697 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700698 * Publishes REMOVE Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700699 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700700 * @param mastershipData the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700701 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700702 private void publishRemoveSwitchMastershipEvent(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700703 MastershipData mastershipData) {
704 if (publishedMastershipDataEntries.get(mastershipData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700705 return; // Nothing to do
706 }
707
708 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700709 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700710 TopologyEvent topologyEvent =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700711 new TopologyEvent(mastershipData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700712 tbo.appendRemoveOperation(topologyEvent);
713 publishTopologyOperations(tbo);
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700714 publishedMastershipDataEntries.remove(mastershipData.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700715 }
716
717 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700718 * Publishes ADD Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700719 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700720 * @param switchData the switch event to publish
721 * @param portDataEntries the corresponding port events for the switch to
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700722 * publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700723 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700724 private void publishAddSwitchEvent(SwitchData switchData,
725 Collection<PortData> portDataEntries) {
726 if (!registryService.hasControl(switchData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700727 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700728 switchData.getOriginDpid(), switchData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700729 return;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700730 }
731
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700732 // Keep track of the old Port Events that should be removed
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700733 ConcurrentMap<ByteBuffer, PortData> oldPortDataEntries =
734 publishedPortDataEntries.get(switchData.getDpid());
735 if (oldPortDataEntries == null) {
736 oldPortDataEntries = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700737 }
738
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700739 // Publish the information for the switch
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700740 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700741 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700742 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700743 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700744
745 // Publish the information for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700746 ConcurrentMap<ByteBuffer, PortData> newPortDataEntries =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700747 new ConcurrentHashMap<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700748 for (PortData portData : portDataEntries) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700749 topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700750 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700751 tbo.appendAddOperation(topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700752
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700753 ByteBuffer id = portData.getIDasByteBuffer();
754 newPortDataEntries.put(id, portData);
755 oldPortDataEntries.remove(id);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700756 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700757 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700758 publishedSwitchDataEntries.put(switchData.getDpid(), switchData);
759 publishedPortDataEntries.put(switchData.getDpid(), newPortDataEntries);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700760
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700761 // Cleanup for each of the old removed port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700762 for (PortData portData : oldPortDataEntries.values()) {
763 publishRemovePortEvent(portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700764 }
765 }
766
767 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700768 * Publishes REMOVE Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700769 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700770 * @param switchData the switch event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700771 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700772 private void publishRemoveSwitchEvent(SwitchData switchData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700773 //
774 // TODO: Removed the check for now, because currently this method is
775 // also called by the SwitchCleanup thread, and in that case
776 // the Switch Event was published by some other ONOS instance.
777 //
778 /*
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700779 if (publishedSwitchDataEntries.get(switchData.getDpid()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700780 return; // Nothing to do
781 }
782 */
783
784 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700785 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700786 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700787 new TopologyEvent(switchData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700788 tbo.appendRemoveOperation(topologyEvent);
789 publishTopologyOperations(tbo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700790 publishedSwitchDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700791
792 // Cleanup for each port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700793 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
794 publishedPortDataEntries.get(switchData.getDpid());
795 if (portDataEntries != null) {
796 for (PortData portData : portDataEntries.values()) {
797 publishRemovePortEvent(portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700798 }
799 }
800
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700801 publishedPortDataEntries.remove(switchData.getDpid());
802 publishedLinkDataEntries.remove(switchData.getDpid());
803 publishedHostDataEntries.remove(switchData.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700804 }
805
806 /**
807 * Publishes ADD Port Event.
808 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700809 * @param portData the port event to publish
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700810 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700811 private void publishAddPortEvent(PortData portData) {
812 if (!registryService.hasControl(portData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700813 log.debug("Not the master for switch {}. Suppressed port add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700814 portData.getOriginDpid(), portData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700815 return;
816 }
817
818 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700819 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700820 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700821 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700822 tbo.appendAddOperation(topologyEvent);
823 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700824
825 // Store the new Port Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700826 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
827 ConcurrentUtils.putIfAbsent(publishedPortDataEntries,
828 portData.getDpid(),
829 new ConcurrentHashMap<ByteBuffer, PortData>());
830 portDataEntries.put(portData.getIDasByteBuffer(), portData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700831 }
832
833 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700834 * Publishes REMOVE Port Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700835 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700836 * @param portData the port event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700837 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700838 private void publishRemovePortEvent(PortData portData) {
839 ConcurrentMap<ByteBuffer, PortData> portDataEntries =
840 publishedPortDataEntries.get(portData.getDpid());
841 if (portDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700842 return; // Nothing to do
843 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700844 if (portDataEntries.get(portData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700845 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700846 }
847
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700848 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700849 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700850 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700851 new TopologyEvent(portData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700852 tbo.appendRemoveOperation(topologyEvent);
853 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700854
855 // Cleanup for the incoming link(s)
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700856 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
857 publishedLinkDataEntries.get(portData.getDpid());
858 if (linkDataEntries != null) {
859 for (LinkData linkData : linkDataEntries.values()) {
860 if (linkData.getDst().equals(portData.getSwitchPort())) {
861 publishRemoveLinkEvent(linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700862 }
863 }
864 }
865
866 // Cleanup for the connected hosts
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700867 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
868 publishedHostDataEntries.get(portData.getDpid());
869 if (hostDataEntries != null) {
870 for (HostData hostData : hostDataEntries.values()) {
871 for (SwitchPort swp : hostData.getAttachmentPoints()) {
872 if (swp.equals(portData.getSwitchPort())) {
873 publishRemoveHostEvent(hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700874 }
875 }
876 }
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700877 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700878
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700879 portDataEntries.remove(portData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700880 }
881
882 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700883 * Publishes ADD Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700884 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700885 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700886 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700887 private void publishAddLinkEvent(LinkData linkData) {
888 if (!registryService.hasControl(linkData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700889 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700890 linkData.getOriginDpid(), linkData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700891 return;
892 }
893
894 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700895 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700896 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700897 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700898 tbo.appendAddOperation(topologyEvent);
899 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700900
901 // Store the new Link Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700902 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
903 ConcurrentUtils.putIfAbsent(publishedLinkDataEntries,
904 linkData.getDst().getDpid(),
905 new ConcurrentHashMap<ByteBuffer, LinkData>());
906 linkDataEntries.put(linkData.getIDasByteBuffer(), linkData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700907 }
908
909 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700910 * Publishes REMOVE Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700911 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700912 * @param linkData the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700913 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700914 private void publishRemoveLinkEvent(LinkData linkData) {
915 ConcurrentMap<ByteBuffer, LinkData> linkDataEntries =
916 publishedLinkDataEntries.get(linkData.getDst().getDpid());
917 if (linkDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700918 return; // Nothing to do
919 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700920 if (linkDataEntries.get(linkData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700921 return; // Nothing to do
922 }
923
924 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700925 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700926 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700927 new TopologyEvent(linkData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700928 tbo.appendRemoveOperation(topologyEvent);
929 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700930
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700931 linkDataEntries.remove(linkData.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700932 }
933
934 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700935 * Publishes ADD Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700936 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700937 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700938 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700939 private void publishAddHostEvent(HostData hostData) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700940 //
941 // NOTE: The implementation below assumes that there is just one
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700942 // attachment point stored in hostData. Currently, this assumption
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700943 // is true based on the existing implementation of the caller
944 // hostAdded().
945 //
946
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700947 if (!registryService.hasControl(hostData.getOriginDpid().value())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700948 log.debug("Not the master for attachment switch {}. Suppressed host add event {}.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700949 hostData.getOriginDpid(), hostData);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700950 return;
951 }
952
953 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700954 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700955 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700956 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700957 tbo.appendAddOperation(topologyEvent);
958 publishTopologyOperations(tbo);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700959
960 // Store the new Host Event in the local cache
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700961 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
962 ConcurrentUtils.putIfAbsent(publishedHostDataEntries,
963 hostData.getOriginDpid(),
964 new ConcurrentHashMap<ByteBuffer, HostData>());
965 hostDataEntries.put(hostData.getIDasByteBuffer(), hostData);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700966 }
967
968 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700969 * Publishes REMOVE Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700970 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700971 * @param hostData the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700972 */
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700973 private void publishRemoveHostEvent(HostData hostData) {
974 ConcurrentMap<ByteBuffer, HostData> hostDataEntries =
975 publishedHostDataEntries.get(hostData.getOriginDpid());
976 if (hostDataEntries == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700977 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700978 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700979 if (hostDataEntries.get(hostData.getIDasByteBuffer()) == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700980 return; // Nothing to do
981 }
982
983 // Publish the information
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700984 TopologyBatchOperation tbo = new TopologyBatchOperation();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700985 TopologyEvent topologyEvent =
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700986 new TopologyEvent(hostData, getOnosInstanceId());
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700987 tbo.appendRemoveOperation(topologyEvent);
988 publishTopologyOperations(tbo);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700989
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700990 hostDataEntries.remove(hostData.getIDasByteBuffer());
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700991 }
Pavlin Radoslavov24409672014-08-20 16:45:11 -0700992
993 /**
994 * Publishes Topology Operations.
995 *
996 * @param tbo the Topology Operations to publish
997 */
998 private void publishTopologyOperations(TopologyBatchOperation tbo) {
999 // TODO: This flag should be configurable
1000 boolean isGlobalLogWriter = false;
1001
1002 log.debug("Publishing: {}", tbo);
1003
1004 if (isGlobalLogWriter) {
1005 if (!topologyService.publish(tbo)) {
1006 log.debug("Cannot publish: {}", tbo);
1007 delayedOperations.add(tbo);
1008 }
1009 } else {
1010 // TODO: For now we publish each TopologyEvent independently
1011 for (BatchOperationEntry<TopologyBatchOperation.Operator,
1012 TopologyEvent> boe : tbo.getOperations()) {
1013 TopologyBatchOperation.Operator oper = boe.getOperator();
1014 TopologyEvent topologyEvent = boe.getTarget();
1015 switch (oper) {
1016 case ADD:
1017 eventChannel.addEntry(topologyEvent.getID(),
1018 topologyEvent);
1019 break;
1020 case REMOVE:
1021 eventChannel.removeEntry(topologyEvent.getID());
1022 break;
1023 default:
1024 log.error("Unknown Topology Batch Operation {}", oper);
1025 break;
1026 }
1027 }
1028 }
1029 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08001030}