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