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