Remove OvsdbConfigurationService
[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.MdsalUtils;
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.OvsdbTerminationPointAugmentation;
19 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
20 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
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
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, OvsdbType ovsdbType, Action action) {
78         logger.info("ovsdbUpdate: {} - {} - {}", node, ovsdbType, action);
79         this.enqueueEvent(new SouthboundEvent(node, ovsdbTypeToSouthboundEventType(ovsdbType), action));
80     }
81
82     public void processOvsdbNodeUpdate(Node node, Action action) {
83         if (action == Action.ADD) {
84             logger.info("processOvsdbNodeUpdate {}", node);
85             bridgeConfigurationManager.prepareNode(node);
86         } else {
87             logger.info("Not implemented yet: {}", action);
88         }
89     }
90
91     private void handleInterfaceUpdate (Node node, OvsdbTerminationPointAugmentation tp) {
92         logger.trace("handleInterfaceUpdate node: {}, tp: {}", node, tp);
93         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(tp);
94         if (network != null && !network.getRouterExternal()) {
95             logger.trace("handleInterfaceUpdate node: {}, tp: {}, network: {}", node, tp, network.getNetworkUUID());
96             tenantNetworkManager.programInternalVlan(node, tp, network);
97             neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
98             if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
99                 networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, tp);
100             }
101         } else {
102             logger.debug("No tenant network found on node: {} for interface: {}", node, tp);
103         }
104     }
105
106     private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
107                                         boolean isLastInstanceOnNode, NeutronNetwork network) {
108         logger.debug("handleInterfaceDelete: node: {}, isLastInstanceOnNode: {}, interface: {}",
109                 node, isLastInstanceOnNode, intf);
110
111         neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
112         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
113         if (isInterfaceOfInterest(intf, phyIfName)) {
114             // delete tunnel or physical interfaces
115             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
116                     network, node, intf, isLastInstanceOnNode);
117         } else if (network != null) {
118             // vlan doesn't need a tunnel endpoint
119             if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
120                 if (configurationService.getTunnelEndPoint(node) == null) {
121                     logger.error("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table");
122                     return;
123                 }
124             }
125             if (isLastInstanceOnNode & networkingProviderManager.getProvider(node).hasPerTenantTunneling()) {
126                 tenantNetworkManager.reclaimInternalVlan(node, network);
127             }
128             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
129                     network, node, intf, isLastInstanceOnNode);
130         }
131     }
132
133     private void triggerUpdates() {
134         List<Node> nodes = connectionService.getNodes();
135         if (nodes == null) return;
136         for (Node node : nodes) {
137             OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
138             if (bridge != null) {
139                 processBridgeUpdate(node, bridge);
140             }
141
142             List<TerminationPoint> tps = MdsalUtils.getTerminationPoints(node);
143             for (TerminationPoint tp : tps) {
144                 OvsdbTerminationPointAugmentation port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
145                 if (port != null) {
146                     processPortUpdate(node, port);
147                 }
148             }
149         }
150     }
151
152     private void processPortDelete(Node node, OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation,
153                                    Object context) {
154         logger.debug("processportDelete {}: {}", node, ovsdbTerminationPointAugmentation);
155         NeutronNetwork network = null;
156         if (context == null) {
157             network = tenantNetworkManager.getTenantNetwork(ovsdbTerminationPointAugmentation);
158         } else {
159             network = (NeutronNetwork)context;
160         }
161         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
162         if (isInterfaceOfInterest(ovsdbTerminationPointAugmentation, phyIfName)) {
163             this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, false, null);
164         } else if (network != null && !network.getRouterExternal()) {
165             logger.debug("Network {} : Delete interface {} attached to bridge {}", network.getNetworkUUID(),
166                     ovsdbTerminationPointAugmentation.getInterfaceUuid(), node);
167             try {
168                 OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class);
169                 if (ovsdbBridgeAugmentation != null) {
170                     List<TerminationPoint> terminationPoints = node.getTerminationPoint();
171                     if(!terminationPoints.isEmpty()){
172                         boolean isLastInstanceOnNode = true;
173                         for(TerminationPoint terminationPoint : terminationPoints) {
174                             OvsdbTerminationPointAugmentation tpAugmentation =
175                                     terminationPoint.getAugmentation( OvsdbTerminationPointAugmentation.class);
176                             if(tpAugmentation.getInterfaceUuid().equals(ovsdbTerminationPointAugmentation.getInterfaceUuid())) continue;
177                             NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(tpAugmentation);
178                             if (neutronNetwork != null && neutronNetwork.equals(network)) {
179                                 isLastInstanceOnNode = false;
180                                 break;
181                             }
182                         }
183                         this.handleInterfaceDelete(node, ovsdbTerminationPointAugmentation, isLastInstanceOnNode, network);
184                     }
185                 }
186             } catch (Exception e) {
187                 logger.error("Error fetching Interface Rows for node " + node, e);
188             }
189         }
190     }
191
192     private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint, List<String> phyIfName) {
193         return (SouthboundMapper.createOvsdbInterfaceType(
194                 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
195                 ||
196                 SouthboundMapper.createOvsdbInterfaceType(
197                         terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE)
198                 ||
199                 phyIfName.contains(terminationPoint.getName()));
200     }
201
202     /**
203      * Notification about an OpenFlow Node
204      *
205      * @param openFlowNode the {@link Node Node} of interest in the notification
206      * @param action the {@link Action}
207      * @see NodeCacheListener#notifyNode
208      */
209     @Override
210     public void notifyNode (Node openFlowNode, Action action) {
211         logger.info("notifyNode: Node {} update {}", openFlowNode, action);
212
213         if (action.equals(Action.ADD)) {
214             networkingProviderManager.getProvider(openFlowNode).initializeOFFlowRules(openFlowNode);
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 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                 processOvsdbNodeUpdate(ev.getNode(), ev.getAction());
235                 break;
236             case BRIDGE:
237                 processBridgeUpdate(ev.getNode(), ev.getAction());
238                 break;
239
240             case PORT:
241                 processPortUpdate(ev.getNode(), ev.getAction());
242                 break;
243
244             case OPENVSWITCH:
245                 processOpenVSwitchUpdate(ev.getNode(), ev.getAction());
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 processPortUpdate(Node node, Action action) {
256         switch (action) {
257             case ADD:
258             case UPDATE:
259                 processPortUpdate(node);
260                 break;
261             case DELETE:
262                 processPortDelete(node);
263                 break;
264         }
265     }
266
267     private void processPortDelete(Node node) {
268         List<TerminationPoint> terminationPoints = MdsalUtils.getTerminationPoints(node);
269         for (TerminationPoint terminationPoint : terminationPoints) {
270             processPortDelete(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class), null);
271         }
272     }
273
274     private void processPortUpdate(Node node) {
275         List<TerminationPoint> terminationPoints = MdsalUtils.getTerminationPoints(node);
276         for (TerminationPoint terminationPoint : terminationPoints) {
277             processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
278         }
279     }
280
281     private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port) {
282         logger.debug("processPortUpdate {} - {}", node, port);
283         NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
284         if (network != null && !network.getRouterExternal()) {
285             this.handleInterfaceUpdate(node, port);
286         }
287
288     }
289
290     private void processOpenVSwitchUpdate(Node node, Action action) {
291         switch (action) {
292             case ADD:
293             case UPDATE:
294                 processOpenVSwitchUpdate(node);
295                 break;
296             case DELETE:
297                 break;
298         }
299     }
300
301     private void processOpenVSwitchUpdate(Node node) {
302         // TODO this node might be the OvsdbNode and not have termination points
303         // Would need to change listener or grab tp nodes in here.
304         List<TerminationPoint> terminationPoints = MdsalUtils.getTerminationPoints(node);
305         for (TerminationPoint terminationPoint : terminationPoints) {
306             processPortUpdate(node, terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class));
307         }
308     }
309
310     private void processBridgeUpdate(Node node, Action action) {
311         OvsdbBridgeAugmentation bridge = MdsalUtils.readBridge(node);
312         switch (action) {
313             case ADD:
314             case UPDATE:
315                 processBridgeUpdate(node, bridge);
316                 break;
317             case DELETE:
318                 processBridgeDelete(node, bridge);
319                 break;
320         }
321     }
322
323     private void processBridgeDelete(Node node, OvsdbBridgeAugmentation bridge) {
324         logger.debug("processBridgeUpdate {}, {}", node, bridge);
325     }
326
327     private void processBridgeUpdate(Node node, OvsdbBridgeAugmentation bridge) {
328         logger.debug("processBridgeUpdate {}, {}", node, bridge);
329     }
330 }