Bug 7606: Fix for missed tunnel flows, after VM live migration
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / netvirt / openstack / netvirt / SouthboundHandler.java
1 /*
2  * Copyright (c) 2013, 2016 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.openstack.netvirt;
10
11 import java.net.InetAddress;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.stream.Collectors;
15
16 import org.apache.commons.lang3.tuple.Pair;
17 import org.opendaylight.netvirt.openstack.netvirt.api.Action;
18 import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
19 import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
20 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
21 import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
22 import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
23 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
24 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
25 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
26 import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryListener;
27 import org.opendaylight.netvirt.openstack.netvirt.api.OvsdbInventoryService;
28 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
29 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
30 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
31 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
32 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
33 import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
34 import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
35 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
44 import org.opendaylight.yangtools.yang.binding.DataObject;
45 import org.osgi.framework.ServiceReference;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  * @author Madhu Venugopal
51  * @author Brent Salisbury
52  * @author Dave Tucker
53  * @author Sam Hague (shague@redhat.com)
54  */
55 public class SouthboundHandler extends AbstractHandler
56         implements ConfigInterface, NodeCacheListener, OvsdbInventoryListener {
57     private static final Logger LOG = LoggerFactory.getLogger(SouthboundHandler.class);
58
59     // The implementation for each of these services is resolved by the OSGi Service Manager
60     private volatile ConfigurationService configurationService;
61     private volatile BridgeConfigurationManager bridgeConfigurationManager;
62     private volatile TenantNetworkManager tenantNetworkManager;
63     private volatile NetworkingProviderManager networkingProviderManager;
64     private volatile NeutronL3Adapter neutronL3Adapter;
65     private volatile DistributedArpService distributedArpService;
66     private volatile NodeCacheManager nodeCacheManager;
67     private volatile INeutronNetworkCRUD neutronNetworkCache;
68     private volatile OvsdbInventoryService ovsdbInventoryService;
69     private volatile Southbound southbound;
70     private volatile VLANProvider vlanProvider;
71     private volatile L2ForwardingProvider l2ForwardingProvider;
72
73     private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
74         SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
75
76         switch (ovsdbType) {
77             case NODE:
78                 type = SouthboundEvent.Type.NODE;
79                 break;
80             case BRIDGE:
81                 type = SouthboundEvent.Type.BRIDGE;
82                 break;
83             case PORT:
84                 type = SouthboundEvent.Type.PORT;
85                 break;
86             case CONTROLLER:
87                 type = SouthboundEvent.Type.CONTROLLER;
88                 break;
89             case OPENVSWITCH:
90                 type = SouthboundEvent.Type.OPENVSWITCH;
91                 break;
92             default:
93                 LOG.warn("Invalid OvsdbType: {}", ovsdbType);
94                 break;
95         }
96         return type;
97     }
98
99     @Override
100     public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
101         LOG.debug("Received ovsdbUpdate for : {} with action : {} for the OVS node : {} Resource Data : {}",
102                 ovsdbType, action, node, resourceAugmentationData);
103         enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
104                 ovsdbTypeToSouthboundEventType(ovsdbType), action));
105     }
106
107     private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp, Action action) {
108         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
109         if (network != null && !network.getRouterExternal()) {
110             LOG.trace("InterfaceUpdate for OVS Node :{} OvsdbTerminationPointAugmentation :"        + " {} for the network : {}", node, tp, network.getNetworkUUID());
111             if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
112                 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
113             }
114         } else {
115             LOG.debug("No tenant network found on node : {} for interface: {}", node, tp);
116         }
117         if (action.equals(Action.UPDATE)) {
118             distributedArpService.processInterfaceEvent(node, tp, network, false, action);
119         }
120         neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
121     }
122     /**
123      * Get dpid from node.
124      *
125      * @param node the {@link Node Node} of interest in the notification
126      * @return dpid value
127      */
128     private Long getDpidForIntegrationBridge(Node node) {
129         // Check if node is integration bridge; and only then return its dpid
130         if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
131             return southbound.getDataPathId(node);
132         }
133         return null;
134     }
135
136     /**
137      * Returns true, if the port is migrated else false.
138      *
139      * @param node the node associated with Neutron Port.
140      * @param neutronPort the port details.
141      * @return boolean true, if the port is migrated else false.
142      */
143     private boolean isMigratedPort(Node node, NeutronPort neutronPort) {
144         boolean isMigratedPort = false;
145         final Long dpId = getDpidForIntegrationBridge(node);
146         final Pair<Long, Uuid> nodeDpIdPair = neutronL3Adapter.getDpIdOfNeutronPort(neutronPort.getPortUUID());
147         Long dpIdNeutronPort = (nodeDpIdPair == null ? null : nodeDpIdPair.getLeft());
148         if(dpIdNeutronPort != null && !dpIdNeutronPort.equals(dpId)) {
149             isMigratedPort = true;
150         }
151         return isMigratedPort;
152     }
153
154     private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
155                                         boolean isLastInstanceOnNode, NeutronNetwork network) {
156         LOG.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
157                 node, isLastInstanceOnNode, intf);
158
159         final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
160         boolean isMigratedPort = isMigratedPort(node, neutronPort);
161         distributedArpService.processInterfaceEvent(node, intf, network, isMigratedPort, Action.DELETE);
162         neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
163         programVLANNetworkFlowProvider(node, intf, network, neutronPort, false);
164         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
165         if (isInterfaceOfInterest(intf, phyIfName)) {
166             // delete tunnel or physical interfaces
167             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
168                     network, node, intf, isLastInstanceOnNode, isMigratedPort);
169         } else if (network != null) {
170             // vlan doesn't need a tunnel endpoint
171             if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
172                     configurationService.getTunnelEndPoint(node) == null) {
173                 LOG.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
174                 return;
175             }
176             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
177                     network, node, intf, isLastInstanceOnNode, isMigratedPort);
178         }
179
180     }
181
182     @Override
183     public void triggerUpdates() {
184         List<Node> ovsdbNodes = southbound.readOvsdbTopologyNodes();
185         for (Node node : ovsdbNodes) {
186             ovsdbUpdate(node, node.getAugmentation(OvsdbNodeAugmentation.class),
187                     OvsdbInventoryListener.OvsdbType.NODE, Action.ADD);
188         }
189     }
190
191     private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
192                                    Object context) {
193         LOG.debug("processPortDelete for Node : {} ovsdbTerminationPointAugmentation : {}",
194                 node, ovsdbTerminationPointAugmentation);
195         NeutronNetwork network;
196         if (context == null) {
197             network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
198         } else {
199             network = (NeutronNetwork)context;
200         }
201         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
202         if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
203             if (network != null) {
204                 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
205             } else {
206                 LOG.warn("processPortDelete: network was null, ignoring update");
207             }
208         } else if (network != null && !network.getRouterExternal()) {
209             LOG.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
210                     ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
211             try {
212                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(node);
213                 if (ovsdbBridgeAugmentation != null) {
214                     List<TerminationPoint> terminationPoints = node.getTerminationPoint();
215                     if (!terminationPoints.isEmpty()){
216                         boolean isLastInstanceOnNode = true;
217                         for (TerminationPoint terminationPoint : terminationPoints) {
218                             OvsdbTerminationPointAugmentation tpAugmentation =
219                                     terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
220                             if (tpAugmentation.getInterfaceUuid().equals(
221                                     ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
222                                 continue;
223                             }
224                             NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
225                             if (neutronNetwork != null) {
226                                 String neutronNetworkSegId = neutronNetwork.getProviderSegmentationID();
227                                 String networkSegId = network.getProviderSegmentationID();
228                                 // vxlan ports should not be removed in table 110 flow entry
229                                 // unless last VM instance removed from the openstack node(Bug# 5813)
230                                 if (neutronNetworkSegId != null && neutronNetworkSegId.equals(networkSegId)) {
231                                     isLastInstanceOnNode = false;
232                                     break;
233                                 }
234                             }
235                         }
236                         this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
237                                 isLastInstanceOnNode, network);
238                     }
239                 }
240             } catch (Exception e) {
241                 LOG.error("Error fetching Interface Rows for node {}", node, e);
242             }
243         } else if (network != null && network.getRouterExternal()) {
244                 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
245         }
246         //remove neutronPort from the CleanupCache, if it has the entry.
247         NeutronPort neutronPort = null;
248         String neutronPortId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
249                 Constants.EXTERNAL_ID_INTERFACE_ID);
250         if (neutronPortId != null) {
251             LOG.trace("Clean up the NeutronPortCache for {} ", neutronPortId);
252             neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId);
253         }
254         if (neutronPort != null) {
255             LOG.debug("Clean up the NeutronPortCache ");
256             neutronL3Adapter.removePortFromCleanupCache(neutronPort);
257             neutronL3Adapter.removeNetworkFromCleanupCache(neutronPort.getNetworkUUID());
258         } else {
259             LOG.trace("Nothing to Clean up in the NeutronPortCache ");
260         }
261
262     }
263
264     private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
265         LOG.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
266
267         if(terminationPoint.getInterfaceType() == null){
268             // This is OK since eth ports don't have an interface type
269             return false;
270         }
271         return MdsalHelper.createOvsdbInterfaceType(
272                 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
273                ||
274                MdsalHelper.createOvsdbInterfaceType(
275                        terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
276                ||
277                phyIfName.contains(terminationPoint.getName());
278     }
279
280     /**
281      * Notification about an OpenFlow Node
282      *
283      * @param node the {@link Node Node} of interest in the notification
284      * @param action the {@link Action}
285      * @see NodeCacheListener#notifyNode
286      */
287     @Override
288     public void notifyNode (Node node, Action action) {
289         LOG.trace("notifyNode : action: {}, Node  : {} ", action, node);
290
291         if ((action == Action.ADD) && (southbound.getBridge(node) != null)) {
292             networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
293         }
294     }
295
296     /**
297      * Process the event.
298      *
299      * @param abstractEvent the {@link AbstractEvent} event to be handled.
300      * @see EventDispatcher
301      */
302     @Override
303     public void processEvent(AbstractEvent abstractEvent) {
304         if (!(abstractEvent instanceof SouthboundEvent)) {
305             LOG.error("processEvent Unable to process abstract event : {}", abstractEvent);
306             return;
307         }
308         SouthboundEvent ev = (SouthboundEvent) abstractEvent;
309         LOG.trace("processEvent : {} for TransactionId : {}", ev, ev.getTransactionId());
310         switch (ev.getType()) {
311             case NODE:
312                 processOvsdbNodeEvent(ev);
313                 break;
314
315             case BRIDGE:
316                 processBridgeEvent(ev);
317                 break;
318
319             case PORT:
320                 processPortEvent(ev);
321                 break;
322
323             case OPENVSWITCH:
324                 processOpenVSwitchEvent(ev);
325                 break;
326
327             default:
328                 LOG.warn("Unable to process type : {} action : {} for node : {}", ev.getType(), ev.getAction(), ev.getNode());
329                 break;
330         }
331         LOG.trace("processEvent exit : {} for TransactionId : {}", ev, ev.getTransactionId());
332     }
333
334     private void processOvsdbNodeEvent(SouthboundEvent ev) {
335         switch (ev.getAction()) {
336             case ADD:
337                 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
338                 break;
339             case UPDATE:
340                 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
341                 break;
342             case DELETE:
343                 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
344                 break;
345         }
346     }
347
348     private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
349         LOG.info("processOvsdb Node Create : {} ", ovsdbNode);
350         nodeCacheManager.nodeAdded(node);
351         bridgeConfigurationManager.prepareNode(node);
352     }
353
354     private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
355         LOG.info("processOvsdb Node Update : {} ", ovsdbNode);
356         nodeCacheManager.nodeAdded(node);
357     }
358
359     private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
360         LOG.info("processOvsdb Node Delete : {} ", ovsdbNode);
361         nodeCacheManager.nodeRemoved(node);
362         /* TODO SB_MIGRATION
363         * I don't think we want to do this yet
364         InstanceIdentifier<Node> bridgeNodeIid =
365                 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
366                         Constants.INTEGRATION_BRIDGE);
367         southbound.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
368         */
369     }
370
371     private void processPortEvent(SouthboundEvent ev) {
372         switch (ev.getAction()) {
373             case ADD:
374             case UPDATE:
375                 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), ev.getAction());
376                 break;
377             case DELETE:
378                 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
379                 break;
380         }
381     }
382
383     private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port, Action action) {
384         LOG.debug("processPortUpdate : {} for the Node: {}", port, node);
385         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
386         if (network != null) {
387             final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(port);
388             if (!network.getRouterExternal()) {
389                 handleInterfaceUpdate(node, port, action);
390             } else if (action != null && action.equals(Action.UPDATE)) {
391                 programVLANNetworkFlowProvider(node, port, network, neutronPort, true);
392             }
393         } else if (null != port.getInterfaceType() && null != port.getOfport()) {
394             // Filter Vxlan interface request and install table#110 unicast flow (Bug 7392).
395             if(port.getInterfaceType().equals(InterfaceTypeVxlan.class)) {
396                 List<Options> optionList = port.getOptions();
397                 if (null != optionList && !optionList.isEmpty()) {
398                     optionList.stream().filter(option -> isRemoteIp(option)).forEach(option ->
399                             handleTunnelOut(node, option.getValue(), port.getOfport()));
400                 }
401             }
402         }
403     }
404
405     private boolean isRemoteIp(Options option) {
406         return option.getOption().equals(Constants.TUNNEL_ENDPOINT_KEY_REMOTE);
407     }
408
409     private void handleTunnelOut(Node node, String remoteIp, Long ofPort) {
410         List<Node> nodes = nodeCacheManager.getBridgeNodes();
411         if (null != nodes && !nodes.isEmpty()) {
412             nodes.stream().filter(dstnode -> isDstNode(node, dstnode, remoteIp)).forEach(dstnode ->
413                     programTunnelOut(node, dstnode, ofPort));
414         }
415     }
416
417     private boolean isDstNode(Node node, Node dstnode, String remoteIp) {
418         if (!(node.getNodeId().getValue().equals(dstnode.getNodeId().getValue()))) {
419             InetAddress dst = configurationService.getTunnelEndPoint(dstnode);
420             String dstIp = dst.getHostAddress();
421             if (remoteIp.equals(dstIp)) {
422                  return true;
423             }
424         }
425         return false;
426     }
427
428     private void programTunnelOut(Node node, Node dstnode, Long ofPort) {
429         List<OvsdbTerminationPointAugmentation> ports = southbound.readTerminationPointAugmentations(dstnode);
430         for (OvsdbTerminationPointAugmentation destport : ports) {
431             NeutronPort neutronPort = tenantNetworkManager.getTenantPort(destport);
432             if (neutronPort != null) {
433                 final String networkUUID = neutronPort.getNetworkUUID();
434                 NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
435                 if (null == neutronNetwork) {
436                     neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(networkUUID);
437                 }
438                 final String segmentationId = neutronNetwork != null ? neutronNetwork.getProviderSegmentationID() : null;
439                 final String macAddress = neutronPort.getMacAddress();
440                 long dpid = getIntegrationBridgeOFDPID(node);
441                 if (null != l2ForwardingProvider) {
442                     l2ForwardingProvider.programTunnelOut(dpid, segmentationId, ofPort, macAddress, true);
443                 }
444             }
445         }
446     }
447
448     private long getIntegrationBridgeOFDPID(Node node) {
449         long dpid = 0L;
450         if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
451             dpid = southbound.getDataPathId(node);
452         }
453         return dpid;
454     }
455
456     private void programVLANNetworkFlowProvider(final Node node, final OvsdbTerminationPointAugmentation port,
457            final NeutronNetwork network, final NeutronPort neutronPort, final Boolean isWrite) {
458         if (neutronPort != null && neutronPort.getDeviceOwner().equalsIgnoreCase(Constants.OWNER_ROUTER_GATEWAY) &&
459                 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
460                 configurationService.isL3MultipleExternalNetworkEnabled()) {
461             vlanProvider.programProviderNetworkFlow(node, port, network, neutronPort, isWrite);
462         }
463     }
464
465     private void processOpenVSwitchEvent(SouthboundEvent ev) {
466         switch (ev.getAction()) {
467             case ADD:
468             case UPDATE:
469                 processOpenVSwitchUpdate(ev.getNode());
470                 break;
471             case DELETE:
472                 break;
473         }
474     }
475
476     private void processOpenVSwitchUpdate(Node node) {
477         LOG.debug("processOpenVSwitchUpdate : {}", node);
478         // TODO this node might be the OvsdbNode and not have termination points
479         // Would need to change listener or grab tp nodes in here.
480         List<TerminationPoint> terminationPoints = southbound.extractTerminationPoints(node);
481         for (TerminationPoint terminationPoint : terminationPoints) {
482             processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class), null);
483         }
484     }
485
486     private void processBridgeEvent(SouthboundEvent ev) {
487         switch (ev.getAction()) {
488             case ADD:
489                 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
490                 break;
491             case UPDATE:
492                 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
493                 break;
494             case DELETE:
495                 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
496                 break;
497         }
498     }
499
500     private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
501         LOG.debug("BridgeCreate : {} for the Node : {}", bridge, node);
502         String datapathId = southbound.getDatapathId(bridge);
503         // Having a datapathId means the ovsdb node has connected to ODL
504         if (datapathId != null) {
505             nodeCacheManager.nodeAdded(node);
506         } else {
507             LOG.debug("processBridgeCreate datapathId not found");
508         }
509     }
510
511     private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
512         LOG.debug("BridgeUpdate : {} for the node : {}", bridge, node);
513         String datapathId = southbound.getDatapathId(bridge);
514         // Having a datapathId means the ovsdb node has connected to ODL
515         if (datapathId != null) {
516             nodeCacheManager.nodeAdded(node);
517         } else {
518             LOG.debug("processBridgeUpdate datapathId not found");
519         }
520     }
521
522     private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
523         LOG.debug("BridgeDelete: Delete bridge from config data store : {}"
524                 +"Node : {}", bridge, node);
525         nodeCacheManager.nodeRemoved(node);
526
527         // Currently we only do not remove the integration bridge from configDS, which resolves
528         // bug 7461 where upon a rapid connection flap, the integration bridge is sometimes
529         // removed from the device due to ODL asynchronous processing of the connection flap.
530         if (bridge.getBridgeName() != null &&
531                 !bridge.getBridgeName().getValue().equals(configurationService.getIntegrationBridgeName())) {
532             southbound.deleteBridge(node);
533         }
534     }
535     @Override
536     public void setDependencies(ServiceReference serviceReference) {
537         configurationService =
538                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
539         networkingProviderManager =
540                 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
541         tenantNetworkManager =
542                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
543         bridgeConfigurationManager =
544                 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
545         nodeCacheManager =
546                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
547         nodeCacheManager.cacheListenerAdded(serviceReference, this);
548         neutronL3Adapter =
549                 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
550         distributedArpService =
551                 (DistributedArpService) ServiceHelper.getGlobalInstance(DistributedArpService.class, this);
552         southbound =
553                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
554         eventDispatcher =
555                 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
556         eventDispatcher.eventHandlerAdded(serviceReference, this);
557         ovsdbInventoryService =
558                 (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
559         ovsdbInventoryService.listenerAdded(this);
560         vlanProvider =
561                 (VLANProvider) ServiceHelper.getGlobalInstance(VLANProvider.class, this);
562         l2ForwardingProvider =
563                 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
564     }
565
566     @Override
567     public void setDependencies(Object impl) {
568         if (impl instanceof INeutronNetworkCRUD) {
569             neutronNetworkCache = (INeutronNetworkCRUD)impl;
570         } else if (impl instanceof L2ForwardingProvider) {
571             l2ForwardingProvider = (L2ForwardingProvider)impl;
572         }
573     }
574 }