Remove SouthboundMapper and SouthboundConstants dependencies
[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);
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: {}", node, tp);
86         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
87         if (network != null && !network.getRouterExternal()) {
88             logger.trace("handleInterfaceUpdate node: {}, tp: {}, network: {}", node, tp, network.getNetworkUUID());
89             tenantNetworkManager.programInternalVlan(node, tp, network);
90             neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
91             if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
92                 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
93             }
94         } else {
95             logger.debug("No tenant network found on node: {} for interface: {}", node, tp);
96         }
97     }
98
99     private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
100                                         boolean isLastInstanceOnNode, NeutronNetwork network) {
101         logger.debug("handleInterfaceDelete: node: {}, isLastInstanceOnNode: {}, interface: {}",
102                 node, isLastInstanceOnNode, intf);
103
104         neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
105         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
106         if (isInterfaceOfInterest(intf, phyIfName)) {
107             // delete tunnel or physical interfaces
108             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
109                     network, node, intf, isLastInstanceOnNode);
110         } else if (network != null) {
111             // vlan doesn't need a tunnel endpoint
112             if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
113                 if (configurationService.getTunnelEndPoint(node) == null) {
114                     logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
115                     return;
116                 }
117             }
118             if (isLastInstanceOnNode & networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
119                 tenantNetworkManager.reclaimInternalVlan(node, network);
120             }
121             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
122                     network, node, intf, isLastInstanceOnNode);
123         }
124     }
125
126     private void triggerUpdates() {
127         List<Node> nodes = connectionService.getNodes();
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");
160             }
161         } else if (network != null && !network.getRouterExternal()) {
162             logger.debug("Network {} : Delete interface {} attached to bridge {}", network.getNetworkUUID(),
163                     ovsdbTerminationPointAugmentation.getInterfaceUuid(), node);
164             try {
165                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
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(ovsdbTerminationPointAugmentation.getInterfaceUuid())) continue;
174                             NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
175                             if (neutronNetwork != null && neutronNetwork.equals(network)) {
176                                 isLastInstanceOnNode = false;
177                                 break;
178                             }
179                         }
180                         this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation,
181                                 isLastInstanceOnNode, network);
182                     }
183                 }
184             } catch (Exception e) {
185                 logger.error("Error fetching Interface Rows for node " + node, e);
186             }
187         }
188     }
189
190     private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
191         return (MdsalHelper.createOvsdbInterfaceType(
192                 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
193                 ||
194                 MdsalHelper.createOvsdbInterfaceType(
195                         terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
196                 ||
197                 phyIfName.contains(terminationPoint.getName()));
198     }
199
200     /**
201      * Notification about an OpenFlow Node
202      *
203      * @param node the {@link Node Node} of interest in the notification
204      * @param action the {@link Action}
205      * @see NodeCacheListener#notifyNode
206      */
207     @Override
208     public void notifyNode (Node node, Action action) {
209         logger.info("notifyNode: Node {} update {}", node, action);
210
211         if (action.equals(Action.ADD)) {
212             if (MdsalUtils.getBridge(node) != null) {
213                 networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
214             }
215         }
216     }
217
218     /**
219      * Process the event.
220      *
221      * @param abstractEvent the {@link org.opendaylight.ovsdb.openstack.netvirt.AbstractEvent} event to be handled.
222      * @see org.opendaylight.ovsdb.openstack.netvirt.api.EventDispatcher
223      */
224     @Override
225     public void processEvent(AbstractEvent abstractEvent) {
226         if (!(abstractEvent instanceof SouthboundEvent)) {
227             logger.error("Unable to process abstract event " + abstractEvent);
228             return;
229         }
230         SouthboundEvent ev = (SouthboundEvent) abstractEvent;
231         logger.info("processEvent: {}", ev);
232         switch (ev.getType()) {
233             case NODE:
234                 processOvsdbNodeEvent(ev);
235                 break;
236             case BRIDGE:
237                 processBridgeEvent(ev);
238                 break;
239
240             case PORT:
241                 processPortEvent(ev);
242                 break;
243
244             case OPENVSWITCH:
245                 processOpenVSwitchEvent(ev);
246                 break;
247
248             default:
249                 logger.warn("Unable to process type " + ev.getType() +
250                         " action " + ev.getAction() + " for node " + ev.getNode());
251                 break;
252         }
253     }
254
255     private void processOvsdbNodeEvent(SouthboundEvent ev) {
256         switch (ev.getAction()) {
257             case ADD:
258                 processOvsdbNodeCreate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
259                 break;
260             case UPDATE:
261                 processOvsdbNodeUpdate(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
262                 break;
263             case DELETE:
264                 processOvsdbNodeDelete(ev.getNode(), (OvsdbNodeAugmentation) ev.getAugmentationData());
265                 break;
266         }
267     }
268
269     private void processOvsdbNodeCreate(Node node, OvsdbNodeAugmentation ovsdbNode) {
270         logger.info("processOvsdbNodeCreate {} - {}", node, ovsdbNode);
271         nodeCacheManager.nodeAdded(node);
272         bridgeConfigurationManager.prepareNode(node);
273     }
274
275     private void processOvsdbNodeUpdate(Node node, OvsdbNodeAugmentation ovsdbNode) {
276         logger.info("processOvsdbNodeUpdate {} - {}", node, ovsdbNode);
277         nodeCacheManager.nodeAdded(node);
278     }
279
280     private void processOvsdbNodeDelete(Node node, OvsdbNodeAugmentation ovsdbNode) {
281         logger.info("processOvsdbNodeDelete {} - {}", node, ovsdbNode);
282         nodeCacheManager.nodeRemoved(node);
283         /* TODO SB_MIGRATION
284         * I don't think we want to do this yet
285         InstanceIdentifier<Node> bridgeNodeIid =
286                 MdsalHelper.createInstanceIdentifier(ovsdbNode.getConnectionInfo(),
287                         Constants.INTEGRATION_BRIDGE);
288         MdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid);
289         */
290     }
291
292     private void processPortEvent(SouthboundEvent ev) {
293         switch (ev.getAction()) {
294             case ADD:
295             case UPDATE:
296                 processPortUpdate(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData());
297                 break;
298             case DELETE:
299                 processPortDelete(ev.getNode(), (OvsdbTerminationPointAugmentation) ev.getAugmentationData(), null);
300                 break;
301         }
302     }
303
304     private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
305         logger.debug("processPortUpdate {} - {}", node, port);
306         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
307         if (network != null && !network.getRouterExternal()) {
308             this.handleInterfaceUpdate(node, port);
309         }
310
311     }
312
313     private void processOpenVSwitchEvent(SouthboundEvent ev) {
314         switch (ev.getAction()) {
315             case ADD:
316             case UPDATE:
317                 processOpenVSwitchUpdate(ev.getNode());
318                 break;
319             case DELETE:
320                 break;
321         }
322     }
323
324     private void processOpenVSwitchUpdate(Node node) {
325         logger.debug("processOpenVSwitchUpdate {}", node);
326         // TODO this node might be the OvsdbNode and not have termination points
327         // Would need to change listener or grab tp nodes in here.
328         List<TerminationPoint> terminationPoints = MdsalUtils.extractTerminationPoints(node);
329         for (TerminationPoint terminationPoint : terminationPoints) {
330             processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
331         }
332     }
333
334     private void processBridgeEvent(SouthboundEvent ev) {
335         switch (ev.getAction()) {
336             case ADD:
337             case UPDATE:
338                 processBridgeUpdate(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
339                 break;
340             case DELETE:
341                 processBridgeDelete(ev.getNode(), (OvsdbBridgeAugmentation) ev.getAugmentationData());
342                 break;
343         }
344     }
345
346     private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
347         logger.debug("processBridgeUpdate {}, {}", node, bridge);
348         String datapathId = MdsalUtils.getDatapathId(bridge);
349         // Having a datapathId means the bridge has connected so it exists
350         if (datapathId != null) {
351             nodeCacheManager.nodeAdded(node);
352         } else {
353             logger.info("dataPathId not found");
354         }
355     }
356
357     private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
358         logger.debug("processBridgeDelete: Delete bridge from config data store : {}", node.getNodeId());
359         nodeCacheManager.nodeRemoved(node);
360         // TODO SB_MIGRATION
361         // Not sure if we want to do this yet
362         //MdsalUtils.deleteBridge(node);
363     }
364 }