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