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