Bug 3563 - Fix/clean methods that determine the OpenFlow Controller ip address
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / impl / BridgeConfigurationManagerImpl.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.impl;
9
10 import org.opendaylight.neutron.spi.NeutronNetwork;
11 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
12 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
13 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
14 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
15 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
16 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbTables;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
19 import org.opendaylight.ovsdb.utils.config.ConfigProperties;
20 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
25
26 import com.google.common.base.Preconditions;
27 import com.google.common.collect.Lists;
28
29 import java.net.InetAddress;
30 import java.net.NetworkInterface;
31 import java.net.UnknownHostException;
32 import java.util.Enumeration;
33 import java.util.List;
34
35 import org.apache.commons.lang3.tuple.ImmutablePair;
36 import org.osgi.framework.BundleContext;
37 import org.osgi.framework.ServiceReference;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * @author Madhu Venugopal
43  * @author Brent Salisbury
44  * @author Sam Hague (shague@redhat.com)
45  */
46 public class BridgeConfigurationManagerImpl implements BridgeConfigurationManager, ConfigInterface {
47     static final Logger LOGGER = LoggerFactory.getLogger(BridgeConfigurationManagerImpl.class);
48
49     // The implementation for each of these services is resolved by the OSGi Service Manager
50     private volatile ConfigurationService configurationService;
51     private volatile NetworkingProviderManager networkingProviderManager;
52     private volatile Southbound southbound;
53
54     public void setConfigurationService(ConfigurationService configurationService) {
55         this.configurationService = configurationService;
56     }
57
58     public void setSouthbound(Southbound southbound) {
59         this.southbound = southbound;
60     }
61
62     @Override
63     public String getBridgeUuid(Node node, String bridgeName) {
64         return southbound.getBridgeUuid(node, bridgeName);
65     }
66
67     @Override
68     public boolean isNodeNeutronReady(Node node) {
69         Preconditions.checkNotNull(configurationService);
70         return southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null;
71     }
72
73     @Override
74     public boolean isNodeOverlayReady(Node node) {
75         Preconditions.checkNotNull(configurationService);
76         return isNodeNeutronReady(node)
77                 && southbound.getBridge(node, configurationService.getNetworkBridgeName()) != null;
78     }
79
80     @Override
81     public boolean isPortOnBridge (Node node, String portName) {
82         return southbound.extractTerminationPointAugmentation(node, portName) != null;
83     }
84
85     @Override
86     public boolean isNodeTunnelReady(Node node) {
87         Preconditions.checkNotNull(configurationService);
88         return southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null;
89     }
90
91     @Override
92     public boolean isNodeVlanReady(Node node, NeutronNetwork network) {
93         Preconditions.checkNotNull(configurationService);
94
95         /* is br-int created */
96         OvsdbBridgeAugmentation intBridge = southbound.getBridge(node, configurationService.getIntegrationBridgeName());
97         if (intBridge == null) {
98             LOGGER.trace("isNodeVlanReady: node: {}, br-int missing", node);
99             return false;
100         }
101
102         /* Check if physical device is added to br-int. */
103         String phyNetName = getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
104         if (southbound.extractTerminationPointAugmentation(node, phyNetName) == null) {
105             LOGGER.trace("isNodeVlanReady: node: {}, eth missing", node);
106             return false;
107         }
108
109         return true;
110     }
111
112     @Override
113     public void prepareNode(Node node) {
114         //Preconditions.checkNotNull(networkingProviderManager);
115
116         try {
117             createIntegrationBridge(node);
118         } catch (Exception e) {
119             LOGGER.error("Error creating Integration Bridge on {}", node, e);
120             return;
121         }
122         // this node is an ovsdb node so it doesn't have a bridge
123         // so either look up the bridges or just wait for the bridge update to come in
124         // and add the flows there.
125         //networkingProviderManager.getProvider(node).initializeFlowRules(node);
126     }
127
128     /**
129      * Check if the full network setup is available. If not, create it.
130      */
131     @Override
132     public boolean createLocalNetwork (Node node, NeutronNetwork network) {
133         boolean isCreated = false;
134         if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
135             if (!isNodeVlanReady(node, network)) {
136                 try {
137                     isCreated = createBridges(node, network);
138                 } catch (Exception e) {
139                     LOGGER.error("Error creating internal net network " + node, e);
140                 }
141             } else {
142                 isCreated = true;
143             }
144         } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
145                    network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
146             if (!isNodeTunnelReady(node)) {
147                 try {
148                     isCreated = createBridges(node, network);
149                 } catch (Exception e) {
150                     LOGGER.error("Error creating internal net network " + node, e);
151                 }
152             } else {
153                 isCreated = true;
154             }
155         }
156         return isCreated;
157     }
158
159     @Override
160     public String getPhysicalInterfaceName (Node node, String physicalNetwork) {
161         String phyIf = null;
162         String providerMaps = southbound.getOtherConfig(node, OvsdbTables.OPENVSWITCH,
163                 configurationService.getProviderMappingsKey());
164         if (providerMaps == null) {
165             providerMaps = configurationService.getDefaultProviderMapping();
166         }
167
168         if (providerMaps != null) {
169             for (String map : providerMaps.split(",")) {
170                 String[] pair = map.split(":");
171                 if (pair[0].equals(physicalNetwork)) {
172                     phyIf = pair[1];
173                     break;
174                 }
175             }
176         }
177
178         if (phyIf == null) {
179             LOGGER.error("Physical interface not found for Node: {}, Network {}",
180                          node, physicalNetwork);
181         }
182
183         return phyIf;
184     }
185
186     @Override
187     public List<String> getAllPhysicalInterfaceNames(Node node) {
188         List<String> phyIfName = Lists.newArrayList();
189         String phyIf = null;
190         String providerMaps = southbound.getOtherConfig(node, OvsdbTables.OPENVSWITCH,
191                 configurationService.getProviderMappingsKey());
192         if (providerMaps == null) {
193             providerMaps = configurationService.getDefaultProviderMapping();
194         }
195
196         if (providerMaps != null) {
197             for (String map : providerMaps.split(",")) {
198                 String[] pair = map.split(":");
199                 phyIfName.add(pair[1]);
200             }
201         }
202
203         return phyIfName;
204     }
205
206     /**
207      * Returns true if a patch port exists between the Integration Bridge and Network Bridge
208      */
209     private boolean isNetworkPatchCreated(Node node, Node intBridge, Node netBridge) {
210         Preconditions.checkNotNull(configurationService);
211
212         boolean isPatchCreated = false;
213
214         String portName = configurationService.getPatchPortName(new ImmutablePair<>(intBridge, netBridge));
215         if (isPortOnBridge(intBridge, portName)) {
216             portName = configurationService.getPatchPortName(new ImmutablePair<>(netBridge, intBridge));
217             if (isPortOnBridge(netBridge, portName)) {
218                 isPatchCreated = true;
219             }
220         }
221
222         return isPatchCreated;
223     }
224
225     /**
226      * Creates the Integration Bridge
227      */
228     private void createIntegrationBridge(Node node) throws Exception {
229         Preconditions.checkNotNull(configurationService);
230
231         String brIntName = configurationService.getIntegrationBridgeName();
232
233         if (!addBridge(node, brIntName, null, null)) {
234             LOGGER.debug("Integration Bridge Creation failed");
235         }
236     }
237
238     /**
239      * Create and configure bridges for all network types and OpenFlow versions.
240      *
241        OF 1.0 vlan:
242        Bridge br-int
243             Port patch-net
244                 Interface patch-net
245                     type: patch
246                     options: {peer=patch-int}
247             Port br-int
248                 Interface br-int
249                     type: internal
250        Bridge br-net
251             Port "eth1"
252                 Interface "eth1"
253             Port patch-int
254                 Interface patch-int
255                     type: patch
256                     options: {peer=patch-net}
257             Port br-net
258                 Interface br-net
259                     type: internal
260
261        OF 1.0 tunnel:
262        Bridge br-int
263             Port patch-net
264                 Interface patch-net
265                     type: patch
266                     options: {peer=patch-int}
267             Port br-int
268                 Interface br-int
269                     type: internal
270        Bridge "br-net"
271             Port patch-int
272                 Interface patch-int
273                     type: patch
274                     options: {peer=patch-net}
275             Port br-net
276                 Interface br-net
277                     type: internal
278
279        OF 1.3 vlan:
280        Bridge br-int
281             Port "eth1"
282                 Interface "eth1"
283             Port br-int
284                 Interface br-int
285                     type: internal
286
287        OF 1.3 tunnel:
288        Bridge br-int
289             Port br-int
290                 Interface br-int
291                     type: internal
292      */
293     private boolean createBridges(Node node, NeutronNetwork network) throws Exception {
294         Preconditions.checkNotNull(configurationService);
295         Preconditions.checkNotNull(networkingProviderManager);
296
297         LOGGER.debug("createBridges: node: {}, network type: {}", node, network.getProviderNetworkType());
298
299         String brInt = configurationService.getIntegrationBridgeName();
300         if (!addBridge(node, brInt, null, null)) {
301             LOGGER.debug("{} Bridge creation failed", brInt);
302             return false;
303         }
304
305         /* For vlan network types add physical port to br-int. */
306         if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
307             String phyNetName = this.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
308             if (!addPortToBridge(node, brInt, phyNetName)) {
309                 LOGGER.debug("Add Port {} to Bridge {} failed", phyNetName, brInt);
310                 return false;
311             }
312         }
313
314         LOGGER.debug("createBridges: node: {}, status: success", node);
315         return true;
316     }
317
318     /**
319      * Add a Port to a Bridge
320      */
321     private boolean addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
322         boolean rv = true;
323
324         if (southbound.extractTerminationPointAugmentation(node, portName) == null) {
325             rv = southbound.addTerminationPoint(node, bridgeName, portName, null);
326         }
327
328         return rv;
329     }
330
331     /**
332      * Add a Patch Port to a Bridge
333      */
334     private boolean addPatchPort (Node node, String bridgeName, String portName, String peerPortName) throws Exception {
335         boolean rv = true;
336
337         if (southbound.extractTerminationPointAugmentation(node, portName) == null) {
338             rv = southbound.addPatchTerminationPoint(node, bridgeName, portName, peerPortName);
339         }
340
341         return rv;
342     }
343
344     /**
345      * Add Bridge to a Node
346      */
347     private boolean addBridge(Node node, String bridgeName,
348                               String localPatchName, String remotePatchName) throws Exception {
349         boolean rv = true;
350         if (southbound.getBridge(node, bridgeName) == null) {
351             rv = southbound.addBridge(node, bridgeName, getControllerTarget(node));
352         }
353         return rv;
354     }
355
356     private String getControllerIPAddress() {
357         InetAddress controllerIP = null;
358
359         String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address");
360         if (addressString != null) {
361             try {
362                 controllerIP = InetAddress.getByName(addressString);
363                 if (controllerIP != null) {
364                     return addressString;
365                 }
366             } catch (UnknownHostException e) {
367                 LOGGER.error("Host {} is invalid", addressString);
368             }
369         }
370
371         addressString = ConfigProperties.getProperty(this.getClass(), "of.address");
372         if (addressString != null) {
373             try {
374                 controllerIP = InetAddress.getByName(addressString);
375                 if (controllerIP != null) {
376                     return addressString;
377                 }
378             } catch (UnknownHostException e) {
379                 LOGGER.error("Host {} is invalid", addressString);
380             }
381         }
382
383         return null;
384     }
385
386     private short getControllerOFPort() {
387         Short defaultOpenFlowPort = Constants.OPENFLOW_PORT;
388         Short openFlowPort = defaultOpenFlowPort;
389         String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort");
390         if (portString != null) {
391             try {
392                 openFlowPort = Short.decode(portString).shortValue();
393             } catch (NumberFormatException e) {
394                 LOGGER.warn("Invalid port:{}, use default({})", portString,
395                         openFlowPort);
396             }
397         }
398         return openFlowPort;
399     }
400
401     private String getControllerTarget(Node node) {
402         String setControllerStr = null;
403         String controllerIpStr = null;
404         short openflowPort = Constants.OPENFLOW_PORT;
405         //Look at user configuration.
406         //TODO: In case we move to config subsystem to expose these user facing parameter,
407         // we will have to modify this code.
408
409         controllerIpStr = getControllerIPAddress();
410
411         if(controllerIpStr == null){
412             // Check if ovsdb node has connection info
413             OvsdbNodeAugmentation ovsdbNodeAugmentation = southbound.extractOvsdbNode(node);
414             if (ovsdbNodeAugmentation != null) {
415                 ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo();
416                 if(connectionInfo != null && connectionInfo.getLocalIp() != null) {
417                     controllerIpStr = new String(connectionInfo.getLocalIp().getValue());
418                 }else{
419                     LOGGER.warn("Ovsdb Node does not contains connection info : {}",node);
420                 }
421             }
422         }else {
423             openflowPort = getControllerOFPort();
424         }
425
426         if(controllerIpStr == null) {
427             // Neither user provided ip nor ovsdb node has controller ip, Lets use local machine ip address
428             LOGGER.debug("Use local machine ip address as a OpenFlow Controller ip address");
429             controllerIpStr = getLocalControllerHostIpAddress();
430         }
431         if(controllerIpStr != null){
432             LOGGER.debug("Targe OpenFlow Controller found : {}",controllerIpStr);
433             setControllerStr = Constants.OPENFLOW_CONNECTION_PROTOCOL + ":" + controllerIpStr + ":" + openflowPort;
434         }else {
435             LOGGER.warn("Failed to determine OpenFlow controller ip address");
436         }
437         return setControllerStr;
438     }
439
440     private String getLocalControllerHostIpAddress() {
441         String ipaddress = null;
442         try{
443             for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();ifaces.hasMoreElements();){
444                 NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
445
446                 for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
447                     InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
448                     if (!inetAddr.isLoopbackAddress()) {
449                         if (inetAddr.isSiteLocalAddress()) {
450                             ipaddress = inetAddr.getHostAddress();
451                             break;
452                         }
453                     }
454                 }
455             }
456         }catch (Exception e){
457             LOGGER.warn("Exception while fetching local host ip address ",e);
458         }
459         return ipaddress;
460     }
461
462     @Override
463     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
464         configurationService =
465                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
466         networkingProviderManager =
467                 (NetworkingProviderManager) ServiceHelper.getGlobalInstance(NetworkingProviderManager.class, this);
468         southbound =
469                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
470     }
471
472     @Override
473     public void setDependencies(Object impl) {}
474 }