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