blob: 2863523ef6dbbf96d8cb895bf15f68ebe1d95e00 [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 Radoslavovb46f89b2014-08-15 23:00:26 -07006import java.util.LinkedList;
Jonathan Hart369875b2014-02-13 10:00:31 -08007import java.util.List;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08008import java.util.Map;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -07009import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.ConcurrentMap;
Jonathan Hart369875b2014-02-13 10:00:31 -080011import java.util.concurrent.TimeUnit;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080012
13import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070014import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080015import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070016import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
17import net.floodlightcontroller.core.IOFSwitchListener;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080018import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.core.module.FloodlightModuleException;
20import net.floodlightcontroller.core.module.IFloodlightModule;
21import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080022import net.floodlightcontroller.core.util.SingletonTask;
23import net.floodlightcontroller.threadpool.IThreadPoolService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070024
25import net.onrc.onos.core.datagrid.IDatagridService;
26import net.onrc.onos.core.datagrid.IEventChannel;
Jonathan Hart03102132014-07-01 23:22:04 -070027import net.onrc.onos.core.hostmanager.Host;
28import net.onrc.onos.core.hostmanager.IHostListener;
29import net.onrc.onos.core.hostmanager.IHostService;
Jonathan Hart23701d12014-04-03 10:45:48 -070030import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
31import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart284e70f2014-07-05 12:32:51 -070032import net.onrc.onos.core.linkdiscovery.Link;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070033import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070034import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070035import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070036import net.onrc.onos.core.util.Dpid;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070037import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -070038import net.onrc.onos.core.util.PortNumber;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070039import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080040
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070041import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070042import org.projectfloodlight.openflow.protocol.OFPortDesc;
43import org.projectfloodlight.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080046
Jonathan Hart88770672014-04-02 18:08:30 -070047/**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070048 * Class for publishing topology-related events.
49 *
50 * The events are received from the discovery modules, reformatted and
51 * published to the other ONOS instances.
52 *
53 * TODO: Add a synchronization mechanism when publishing the events to
54 * preserve the ordering and to avoid mismatch in the local "published" state,
55 * because each of the caller (the discovery modules) might be running
56 * on a different thread.
Jonathan Hart88770672014-04-02 18:08:30 -070057 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070058public class TopologyPublisher implements IOFSwitchListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070059 ILinkDiscoveryListener,
60 IFloodlightModule,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070061 IHostListener {
Jonathan Hart88770672014-04-02 18:08:30 -070062 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070063 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080064
Jonathan Hart88770672014-04-02 18:08:30 -070065 private IFloodlightProviderService floodlightProvider;
66 private ILinkDiscoveryService linkDiscovery;
67 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070068 private ITopologyService topologyService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070069 private IDatagridService datagridService;
Toshio Koide2f570c12014-02-06 16:55:32 -080070
Jonathan Hart03102132014-07-01 23:22:04 -070071 private IHostService hostService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070072
Jonathan Harte37e4e22014-05-13 19:12:02 -070073 private Topology topology;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070074
Jonathan Hart88770672014-04-02 18:08:30 -070075 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
76 private boolean cleanupEnabled = true;
77 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
78 private SingletonTask cleanupTask;
Toshio Koide2f570c12014-02-06 16:55:32 -080079
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070080 private IEventChannel<byte[], TopologyEvent> eventChannel;
81
82 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070083 // Local state for keeping track of locally published events so we can
84 // cleanup properly when an entry is removed.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070085 //
86 // We keep all Port, (incoming) Link and Host events per Switch DPID:
87 // - If a switch goes down, we remove all corresponding Port, Link and
88 // Host events.
89 // - If a port on a switch goes down, we remove all corresponding Link
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070090 // and Host events attached to this port.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070091 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070092 // TODO: What to do if the Mastership changes?
93 // - Cleanup state from publishedFoo maps, but do not send REMOVE events?
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070094 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070095 private ConcurrentMap<Dpid, MastershipEvent> publishedMastershipEvents =
96 new ConcurrentHashMap<>();
97 private ConcurrentMap<Dpid, SwitchEvent> publishedSwitchEvents =
98 new ConcurrentHashMap<>();
99 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, PortEvent>>
100 publishedPortEvents = new ConcurrentHashMap<>();
101 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, LinkEvent>>
102 publishedLinkEvents = new ConcurrentHashMap<>();
103 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, HostEvent>>
104 publishedHostEvents = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700105
106
Jonathan Hart369875b2014-02-13 10:00:31 -0800107 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700108 * Gets the ONOS Instance ID.
109 *
110 * @return the ONOS Instance ID.
111 */
112 private OnosInstanceId getOnosInstanceId() {
113 return registryService.getOnosInstanceId();
114 }
115
116 /**
117 * Cleanup old switches from the topology. Old switches are those which
118 * have no controller in the registry.
119 *
120 * TODO: The overall switch cleanup mechanism needs refactoring/redesign.
Jonathan Hart369875b2014-02-13 10:00:31 -0800121 */
122 private class SwitchCleanup implements ControlChangeCallback, Runnable {
123 @Override
124 public void run() {
125 String old = Thread.currentThread().getName();
126 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700127
Jonathan Hart369875b2014-02-13 10:00:31 -0800128 try {
Jonathan Hart88770672014-04-02 18:08:30 -0700129 if (log.isTraceEnabled()) {
130 log.trace("Running cleanup thread");
131 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800132 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -0800133 } finally {
134 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -0700135 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -0800136 Thread.currentThread().setName(old);
137 }
138 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700139
Jonathan Hart88770672014-04-02 18:08:30 -0700140 /**
141 * First half of the switch cleanup operation. This method will attempt
142 * to get control of any switch it sees without a controller via the
143 * registry.
144 */
Jonathan Hart369875b2014-02-13 10:00:31 -0800145 private void switchCleanup() {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700146 Iterable<Switch> switches = topology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -0800147
Jonathan Hart88770672014-04-02 18:08:30 -0700148 if (log.isTraceEnabled()) {
149 log.trace("Checking for inactive switches");
150 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700151 // For each switch check if a controller exists in controller
152 // registry
Ray Milkey269ffb92014-04-03 14:43:30 -0700153 for (Switch sw : switches) {
Praseed Balakrishnane82adc62014-08-04 10:59:24 -0700154 // FIXME How to handle case where Switch has never been
155 // registered to ZK
156 if (sw.getConfigState() == ConfigState.CONFIGURED) {
157 continue;
158 }
Jonathan Hart88770672014-04-02 18:08:30 -0700159 try {
160 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700161 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700162 if (controller == null) {
163 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700164 sw.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700165 registryService.requestControl(sw.getDpid().value(),
166 this);
Jonathan Hart88770672014-04-02 18:08:30 -0700167 }
168 } catch (RegistryException e) {
169 log.error("Caught RegistryException in cleanup thread", e);
170 }
171 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800172 }
173
Jonathan Hart88770672014-04-02 18:08:30 -0700174 /**
175 * Second half of the switch cleanup operation. If the registry grants
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700176 * control of a switch, we can be sure no other instance is writing
177 * this switch to the topology, so we can remove it now.
178 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700179 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700180 * @param hasControl whether we got control or not
181 */
182 @Override
183 public void controlChanged(long dpid, boolean hasControl) {
184 if (hasControl) {
185 log.debug("Got control to set switch {} INACTIVE",
186 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700187
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700188 SwitchEvent switchEvent = new SwitchEvent(new Dpid(dpid));
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700189 publishRemoveSwitchEvent(switchEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700190 registryService.releaseControl(dpid);
191 }
192 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800193 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800194
Jonathan Hart88770672014-04-02 18:08:30 -0700195 @Override
Jonathan Hart284e70f2014-07-05 12:32:51 -0700196 public void linkAdded(Link link) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700197 LinkEvent linkEvent = new LinkEvent(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700198 new SwitchPort(link.getSrc(), link.getSrcPort()),
199 new SwitchPort(link.getDst(), link.getDstPort()));
200
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700201 // FIXME should be merging, with existing attrs, etc..
202 // TODO define attr name as constant somewhere.
203 // TODO populate appropriate attributes.
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700204 linkEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700205 TopologyElement.TYPE_PACKET_LAYER);
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700206 linkEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
207 ConfigState.NOT_CONFIGURED.toString());
208 linkEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
209 AdminStatus.ACTIVE.toString());
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700210 linkEvent.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700211
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700212 publishAddLinkEvent(linkEvent);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700213 }
214
215 @Override
216 public void linkRemoved(Link link) {
217 LinkEvent linkEvent = new LinkEvent(
218 new SwitchPort(link.getSrc(), link.getSrcPort()),
219 new SwitchPort(link.getDst(), link.getDstPort()));
220
221 // FIXME should be merging, with existing attrs, etc..
222 // TODO define attr name as constant somewhere.
223 // TODO populate appropriate attributes.
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700224 linkEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700225 TopologyElement.TYPE_PACKET_LAYER);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700226 linkEvent.freeze();
227
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700228 publishRemoveLinkEvent(linkEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700229 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800230
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700231 /* *****************
232 * IOFSwitchListener
233 * *****************/
234
Jonathan Hart88770672014-04-02 18:08:30 -0700235 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700236 public void switchActivatedMaster(long swId) {
237 IOFSwitch sw = floodlightProvider.getSwitch(swId);
238 final Dpid dpid = new Dpid(swId);
239 if (sw == null) {
240 log.warn("Added switch not available {} ", dpid);
241 return;
242 }
243
244 controllerRoleChanged(dpid, Role.MASTER);
245
246 SwitchEvent switchEvent = new SwitchEvent(dpid);
247 // FIXME should be merging, with existing attrs, etc..
248 // TODO define attr name as constant somewhere.
249 // TODO populate appropriate attributes.
250 switchEvent.createStringAttribute(TopologyElement.TYPE,
251 TopologyElement.TYPE_PACKET_LAYER);
252 switchEvent.createStringAttribute("ConnectedSince",
253 sw.getConnectedSince().toString());
254 switchEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
255 ConfigState.NOT_CONFIGURED.toString());
256 switchEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
257 AdminStatus.ACTIVE.toString());
258 switchEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700259 // The Port events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700260 List<PortEvent> portEvents = new ArrayList<PortEvent>();
261 for (OFPortDesc port : sw.getPorts()) {
262 PortEvent portEvent = new PortEvent(dpid,
263 new PortNumber(port.getPortNo().getShortPortNumber()));
264 // FIXME should be merging, with existing attrs, etc..
265 // TODO define attr name as constant somewhere.
266 // TODO populate appropriate attributes.
267 portEvent.createStringAttribute("name", port.getName());
268 portEvent.createStringAttribute(TopologyElement.TYPE,
269 TopologyElement.TYPE_PACKET_LAYER);
270 portEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
271 ConfigState.NOT_CONFIGURED.toString());
272 portEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
273 AdminStatus.ACTIVE.toString());
274
275 portEvent.freeze();
276 portEvents.add(portEvent);
277 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700278 publishAddSwitchEvent(switchEvent, portEvents);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700279 }
280
281 @Override
282 public void switchActivatedEqual(long swId) {
283 final Dpid dpid = new Dpid(swId);
284 controllerRoleChanged(dpid, Role.EQUAL);
285 }
286
287 @Override
288 public void switchMasterToEqual(long swId) {
289 final Dpid dpid = new Dpid(swId);
290 controllerRoleChanged(dpid, Role.EQUAL);
291 }
292
293 @Override
294 public void switchEqualToMaster(long swId) {
295 // for now treat as switchActivatedMaster
296 switchActivatedMaster(swId);
297 }
298
299 @Override
300 public void switchDisconnected(long swId) {
301 final Dpid dpid = new Dpid(swId);
302
303 log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
304
305 Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
306
307 MastershipEvent mastershipEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700308 new MastershipEvent(dpid, getOnosInstanceId(), role);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700309 // FIXME should be merging, with existing attrs, etc..
310 // TODO define attr name as constant somewhere.
311 // TODO populate appropriate attributes.
312 mastershipEvent.createStringAttribute(TopologyElement.TYPE,
313 TopologyElement.TYPE_ALL_LAYERS);
314 mastershipEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700315 publishRemoveSwitchMastershipEvent(mastershipEvent);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700316 }
317
318 @Override
319 public void switchPortChanged(long swId, OFPortDesc port,
320 PortChangeType changeType) {
321 switch (changeType) {
322 case ADD:
323 switchPortAdded(swId, port);
324 break;
325 case DELETE:
326 switchPortRemoved(swId, port);
327 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700328 case UP:
Pavlin Radoslavov7946c612014-08-13 15:06:00 -0700329 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
330 switchPortAdded(swId, port);
331 break;
332 case DOWN:
333 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
334 switchPortRemoved(swId, port);
335 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700336 case OTHER_UPDATE:
337 default:
338 // XXX S what is the right set of port change handlers?
339 log.debug("Topology publisher does not handle these port updates: {}",
340 changeType);
341 }
342 }
343
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700344 /**
345 * Prepares an event for adding a port on a switch.
346 *
347 * @param switchId the switch ID (DPID)
348 * @param port the port to add
349 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700350 private void switchPortAdded(long switchId, OFPortDesc port) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700351 final Dpid dpid = new Dpid(switchId);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700352 PortEvent portEvent = new PortEvent(dpid,
353 new PortNumber(port.getPortNo().getShortPortNumber()));
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700354 // FIXME should be merging, with existing attrs, etc..
355 // TODO define attr name as constant somewhere.
356 // TODO populate appropriate attributes.
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700357 portEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700358 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700359 portEvent.createStringAttribute("name", port.getName());
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700360 portEvent.freeze();
361
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700362 publishAddPortEvent(portEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700363 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800364
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700365 /**
366 * Prepares an event for removing a port on a switch.
367 *
368 * @param switchId the switch ID (DPID)
369 * @param port the port to remove
370 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700371 private void switchPortRemoved(long switchId, OFPortDesc port) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700372 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700373
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700374 PortEvent portEvent = new PortEvent(dpid, new PortNumber(
375 port.getPortNo().getShortPortNumber()));
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700376 // FIXME should be merging, with existing attrs, etc..
377 // TODO define attr name as constant somewhere.
378 // TODO populate appropriate attributes.
379 portEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700380 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700381 portEvent.createStringAttribute("name", port.getName());
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700382 portEvent.freeze();
383
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700384 publishRemovePortEvent(portEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700385 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800386
Jonathan Hart88770672014-04-02 18:08:30 -0700387 @Override
Jonathan Hart88770672014-04-02 18:08:30 -0700388 public String getName() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700389 return "topologyPublisher";
Jonathan Hart88770672014-04-02 18:08:30 -0700390 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800391
Jonathan Hart88770672014-04-02 18:08:30 -0700392 /* *****************
393 * IFloodlightModule
394 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800395
Jonathan Hart88770672014-04-02 18:08:30 -0700396 @Override
397 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
398 return null;
399 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800400
Jonathan Hart88770672014-04-02 18:08:30 -0700401 @Override
402 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700403 getServiceImpls() {
Jonathan Hart88770672014-04-02 18:08:30 -0700404 return null;
405 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800406
Jonathan Hart88770672014-04-02 18:08:30 -0700407 @Override
408 public Collection<Class<? extends IFloodlightService>>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700409 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700410 Collection<Class<? extends IFloodlightService>> l =
411 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800412 l.add(IFloodlightProviderService.class);
413 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800414 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800415 l.add(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700416 l.add(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700417 l.add(ITopologyService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700418 l.add(IHostService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800419 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700420 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800421
Jonathan Hart88770672014-04-02 18:08:30 -0700422 @Override
423 public void init(FloodlightModuleContext context)
424 throws FloodlightModuleException {
425 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
426 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
427 registryService = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700428 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700429 hostService = context.getServiceImpl(IHostService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700430 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700431 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800432
Jonathan Hart88770672014-04-02 18:08:30 -0700433 @Override
434 public void startUp(FloodlightModuleContext context) {
435 floodlightProvider.addOFSwitchListener(this);
436 linkDiscovery.addListener(this);
Jonathan Hart03102132014-07-01 23:22:04 -0700437 hostService.addHostListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800438
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700439 eventChannel = datagridService.createChannel(
440 TopologyManager.EVENT_CHANNEL_NAME,
441 byte[].class,
442 TopologyEvent.class);
443
Jonathan Harte37e4e22014-05-13 19:12:02 -0700444 topology = topologyService.getTopology();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700445
Jonathan Hart88770672014-04-02 18:08:30 -0700446 // Run the cleanup thread
447 String enableCleanup =
448 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
449 if (enableCleanup != null
450 && enableCleanup.equalsIgnoreCase("false")) {
451 cleanupEnabled = false;
452 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700453
Jonathan Hart88770672014-04-02 18:08:30 -0700454 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700455
Jonathan Hart88770672014-04-02 18:08:30 -0700456 if (cleanupEnabled) {
457 IThreadPoolService threadPool =
458 context.getServiceImpl(IThreadPoolService.class);
459 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
460 new SwitchCleanup());
461 // Run the cleanup task immediately on startup
462 cleanupTask.reschedule(0, TimeUnit.SECONDS);
463 }
464 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700465
Jonathan Hart88770672014-04-02 18:08:30 -0700466 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700467 public void hostAdded(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700468 log.debug("Host added with MAC {}", host.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700469
Jonathan Hart03102132014-07-01 23:22:04 -0700470 SwitchPort sp = new SwitchPort(host.getSwitchDPID(), host.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700471 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
472 spLists.add(sp);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700473 HostEvent event = new HostEvent(host.getMacAddress());
Jonathan Hart88770672014-04-02 18:08:30 -0700474 event.setAttachmentPoints(spLists);
Jonathan Hart03102132014-07-01 23:22:04 -0700475 event.setLastSeenTime(host.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700476 // Does not use vlan info now.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700477 event.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700478
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700479 publishAddHostEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700480 }
TeruUd1c5b652014-03-24 13:58:46 -0700481
Jonathan Hart88770672014-04-02 18:08:30 -0700482 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700483 public void hostRemoved(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700484 log.debug("Host removed with MAC {}", host.getMacAddress());
485
486 //
487 // Remove all previously added HostEvent for this MAC address
488 //
489 // TODO: Currently, the caller of hostRemoved() might not include
490 // the correct set of Attachment Points in the HostEvent entry itself.
491 // Also, we might have multiple HostEvent entries for the same
492 // host (MAC address), each containing a single (different) Attachment
493 // Point.
494 // Hence, here we have to cleanup all HostEvent entries for this
495 // particular host, based on its MAC address.
496 //
497 List<HostEvent> removeHostEvents = new LinkedList<>();
498 for (ConcurrentMap<ByteBuffer, HostEvent> cm : publishedHostEvents.values()) {
499 for (HostEvent hostEvent : cm.values()) {
500 if (hostEvent.getMac().equals(host.getMacAddress())) {
501 removeHostEvents.add(hostEvent);
502 }
503 }
504 }
505 for (HostEvent event : removeHostEvents) {
506 publishRemoveHostEvent(event);
507 }
Jonathan Hart88770672014-04-02 18:08:30 -0700508 }
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700509
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700510 /**
511 * Prepares the Controller role changed event for a switch.
512 *
513 * @param dpid the switch DPID
514 * @param role the new role of the controller
515 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700516 private void controllerRoleChanged(Dpid dpid, Role role) {
517 log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
518 dpid, role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700519 MastershipEvent mastershipEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700520 new MastershipEvent(dpid, getOnosInstanceId(), role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700521 // FIXME should be merging, with existing attrs, etc..
522 // TODO define attr name as constant somewhere.
523 // TODO populate appropriate attributes.
524 mastershipEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700525 TopologyElement.TYPE_ALL_LAYERS);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700526 mastershipEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700527 publishAddSwitchMastershipEvent(mastershipEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700528 }
529
530 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700531 * Publishes ADD Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700532 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700533 * @param mastershipEvent the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700534 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700535 private void publishAddSwitchMastershipEvent(
536 MastershipEvent mastershipEvent) {
537 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700538 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700539 new TopologyEvent(mastershipEvent, getOnosInstanceId());
540 log.debug("Publishing add mastership: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700541 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700542 publishedMastershipEvents.put(mastershipEvent.getDpid(),
543 mastershipEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700544 }
545
546 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700547 * Publishes REMOVE Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700548 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700549 * @param mastershipEvent the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700550 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700551 private void publishRemoveSwitchMastershipEvent(
552 MastershipEvent mastershipEvent) {
553 if (publishedMastershipEvents.get(mastershipEvent.getDpid()) == null) {
554 return; // Nothing to do
555 }
556
557 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700558 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700559 new TopologyEvent(mastershipEvent, getOnosInstanceId());
560 log.debug("Publishing remove mastership: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700561 eventChannel.removeEntry(topologyEvent.getID());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700562 publishedMastershipEvents.remove(mastershipEvent.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700563 }
564
565 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700566 * Publishes ADD Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700567 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700568 * @param switchEvent the switch event to publish
569 * @param portEvents the corresponding port events for the switch to
570 * publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700571 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700572 private void publishAddSwitchEvent(SwitchEvent switchEvent,
573 Collection<PortEvent> portEvents) {
574 if (!registryService.hasControl(switchEvent.getOriginDpid().value())) {
575 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
576 switchEvent.getOriginDpid(), switchEvent);
577 return;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700578 }
579
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700580 // Keep track of the old Port Events that should be removed
581 ConcurrentMap<ByteBuffer, PortEvent> oldPortEvents =
582 publishedPortEvents.get(switchEvent.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700583 if (oldPortEvents == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700584 oldPortEvents = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700585 }
586
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700587 // Publish the information for the switch
588 TopologyEvent topologyEvent =
589 new TopologyEvent(switchEvent, getOnosInstanceId());
590 log.debug("Publishing add switch: {}", topologyEvent);
591 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
592 publishedSwitchEvents.put(switchEvent.getDpid(), switchEvent);
593
594 // Publish the information for each port
595 ConcurrentMap<ByteBuffer, PortEvent> newPortEvents =
596 new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700597 for (PortEvent portEvent : portEvents) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700598 topologyEvent =
599 new TopologyEvent(portEvent, getOnosInstanceId());
600 log.debug("Publishing add port: {}", topologyEvent);
601 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
602
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700603 ByteBuffer id = portEvent.getIDasByteBuffer();
604 newPortEvents.put(id, portEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700605 oldPortEvents.remove(id);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700606 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700607 publishedPortEvents.put(switchEvent.getDpid(), newPortEvents);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700608
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700609 // Cleanup for each of the old removed port
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700610 for (PortEvent portEvent : oldPortEvents.values()) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700611 publishRemovePortEvent(portEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700612 }
613 }
614
615 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700616 * Publishes REMOVE Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700617 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700618 * @param switchEvent the switch event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700619 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700620 private void publishRemoveSwitchEvent(SwitchEvent switchEvent) {
621 //
622 // TODO: Removed the check for now, because currently this method is
623 // also called by the SwitchCleanup thread, and in that case
624 // the Switch Event was published by some other ONOS instance.
625 //
626 /*
627 if (publishedSwitchEvents.get(switchEvent.getDpid()) == null) {
628 return; // Nothing to do
629 }
630 */
631
632 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700633 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700634 new TopologyEvent(switchEvent, getOnosInstanceId());
635 log.debug("Publishing remove switch: {}", topologyEvent);
636 eventChannel.removeEntry(topologyEvent.getID());
637 publishedSwitchEvents.remove(switchEvent.getDpid());
638
639 // Cleanup for each port
640 ConcurrentMap<ByteBuffer, PortEvent> portEvents =
641 publishedPortEvents.get(switchEvent.getDpid());
642 if (portEvents != null) {
643 for (PortEvent portEvent : portEvents.values()) {
644 publishRemovePortEvent(portEvent);
645 }
646 }
647
648 publishedPortEvents.remove(switchEvent.getDpid());
649 publishedLinkEvents.remove(switchEvent.getDpid());
650 publishedHostEvents.remove(switchEvent.getDpid());
651 }
652
653 /**
654 * Publishes ADD Port Event.
655 *
656 * @param portEvent the port event to publish
657 */
658 private void publishAddPortEvent(PortEvent portEvent) {
659 if (!registryService.hasControl(portEvent.getOriginDpid().value())) {
660 log.debug("Not the master for switch {}. Suppressed port add event {}.",
661 portEvent.getOriginDpid(), portEvent);
662 return;
663 }
664
665 // Publish the information
666 TopologyEvent topologyEvent =
667 new TopologyEvent(portEvent, getOnosInstanceId());
668 log.debug("Publishing add port: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700669 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
670
671 // Store the new Port Event in the local cache
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700672 ConcurrentMap<ByteBuffer, PortEvent> portEvents =
673 ConcurrentUtils.putIfAbsent(publishedPortEvents,
674 portEvent.getDpid(),
675 new ConcurrentHashMap<ByteBuffer, PortEvent>());
676 portEvents.put(portEvent.getIDasByteBuffer(), portEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700677 }
678
679 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700680 * Publishes REMOVE Port Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700681 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700682 * @param portEvent the port event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700683 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700684 private void publishRemovePortEvent(PortEvent portEvent) {
685 ConcurrentMap<ByteBuffer, PortEvent> portEvents =
686 publishedPortEvents.get(portEvent.getDpid());
687 if (portEvents == null) {
688 return; // Nothing to do
689 }
690 if (portEvents.get(portEvent.getIDasByteBuffer()) == null) {
691 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700692 }
693
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700694 // Publish the information
695 TopologyEvent topologyEvent =
696 new TopologyEvent(portEvent, getOnosInstanceId());
697 log.debug("Publishing remove port: {}", topologyEvent);
698 eventChannel.removeEntry(topologyEvent.getID());
699
700 // Cleanup for the incoming link(s)
701 ConcurrentMap<ByteBuffer, LinkEvent> linkEvents =
702 publishedLinkEvents.get(portEvent.getDpid());
703 if (linkEvents != null) {
704 for (LinkEvent linkEvent : linkEvents.values()) {
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700705 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700706 publishRemoveLinkEvent(linkEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700707 }
708 }
709 }
710
711 // Cleanup for the connected hosts
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700712 ConcurrentMap<ByteBuffer, HostEvent> hostEvents =
713 publishedHostEvents.get(portEvent.getDpid());
714 if (hostEvents != null) {
715 for (HostEvent hostEvent : hostEvents.values()) {
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700716 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
717 if (swp.equals(portEvent.getSwitchPort())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700718 publishRemoveHostEvent(hostEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700719 }
720 }
721 }
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700722 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700723
724 portEvents.remove(portEvent.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700725 }
726
727 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700728 * Publishes ADD Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700729 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700730 * @param linkEvent the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700731 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700732 private void publishAddLinkEvent(LinkEvent linkEvent) {
733 if (!registryService.hasControl(linkEvent.getOriginDpid().value())) {
734 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
735 linkEvent.getOriginDpid(), linkEvent);
736 return;
737 }
738
739 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700740 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700741 new TopologyEvent(linkEvent, getOnosInstanceId());
742 log.debug("Publishing add link: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700743 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
744
745 // Store the new Link Event in the local cache
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700746 ConcurrentMap<ByteBuffer, LinkEvent> linkEvents =
747 ConcurrentUtils.putIfAbsent(publishedLinkEvents,
748 linkEvent.getDst().getDpid(),
749 new ConcurrentHashMap<ByteBuffer, LinkEvent>());
750 linkEvents.put(linkEvent.getIDasByteBuffer(), linkEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700751 }
752
753 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700754 * Publishes REMOVE Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700755 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700756 * @param linkEvent the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700757 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700758 private void publishRemoveLinkEvent(LinkEvent linkEvent) {
759 ConcurrentMap<ByteBuffer, LinkEvent> linkEvents =
760 publishedLinkEvents.get(linkEvent.getDst().getDpid());
761 if (linkEvents == null) {
762 return; // Nothing to do
763 }
764 if (linkEvents.get(linkEvent.getIDasByteBuffer()) == null) {
765 return; // Nothing to do
766 }
767
768 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700769 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700770 new TopologyEvent(linkEvent, getOnosInstanceId());
771 log.debug("Publishing remove link: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700772 eventChannel.removeEntry(topologyEvent.getID());
773
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700774 linkEvents.remove(linkEvent.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700775 }
776
777 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700778 * Publishes ADD Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700779 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700780 * @param hostEvent the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700781 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700782 private void publishAddHostEvent(HostEvent hostEvent) {
783 //
784 // NOTE: The implementation below assumes that there is just one
785 // attachment point stored in hostEvent. Currently, this assumption
786 // is true based on the existing implementation of the caller
787 // hostAdded().
788 //
789
790 if (!registryService.hasControl(hostEvent.getOriginDpid().value())) {
791 log.debug("Not the master for attachment switch {}. Suppressed host add event {}.",
792 hostEvent.getOriginDpid(), hostEvent);
793 return;
794 }
795
796 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700797 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700798 new TopologyEvent(hostEvent, getOnosInstanceId());
799 log.debug("Publishing add host: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700800 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700801
802 // Store the new Host Event in the local cache
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700803 ConcurrentMap<ByteBuffer, HostEvent> hostEvents =
804 ConcurrentUtils.putIfAbsent(publishedHostEvents,
805 hostEvent.getOriginDpid(),
806 new ConcurrentHashMap<ByteBuffer, HostEvent>());
807 hostEvents.put(hostEvent.getIDasByteBuffer(), hostEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700808 }
809
810 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700811 * Publishes REMOVE Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700812 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700813 * @param hostEvent the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700814 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700815 private void publishRemoveHostEvent(HostEvent hostEvent) {
816 ConcurrentMap<ByteBuffer, HostEvent> hostEvents =
817 publishedHostEvents.get(hostEvent.getOriginDpid());
818 if (hostEvents == null) {
819 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700820 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700821 if (hostEvents.get(hostEvent.getIDasByteBuffer()) == null) {
822 return; // Nothing to do
823 }
824
825 // Publish the information
826 TopologyEvent topologyEvent =
827 new TopologyEvent(hostEvent, getOnosInstanceId());
828 log.debug("Publishing remove host: {}", topologyEvent);
829 eventChannel.removeEntry(topologyEvent.getID());
830
831 hostEvents.remove(hostEvent.getIDasByteBuffer());
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700832 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800833}