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