Fix NPE triggered after disabling SG on a port
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / netvirt / openstack / netvirt / PortHandler.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.net.HttpURLConnection;
12 import java.util.List;
13
14 import org.opendaylight.netvirt.openstack.netvirt.api.Action;
15 import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
16 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
17 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
18 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
19 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
20 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
21 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
22 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
23 import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.INeutronPortAware;
24 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
25 import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
26 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
27 import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
28 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
31
32 import org.osgi.framework.ServiceReference;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * Handle requests for Neutron Port.
38  */
39 public class PortHandler extends AbstractHandler implements INeutronPortAware, NodeCacheListener, ConfigInterface {
40     private static final Logger LOG = LoggerFactory.getLogger(PortHandler.class);
41
42     // The implementation for each of these services is resolved by the OSGi Service Manager
43     private volatile NodeCacheManager nodeCacheManager;
44     private volatile BridgeConfigurationManager bridgeConfigurationManager;
45     private volatile TenantNetworkManager tenantNetworkManager;
46     private volatile NetworkingProviderManager networkingProviderManager;
47     private volatile NeutronL3Adapter neutronL3Adapter;
48     private volatile Southbound southbound;
49     private volatile INeutronPortCRUD neutronPortCache;
50
51     /**
52      * Invoked when a port creation is requested
53      * to indicate if the specified port can be created.
54      *
55      * @param port     An instance of proposed new Port object.
56      * @return A HTTP status code to the creation request.
57      */
58     @Override
59     public int canCreatePort(NeutronPort port) {
60         return HttpURLConnection.HTTP_OK;
61     }
62
63     /**
64      * Invoked to take action after a port has been created.
65      *
66      * @param neutronPort An instance of new Neutron Port object.
67      */
68     @Override
69     public void neutronPortCreated(NeutronPort neutronPort) {
70         enqueueEvent(new NorthboundEvent(neutronPort, Action.ADD));
71     }
72     private void doNeutronPortCreated(NeutronPort neutronPort) {
73         LOG.debug(" Port-ADD successful for tenant-id - {}, network-id - {}, port-id - {}",
74                      neutronPort.getTenantID(), neutronPort.getNetworkUUID(),
75                      neutronPort.getID());
76
77         //TODO: Need to implement getNodes
78         List<Node> nodes = nodeCacheManager.getNodes();
79         for (Node node : nodes) {
80             OvsdbTerminationPointAugmentation port = findPortOnNode(node, neutronPort);
81             // if the port already exist on the node it means that the southbound event already arrived
82             // and was not handled because we could not find the tenant network
83             if (port != null) {
84                 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
85                 if (network != null && !network.getRouterExternal()) {
86                     LOG.trace("handleInterfaceUpdate <{}> <{}> network: {}", node, port, network.getNetworkUUID());
87                     if (bridgeConfigurationManager.createLocalNetwork(node, network)) {
88                         networkingProviderManager.getProvider(node).handleInterfaceUpdate(network, node, port);
89                     }
90                 }
91                 break;
92             }
93         }
94
95         neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.ADD);
96     }
97
98     /**
99      * Invoked when a port update is requested
100      * to indicate if the specified port can be changed
101      * using the specified delta.
102      *
103      * @param delta    Updates to the port object using patch semantics.
104      * @param original An instance of the Neutron Port object
105      *                  to be updated.
106      * @return A HTTP status code to the update request.
107      */
108     @Override
109     public int canUpdatePort(NeutronPort delta,
110                              NeutronPort original) {
111         return HttpURLConnection.HTTP_OK;
112     }
113
114     /**
115      * Invoked to take action after a port has been updated.
116      *
117      * @param neutronPort An instance of modified Neutron Port object.
118      */
119     @Override
120     public void neutronPortUpdated(NeutronPort neutronPort) {
121         enqueueEvent(new NorthboundEvent(neutronPort, Action.UPDATE));
122     }
123     private void doNeutronPortUpdated(NeutronPort neutronPort) {
124         LOG.debug("Handling neutron update port {}", neutronPort);
125         neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.UPDATE);
126     }
127
128     /**
129      * Invoked when a port deletion is requested
130      * to indicate if the specified port can be deleted.
131      *
132      * @param port     An instance of the Neutron Port object to be deleted.
133      * @return A HTTP status code to the deletion request.
134      */
135     @Override
136     public int canDeletePort(NeutronPort port) {
137         return HttpURLConnection.HTTP_OK;
138     }
139
140     /**
141      * Invoked to take action after a port has been deleted.
142      *
143      * @param neutronPort  An instance of deleted Neutron Port object.
144      */
145     @Override
146     public void neutronPortDeleted(NeutronPort neutronPort) {
147         enqueueEvent(new NorthboundEvent(neutronPort, Action.DELETE));
148     }
149     private void doNeutronPortDeleted(NeutronPort neutronPort) {
150         LOG.debug("Handling neutron delete port {}", neutronPort);
151         neutronL3Adapter.handleNeutronPortEvent(neutronPort, Action.DELETE);
152
153         //TODO: Need to implement getNodes
154         List<Node> nodes = nodeCacheManager.getNodes();
155         for (Node node : nodes) {
156             OvsdbTerminationPointAugmentation port = findPortOnNode(node, neutronPort);
157             if (port != null) {
158                 LOG.trace("neutronPortDeleted: Delete interface {}", port.getName());
159                 southbound.deleteTerminationPoint(node, port.getName());
160                 break;
161             }
162         }
163
164         LOG.debug(" PORT delete successful for tenant-id - {}, network-id - {}, port-id - {}",
165                      neutronPort.getTenantID(), neutronPort.getNetworkUUID(),
166                      neutronPort.getID());
167     }
168
169     private OvsdbTerminationPointAugmentation findPortOnNode(Node node, NeutronPort neutronPort){
170         try {
171             List<OvsdbTerminationPointAugmentation> ports = southbound.readTerminationPointAugmentations(node);
172             for (OvsdbTerminationPointAugmentation port : ports) {
173                 String neutronPortId =
174                         southbound.getInterfaceExternalIdsValue(port, Constants.EXTERNAL_ID_INTERFACE_ID);
175                 if (neutronPortId != null && neutronPortId.equalsIgnoreCase(neutronPort.getPortUUID())) {
176                     return port;
177                 }
178             }
179         } catch (Exception e) {
180             LOG.error("Exception while reading ports", e);
181         }
182         return null;
183     }
184
185     @Override
186     public void notifyNode(Node node, Action action) {
187         if (action == Action.ADD) {
188             List<NeutronPort> neutronPorts = neutronPortCache.getAllPorts();
189             for (NeutronPort neutronPort : neutronPorts) {
190                 LOG.info("in notifyNode, neutronPort {} will be added", neutronPort);
191                 neutronPortCreated(neutronPort);
192             }
193         }
194     }
195
196     /**
197      * Process the event.
198      *
199      * @param abstractEvent the {@link AbstractEvent} event to be handled.
200      * @see EventDispatcher
201      */
202     @Override
203     public void processEvent(AbstractEvent abstractEvent) {
204         if (!(abstractEvent instanceof NorthboundEvent)) {
205             LOG.error("Unable to process abstract event {}", abstractEvent);
206             return;
207         }
208         NorthboundEvent ev = (NorthboundEvent) abstractEvent;
209         switch (ev.getAction()) {
210             case ADD:
211                 doNeutronPortCreated(ev.getPort());
212                 break;
213             case DELETE:
214                 doNeutronPortDeleted(ev.getPort());
215                 break;
216             case UPDATE:
217                 doNeutronPortUpdated(ev.getPort());
218                 break;
219             default:
220                 LOG.warn("Unable to process event action {}", ev.getAction());
221                 break;
222         }
223     }
224
225     @Override
226     public void setDependencies(ServiceReference serviceReference) {
227         nodeCacheManager =
228                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
229         nodeCacheManager.cacheListenerAdded(serviceReference, this);
230         networkingProviderManager =
231                 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
232         tenantNetworkManager =
233                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
234         bridgeConfigurationManager =
235                 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
236         neutronL3Adapter =
237                 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
238         southbound =
239                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
240         eventDispatcher =
241                 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
242         eventDispatcher.eventHandlerAdded(serviceReference, this);
243
244     }
245
246     @Override
247     public void setDependencies(Object impl) {
248         if (impl instanceof INeutronPortCRUD) {
249             neutronPortCache = (INeutronPortCRUD)impl;
250         }
251     }
252 }