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