Merge "Adding Pax-Exam infra with a basic IT for plugin"
[netvirt.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / InternalNetworkManager.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  * Authors : Madhu Venugopal, Brent Salisbury, Sam Hague
9  */
10 package org.opendaylight.ovsdb.neutron;
11
12 import java.util.Map;
13
14 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
15 import org.opendaylight.controller.sal.core.Node;
16 import org.opendaylight.controller.sal.utils.ServiceHelper;
17 import org.opendaylight.controller.sal.utils.Status;
18 import org.opendaylight.controller.sal.utils.StatusCode;
19 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
20 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
21 import org.opendaylight.ovsdb.lib.notation.UUID;
22 import org.opendaylight.ovsdb.lib.table.Bridge;
23 import org.opendaylight.ovsdb.lib.table.Interface;
24 import org.opendaylight.ovsdb.lib.table.Port;
25 import org.opendaylight.ovsdb.lib.table.internal.Table;
26 import org.opendaylight.ovsdb.neutron.provider.IProviderNetworkManager;
27 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
28 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
29 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * OpenStack Neutron with the OpenvSwitch data plan relies on a typical OVS bridge configurations that
35  * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
36  *
37  * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
38  * Hence this class attempts to bring all the nodes to be eligible for OpenStack operations.
39  *
40  */
41 public class InternalNetworkManager implements IInternalNetworkManager {
42     static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
43     private static final int LLDP_PRIORITY = 1000;
44     private static final int NORMAL_PRIORITY = 0;
45
46     // The implementation for each of these services is resolved by the OSGi Service Manager
47     private volatile IAdminConfigManager adminConfigManager;
48     private volatile IProviderNetworkManager providerNetworkManager;
49
50     public InternalNetworkManager() {
51     }
52
53     public String getInternalBridgeUUID (Node node, String bridgeName) {
54         try {
55             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
56             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
57             if (bridgeTable == null) return null;
58             for (String key : bridgeTable.keySet()) {
59                 Bridge bridge = (Bridge)bridgeTable.get(key);
60                 if (bridge.getName().equals(bridgeName)) return key;
61             }
62         } catch (Exception e) {
63             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
64         }
65         return null;
66     }
67
68     public Bridge getInternalBridge (Node node, String bridgeName) {
69         try {
70             OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
71             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
72             if (bridgeTable != null) {
73                 for (String key : bridgeTable.keySet()) {
74                     Bridge bridge = (Bridge) bridgeTable.get(key);
75                     if (bridge.getName().equals(bridgeName)) {
76                         return bridge;
77                     }
78                 }
79             }
80         } catch (Exception e) {
81             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
82         }
83         return null;
84     }
85
86     public boolean isInternalNetworkNeutronReady(Node node) {
87         if (this.getInternalBridgeUUID(node, adminConfigManager.getIntegrationBridgeName()) != null) {
88             return true;
89         } else {
90             return false;
91         }
92     }
93
94     public boolean isInternalNetworkOverlayReady(Node node) {
95         if (!this.isInternalNetworkNeutronReady(node)) {
96             return false;
97         }
98         if (this.getInternalBridgeUUID(node, adminConfigManager.getNetworkBridgeName()) != null) {
99             return true;
100         } else {
101             return false;
102         }
103     }
104
105     public boolean isPortOnBridge (Node node, Bridge bridge, String portName) {
106         OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
107
108         for (UUID portsUUID : bridge.getPorts()) {
109             try {
110                 Port port = (Port) ovsdbTable.getRow(node, Port.NAME.getName(), portsUUID.toString());
111                 if ((port != null) && port.getName().equalsIgnoreCase(portName)) {
112                     return true;
113                 }
114             } catch (Exception e) {
115                 logger.error("Error getting port {} for bridge domain {}/{}", portsUUID, node, bridge.getName(), e);
116             }
117         }
118
119         return false;
120     }
121
122     public boolean isNetworkPatchCreated (Node node, Bridge intBridge, Bridge netBridge) {
123         boolean isPatchCreated = false;
124
125         String portName = adminConfigManager.getPatchToNetwork();
126         if (isPortOnBridge(node, intBridge, portName)) {
127             portName = adminConfigManager.getPatchToIntegration();
128             if (isPortOnBridge(node, netBridge, portName)) {
129                 isPatchCreated = true;
130             }
131         }
132
133         return isPatchCreated;
134     }
135
136     /* Determine if internal network is ready for tunnel network types.
137      * - OF 1.0 requires br-int, br-net and a patch connecting them.
138      * - OF 1.3 requires br-int.
139      */
140     public boolean isInternalNetworkTunnelReady (Node node) {
141         /* Is br-int created? */
142         Bridge intBridge = this.getInternalBridge(node, adminConfigManager.getIntegrationBridgeName());
143         if (intBridge == null) {
144             return false;
145         }
146
147         if (providerNetworkManager == null) {
148             logger.error("Provider Network Manager is not available");
149             return false;
150         }
151         if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
152             /* Is br-net created? */
153             Bridge netBridge = this.getInternalBridge(node, adminConfigManager.getNetworkBridgeName());
154             if (netBridge == null) {
155                 return false;
156             }
157
158             if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
159                 return false;
160             }
161         }
162         return true;
163     }
164
165     /* Determine if internal network is ready for vlan network types.
166      * - OF 1.0 requires br-int, br-net, a patch connecting them and
167      * physical device added to br-net.
168      * - OF 1.3 requires br-int and physical device added to br-int.
169      */
170     public boolean isInternalNetworkVlanReady (Node node, NeutronNetwork network) {
171         /* is br-int created */
172         Bridge intBridge = this.getInternalBridge(node, adminConfigManager.getIntegrationBridgeName());
173         if (intBridge == null) {
174             logger.trace("shague isInternalNetworkVlanReady: node: {}, br-int missing", node);
175             return false;
176         }
177
178         if (providerNetworkManager == null) {
179             logger.error("Provider Network Manager is not available");
180             return false;
181         }
182         if (providerNetworkManager.getProvider().hasPerTenantTunneling()) {
183             /* is br-net created? */
184             Bridge netBridge = this.getInternalBridge(node, adminConfigManager.getNetworkBridgeName());
185
186             if (netBridge == null) {
187                 logger.trace("shague isInternalNetworkVlanReady: node: {}, br-net missing", node);
188                 return false;
189             }
190
191             if (!isNetworkPatchCreated(node, intBridge, netBridge)) {
192                 logger.trace("shague isInternalNetworkVlanReady: node: {}, patch missing", node);
193                 return false;
194             }
195
196             /* Check if physical device is added to br-net. */
197             String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
198             if (isPortOnBridge(node, netBridge, phyNetName)) {
199                 return true;
200             }
201         } else {
202             /* Check if physical device is added to br-int. */
203             String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
204             if (isPortOnBridge(node, intBridge, phyNetName)) {
205                 return true;
206             }
207         }
208
209         logger.trace("shague isInternalNetworkVlanReady: node: {}, eth missing", node);
210         return false;
211     }
212
213     /*
214      * Create the integration bridge.
215      *
216        Bridge br-int
217             Port br-int
218                 Interface br-int
219                     type: internal
220      */
221     public void createIntegrationBridge (Node node) throws Exception {
222         String brInt = adminConfigManager.getIntegrationBridgeName();
223
224         Status status = this.addInternalBridge(node, brInt, null, null);
225         if (!status.isSuccess()) {
226             logger.debug("Integration Bridge Creation Status: {}", status);
227         }
228     }
229
230     /*
231      * Create complete network for all network types and OpenFlow versions.
232      *
233        OF 1.0 vlan:
234        Bridge br-int
235             Port patch-net
236                 Interface patch-net
237                     type: patch
238                     options: {peer=patch-int}
239             Port br-int
240                 Interface br-int
241                     type: internal
242        Bridge br-net
243             Port "eth1"
244                 Interface "eth1"
245             Port patch-int
246                 Interface patch-int
247                     type: patch
248                     options: {peer=patch-net}
249             Port br-net
250                 Interface br-net
251                     type: internal
252
253        OF 1.0 tunnel:
254        Bridge br-int
255             Port patch-net
256                 Interface patch-net
257                     type: patch
258                     options: {peer=patch-int}
259             Port br-int
260                 Interface br-int
261                     type: internal
262        Bridge "br-net"
263             Port patch-int
264                 Interface patch-int
265                     type: patch
266                     options: {peer=patch-net}
267             Port br-net
268                 Interface br-net
269                     type: internal
270
271        OF 1.3 vlan:
272        Bridge br-int
273             Port "eth1"
274                 Interface "eth1"
275             Port br-int
276                 Interface br-int
277                     type: internal
278
279        OF 1.3 tunnel:
280        Bridge br-int
281             Port br-int
282                 Interface br-int
283                     type: internal
284      */
285     public boolean createNetNetwork (Node node, NeutronNetwork network) throws Exception {
286         Status status;
287
288         logger.debug("createNetNetwork: node: {}, network type: {}", node, network.getProviderNetworkType());
289
290         if (providerNetworkManager == null) {
291             logger.error("Provider Network Manager is not available");
292             return false;
293         }
294         if (providerNetworkManager.getProvider().hasPerTenantTunneling()) { /* indicates OF 1.0 */
295             String brInt = adminConfigManager.getIntegrationBridgeName();
296             String brNet = adminConfigManager.getNetworkBridgeName();
297             String patchNet = adminConfigManager.getPatchToNetwork();
298             String patchInt = adminConfigManager.getPatchToIntegration();
299
300             status = this.addInternalBridge(node, brInt, patchNet, patchInt);
301             if (!status.isSuccess()) {
302                 logger.debug("{} Bridge Creation Status: {}", brInt, status);
303                 return false;
304             }
305             status = this.addInternalBridge(node, brNet, patchInt, patchNet);
306             if (!status.isSuccess()) {
307                 logger.debug("{} Bridge Creation Status: {}", brNet, status);
308                 return false;
309             }
310
311             /* For vlan network types add physical port to br-net. */
312             if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
313                 String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
314                 status = addPortToBridge(node, brNet, phyNetName);
315                 if (!status.isSuccess()) {
316                     logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brNet, status);
317                     return false;
318                 }
319             }
320         } else {
321             String brInt = adminConfigManager.getIntegrationBridgeName();
322             status = this.addInternalBridge(node, brInt, null, null);
323             if (!status.isSuccess()) {
324                 logger.debug("{} Bridge Creation Status: {}", brInt, status);
325                 return false;
326             }
327
328             /* For vlan network types add physical port to br-int. */
329             if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
330                 String phyNetName = adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
331                 status = addPortToBridge(node, brInt, phyNetName);
332                 if (!status.isSuccess()) {
333                     logger.debug("Add Port {} to Bridge {} Status: {}", phyNetName, brInt, status);
334                     return false;
335                 }
336             }
337         }
338
339         logger.debug("createNetNetwork: node: {}, status: success", node);
340         return true;
341     }
342
343     private Status addPortToBridge (Node node, String bridgeName, String portName) throws Exception {
344         logger.debug("addPortToBridge: Adding port: {} to Bridge {}, Node {}", portName, bridgeName, node);
345         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
346
347         String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
348         if (bridgeUUID == null) {
349             logger.error("addPortToBridge: Could not find Bridge {} in Node {}", bridgeName, node);
350             return new Status(StatusCode.NOTFOUND, "Could not find "+bridgeName+" in "+node);
351         }
352
353         /* Check if the port already exists. */
354         Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
355         if (bridge != null) {
356             if (isPortOnBridge(node, bridge, portName)) {
357                 logger.debug("addPortToBridge: Port {} already in Bridge {}, Node {}", portName, bridgeName, node);
358                 return new Status(StatusCode.SUCCESS);
359             }
360         } else {
361             logger.error("addPortToBridge: Could not find Port {} in Bridge {}, Node {}", portName, bridgeName, node);
362             return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in "+bridgeName);
363         }
364
365         Port port = new Port();
366         port.setName(portName);
367         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
368         if (!statusWithUuid.isSuccess()) {
369             logger.error("addPortToBridge: Failed to add Port {} in Bridge {}, Node {}", portName, bridgeName, node);
370             return statusWithUuid;
371         }
372
373         String portUUID = statusWithUuid.getUuid().toString();
374         String interfaceUUID = null;
375         int timeout = 6;
376         while ((interfaceUUID == null) && (timeout > 0)) {
377             port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
378             OvsDBSet<UUID> interfaces = port.getInterfaces();
379             if (interfaces == null || interfaces.size() == 0) {
380                 // Wait for the OVSDB update to sync up the Local cache.
381                 Thread.sleep(500);
382                 timeout--;
383                 continue;
384             }
385             interfaceUUID = interfaces.toArray()[0].toString();
386             Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
387             if (intf == null) {
388                 interfaceUUID = null;
389             }
390         }
391
392         if (interfaceUUID == null) {
393             logger.error("addPortToBridge: Cannot identify Interface for port {}/{}", portName, portUUID);
394             return new Status(StatusCode.INTERNALERROR);
395         }
396
397         return new Status(StatusCode.SUCCESS);
398     }
399
400     private Status addPatchPort (Node node, String bridgeUUID, String portName, String peerPortName) throws Exception {
401         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
402
403         logger.debug("addPatchPort: node: {}, bridgeUUID: {}, port: {}, peer: {}",
404                 node, bridgeUUID, portName, peerPortName);
405
406         /* Check if the port already exists. */
407         Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
408         if (bridge != null) {
409             if (isPortOnBridge(node, bridge, portName)) {
410                 logger.debug("addPatchPort: Port {} already in Bridge, Node {}", portName, node);
411                 return new Status(StatusCode.SUCCESS);
412             }
413         } else {
414             logger.error("addPatchPort: Could not find Port {} in Bridge, Node {}", portName, node);
415             return new Status(StatusCode.NOTFOUND, "Could not find "+portName+" in Bridge");
416         }
417
418         Port patchPort = new Port();
419         patchPort.setName(portName);
420         // Create patch port and interface
421         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
422         if (!statusWithUuid.isSuccess()) return statusWithUuid;
423
424         String patchPortUUID = statusWithUuid.getUuid().toString();
425
426         String interfaceUUID = null;
427         int timeout = 6;
428         while ((interfaceUUID == null) && (timeout > 0)) {
429             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
430             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
431             if (interfaces == null || interfaces.size() == 0) {
432                 // Wait for the OVSDB update to sync up the Local cache.
433                 Thread.sleep(500);
434                 timeout--;
435                 continue;
436             }
437             interfaceUUID = interfaces.toArray()[0].toString();
438         }
439
440         if (interfaceUUID == null) {
441             return new Status(StatusCode.INTERNALERROR);
442         }
443
444         Interface intf = new Interface();
445         intf.setType("patch");
446         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
447         options.put("peer", peerPortName);
448         intf.setOptions(options);
449         return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, intf);
450     }
451
452     private Status addInternalBridge (Node node, String bridgeName, String localPatchName, String remotePatchName) throws Exception {
453         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
454
455         String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
456         Bridge bridge = new Bridge();
457         OvsDBSet<String> failMode = new OvsDBSet<String>();
458         failMode.add("secure");
459         bridge.setFail_mode(failMode);
460
461         OvsDBSet<String> protocols = new OvsDBSet<String>();
462         if (providerNetworkManager == null) {
463             logger.error("Provider Network Manager is not available");
464             return new Status(StatusCode.INTERNALERROR);
465         }
466         if (!providerNetworkManager.getProvider().hasPerTenantTunneling()) {
467             protocols.add("OpenFlow13");
468         } else {
469             protocols.add("OpenFlow10");
470         }
471         bridge.setProtocols(protocols);
472
473         if (bridgeUUID == null) {
474             bridge.setName(bridgeName);
475
476             StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
477             if (!statusWithUuid.isSuccess()) return statusWithUuid;
478             bridgeUUID = statusWithUuid.getUuid().toString();
479             Port port = new Port();
480             port.setName(bridgeName);
481             Status status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
482             logger.debug("addInternalBridge: Inserting Bridge {} {} with protocols {} and status {}",
483                     bridgeName, bridgeUUID, protocols, status);
484         } else {
485             Status status = ovsdbTable.updateRow(node, Bridge.NAME.getName(), null, bridgeUUID, bridge);
486             logger.debug("addInternalBridge: Updating Bridge {} {} with protocols {} and status {}",
487                     bridgeName, bridgeUUID, protocols, status);
488         }
489
490         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
491         connectionService.setOFController(node, bridgeUUID);
492
493         if (localPatchName != null && remotePatchName != null && providerNetworkManager.getProvider().hasPerTenantTunneling()) {
494             return addPatchPort(node, bridgeUUID, localPatchName, remotePatchName);
495         }
496         return new Status(StatusCode.SUCCESS);
497     }
498
499     public void prepareInternalNetwork(Node node) {
500         try {
501             this.createIntegrationBridge(node);
502         } catch (Exception e) {
503             logger.error("Error creating internal network "+node.toString(), e);
504             return;
505         }
506         if (providerNetworkManager == null) {
507             logger.error("Error creating internal network. Provider Network Manager unavailable");
508             return;
509         }
510         providerNetworkManager.getProvider().initializeFlowRules(node);
511     }
512
513     /*
514      * Check if the full network setup is available. If not, create it.
515      */
516     public boolean checkAndCreateNetwork (Node node, NeutronNetwork network) {
517         boolean isCreated = false;
518         if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
519             if (!this.isInternalNetworkVlanReady(node, network)) {
520                 try {
521                     isCreated = this.createNetNetwork(node, network);
522                 } catch (Exception e) {
523                     logger.error("Error creating internal net network ", node, e);
524                 }
525             } else {
526                 isCreated = true;
527             }
528         } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
529                 network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
530             if (!this.isInternalNetworkTunnelReady(node)) {
531                 try {
532                     isCreated = this.createNetNetwork(node, network);
533                 } catch (Exception e) {
534                     logger.error("Error creating internal net network ", node, e);
535                 }
536             } else {
537                 isCreated = true;
538             }
539         }
540         return isCreated;
541     }
542 }