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