Use config instead of Activator for netvirt and netvirt-providers
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / SouthboundHandler.java
1 /*
2  * Copyright (C) 2013 Red Hat, Inc.
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 package org.opendaylight.ovsdb.openstack.netvirt;
9
10 import java.util.List;
11
12 import org.opendaylight.neutron.spi.NeutronNetwork;
13 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
14 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
15 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
19 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
20 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.osgi.framework.BundleContext;
23 import org.osgi.framework.ServiceReference;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * @author Madhu Venugopal
29  * @author Brent Salisbury
30  * @author Dave Tucker
31  * @author Sam Hague (shague@redhat.com)
32  */
33 public class SouthboundHandler extends AbstractHandler
34         implements ConfigInterface, NodeCacheListener, OvsdbInventoryListener {
35     static final Logger logger = LoggerFactory.getLogger(SouthboundHandler.class);
36
37     // The implementation for each of these services is resolved by the OSGi Service Manager
38     private volatile ConfigurationService configurationService;
39     private volatile BridgeConfigurationManager bridgeConfigurationManager;
40     private volatile TenantNetworkManager tenantNetworkManager;
41     private volatile NetworkingProviderManager networkingProviderManager;
42     private volatile NeutronL3Adapter neutronL3Adapter;
43     private volatile NodeCacheManager nodeCacheManager = null;
44     private volatile EventDispatcher eventDispatcher;
45     private volatile OvsdbInventoryService ovsdbInventoryService;
46
47     void start() {
48         this.triggerUpdates();
49     }
50
51     /*void init() {
52         logger.info(">>>>>> init {}", this.getClass());
53     }*/
54
55     private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
56         SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
57
58         switch (ovsdbType) {
59             case NODE:
60                 type = SouthboundEvent.Type.NODE;
61                 break;
62             case BRIDGE:
63                 type = SouthboundEvent.Type.BRIDGE;
64                 break;
65             case PORT:
66                 type = SouthboundEvent.Type.PORT;
67                 break;
68             case CONTROLLER:
69                 type = SouthboundEvent.Type.CONTROLLER;
70                 break;
71             case OPENVSWITCH:
72                 type = SouthboundEvent.Type.OPENVSWITCH;
73                 break;
74             default:
75                 logger.warn("Invalid OvsdbType: {}", ovsdbType);
76                 break;
77         }
78         return type;
79     }
80
81     @Override
82     public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
83         logger.info("ovsdbUpdate: {} - {} - <<{}>> <<{}>>", ovsdbType, action, node, resourceAugmentationData);
84         enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
85                 ovsdbTypeToSouthboundEventType(ovsdbType), action));
86     }
87
88     private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
89         logger.debug("handleInterfaceUpdate <{}> <{}>", node, tp);
90         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
91         if (network != null && !network.getRouterExternal()) {
92             logger.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, tp, network.getNetworkUUID());
93             neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
94             if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
95                 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
96             }
97         } else {
98             logger.debug("No tenant network found on node: <{}> for interface: <{}>", node, tp);
99         }
100     }
101
102     private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
103                                         boolean isLastInstanceOnNode, NeutronNetwork network) {
104         logger.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
105                 node, isLastInstanceOnNode, intf);
106
107         neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
108         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
109         if (isInterfaceOfInterest(intf, phyIfName)) {
110             // delete tunnel or physical interfaces
111             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
112                     network, node, intf, isLastInstanceOnNode);
113         } else if (network != null) {
114             // vlan doesn't need a tunnel endpoint
115             if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
116                 if (configurationService.getTunnelEndPoint(node) == null) {
117                     logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
118                     return;
119                 }
120             }
121             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
122                     network, node, intf, isLastInstanceOnNode);
123         }
124     }
125
126     private void triggerUpdates() {
127         List<Node> nodes = null; // nodeCacheManager.getBridgeNodes();
128         if (nodes == null) return;
129         for (Node node : nodes) {
130             OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
131             if (bridge != null) {
132                 processBridgeUpdate(node, bridge);
133             }
134
135             List<TerminationPoint> tps = MdsalUtils.extractTerminationPoints(node);
136             for (TerminationPoint tp : tps) {
137                 OvsdbTerminationPointAugmentation port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
138                 if (port != null) {
139                     processPortUpdate(node, port);
140                 }
141             }
142         }
143     }
144
145     private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
146                                    Object context) {
147         logger.debug("processPortDelete <{}> <{}>", node, ovsdbTerminationPointAugmentation);
148         NeutronNetwork network = null;
149         if (context == null) {
150             network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
151         } else {
152             network = (NeutronNetwork)context;
153         }
154         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
155         if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
156             if (network != null) {
157                 this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, network);
158             } else {
159                 logger.warn("processPortDelete: network was null, ignoring update");
160             }
161         } else if (network != null && !network.getRouterExternal()) {
162             logger.debug("Network {}: Delete interface {} attached to bridge {}", network.getNetworkUUID(),
163                     ovsdbTerminationPointAugmentation.getInterfaceUuid(), node.getNodeId());
164             try {
165                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = MdsalUtils.getBridge(node);
166                 if (ovsdbBridgeAugmentation != null) {
167                     List<TerminationPoint> terminationPoints = node.getTerminationPoint();
168                     if (!terminationPoints.isEmpty()){
169                         boolean isLastInstanceOnNode = true;
170                         for (TerminationPoint terminationPoint : terminationPoints) {
171                             OvsdbTerminationPointAugmentation tpAugmentation =
172                                     terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
173                             if (tpAugmentation.getInterfaceUuid().equals(
174                                     ovsdbTerminationPointAugmentation.getInterfaceUuid())) {
175                                 continue;
176                             }
177                             NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
178                             if (neutronNetwork != null && neutronNetwork.equals(network)) {
179                                 isLastInstanceOnNode = false;
180                                 break;
181                             }
182                         }
183                         this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
184                                 isLastInstanceOnNode, network);
185                     }
186                 }
187             } catch (Exception e) {
188                 logger.error("Error fetching Interface Rows for node " + node, e);
189             }
190         }
191     }
192
193     private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
194         logger.trace("SouthboundHandler#isInterfaceOfInterest: Interface : {}", terminationPoint);
195
196         if(terminationPoint.getInterfaceType() == null){
197             // This is OK since eth ports don't have an interface type
198             logger.info("No type found for the interface : {}", terminationPoint);
199             return false;
200         }
201         return (MdsalHelper.createOvsdbInterfaceType(
202                 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
203                 ||
204                 MdsalHelper.createOvsdbInterfaceType(
205                         terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
206                 ||
207                 phyIfName.contains(terminationPoint.getName()));
208     }
209
210     /**
211      * Notification about an OpenFlow Node
212      *
213      * @param node the {@link Node Node} of interest in the notification
214      * @param action the {@link Action}
215      * @see NodeCacheListener#notifyNode
216      */
217     @Override
218     public void notifyNode (Node node, Action action) {
219         logger.info("notifyNode: action: {}, Node <{}>", action, node);
220
221         if (action.equals(Action.ADD)) {
222             if (MdsalUtils.getBridge(node) != null) {
223                 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
224             }
225         }
226     }
227
228     /**
229      * Process the event.
230      *
231      * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
232      * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
233      */
234     @Override
235     public void processEvent(AbstractEvent abstractEvent) {
236         if (!(abstractEvent instanceof SouthboundEvent)) {
237             logger.error("processEvent: Unable to process abstract event {}", abstractEvent);
238             return;
239         }
240         SouthboundEvent ev = (SouthboundEvent) abstractEvent;
241         logger.trace("processEvent: {}", ev);
242         switch (ev.getType()) {
243             case NODE:
244                 processOvsdbNodeEvent(ev);
245                 break;
246
247             case BRIDGE:
248                 processBridgeEvent(ev);
249                 break;
250
251             case PORT:
252                 processPortEvent(ev);
253                 break;
254
255             case OPENVSWITCH:
256                 processOpenVSwitchEvent(ev);
257                 break;
258
259             default:
260                 logger.warn("Unable to process type " + ev.getType() +
261                         " action " + ev.getAction() + " for node " + ev.getNode());
262                 break;
263         }
264     }
265
266     private void processOvsdbNodeEvent(SouthboundEvent ev) {
267         switch (ev.getAction()) {
268             case ADD:
269                 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
270                 break;
271             case UPDATE:
272                 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
273                 break;
274             case DELETE:
275                 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
276                 break;
277         }
278     }
279
280     private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
281         logger.info("processOvsdbNodeCreate <{}> <{}>", node, ovsdbNode);
282         nodeCacheManager.nodeAdded(node);
283         bridgeConfigurationManager.prepareNode(node);
284     }
285
286     private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
287         logger.info("processOvsdbNodeUpdate <{}> <{}>", node, ovsdbNode);
288         nodeCacheManager.nodeAdded(node);
289     }
290
291     private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
292         logger.info("processOvsdbNodeDelete <{}> <{}>", node, ovsdbNode);
293         nodeCacheManager.nodeRemoved(node);
294         /* TODO SB_MIGRATION
295         * I don't think we want to do this yet
296         InstanceIdentifier<Node> bridgeNodeIid =
297                 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
298                         Constants.INTEGRATION_BRIDGE);
299         MdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
300         */
301     }
302
303     private void processPortEvent(SouthboundEvent ev) {
304         switch (ev.getAction()) {
305             case ADD:
306             case UPDATE:
307                 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
308                 break;
309             case DELETE:
310                 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
311                 break;
312         }
313     }
314
315     private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
316         logger.debug("processPortUpdate <{}> <{}>", node, port);
317         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
318         if (network != null && !network.getRouterExternal()) {
319             this.handleInterfaceUpdate(node, port);
320         }
321     }
322
323     private void processOpenVSwitchEvent(SouthboundEvent ev) {
324         switch (ev.getAction()) {
325             case ADD:
326             case UPDATE:
327                 processOpenVSwitchUpdate(ev.getNode());
328                 break;
329             case DELETE:
330                 break;
331         }
332     }
333
334     private void processOpenVSwitchUpdate(Node node) {
335         logger.debug("processOpenVSwitchUpdate {}", node);
336         // TODO this node might be the OvsdbNode and not have termination points
337         // Would need to change listener or grab tp nodes in here.
338         List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
339         for (TerminationPoint terminationPoint : terminationPoints) {
340             processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
341         }
342     }
343
344     private void processBridgeEvent(SouthboundEvent ev) {
345         switch (ev.getAction()) {
346             case ADD:
347                 processBridgeCreate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
348                 break;
349             case UPDATE:
350                 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
351                 break;
352             case DELETE:
353                 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
354                 break;
355         }
356     }
357
358     private boolean isMainBridge(Node node, OvsdbBridgeAugmentation bridge) {
359         boolean rv = false;
360         String nodeIdStr = node.getNodeId().getValue();
361         String bridgeName = nodeIdStr.substring(nodeIdStr.lastIndexOf('/') + 1);
362         List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
363         if (terminationPoints != null && terminationPoints.size() == 1) {
364         }
365         OvsdbTerminationPointAugmentation port = MdsalUtils.extractTerminationPointAugmentation(node, bridgeName);
366         if (port != null) {
367             String datapathId = MdsalUtils.getDatapathId(bridge);
368             // Having a datapathId means the ovsdb node has connected to ODL
369             if (datapathId != null) {
370                 rv = true;
371             } else {
372                 logger.info("datapathId not found");
373             }
374         }
375         return rv;
376     }
377
378     private void processBridgeCreate(Node node, OvsdbBridgeAugmentation bridge) {
379         logger.debug("processBridgeCreate <{}> <{}>", node, bridge);
380         String datapathId = MdsalUtils.getDatapathId(bridge);
381         // Having a datapathId means the ovsdb node has connected to ODL
382         if (datapathId != null) {
383             nodeCacheManager.nodeAdded(node);
384         } else {
385             logger.info("processBridgeCreate datapathId not found");
386         }
387     }
388
389     private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
390         logger.debug("processBridgeUpdate <{}> <{}>", node, bridge);
391         String datapathId = MdsalUtils.getDatapathId(bridge);
392         // Having a datapathId means the ovsdb node has connected to ODL
393         if (datapathId != null) {
394             nodeCacheManager.nodeAdded(node);
395         } else {
396             logger.info("processBridgeUpdate datapathId not found");
397         }
398     }
399
400     private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
401         logger.debug("processBridgeDelete: Delete bridge from config data store: <{}> <{}>",
402                 node, bridge);
403         nodeCacheManager.nodeRemoved(node);
404         // TODO SB_MIGRATION
405         // Not sure if we want to do this yet
406         MdsalUtils.deleteBridge(node);
407     }
408
409     @Override
410     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
411         configurationService =
412                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
413         networkingProviderManager =
414                 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
415         tenantNetworkManager =
416                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
417         bridgeConfigurationManager =
418                 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
419         nodeCacheManager =
420                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
421         nodeCacheManager.cacheListenerAdded(
422                 bundleContext.getServiceReference(OvsdbInventoryListener.class.getName()), this);
423         neutronL3Adapter =
424                 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
425         eventDispatcher =
426                 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
427         eventDispatcher.eventHandlerAdded(
428                 bundleContext.getServiceReference(OvsdbInventoryListener.class.getName()), this);
429         super.setDispatcher(eventDispatcher);
430         ovsdbInventoryService =
431                 (OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
432         ovsdbInventoryService.listenerAdded(this);
433     }
434
435     @Override
436     public void setDependencies(Object impl) {}
437 }