OVSDB Neutron & OpenFlow 1.3 integration
[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
9  */
10 package org.opendaylight.ovsdb.neutron;
11
12 import java.util.Map;
13
14 import org.opendaylight.controller.sal.core.Node;
15 import org.opendaylight.controller.sal.utils.ServiceHelper;
16 import org.opendaylight.controller.sal.utils.Status;
17 import org.opendaylight.controller.sal.utils.StatusCode;
18 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
19 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
20 import org.opendaylight.ovsdb.lib.notation.UUID;
21 import org.opendaylight.ovsdb.lib.table.Bridge;
22 import org.opendaylight.ovsdb.lib.table.Interface;
23 import org.opendaylight.ovsdb.lib.table.Port;
24 import org.opendaylight.ovsdb.lib.table.internal.Table;
25 import org.opendaylight.ovsdb.neutron.provider.ProviderNetworkManager;
26 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
27 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
28 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * OpenStack Neutron with the OpenVswitch data plan relies on a typical OVS bridge configurations that
34  * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
35  *
36  * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
37  * Hence this class attempts to bring all the nodes to be elibible for OpenStack operations.
38  *
39  */
40 public class InternalNetworkManager {
41     static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
42     private static final int LLDP_PRIORITY = 1000;
43     private static final int NORMAL_PRIORITY = 0;
44
45     private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
46     private InternalNetworkManager() {
47     }
48
49     public static InternalNetworkManager getManager() {
50         return internalNetwork;
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 boolean isInternalNetworkNeutronReady(Node node) {
69         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
70             return true;
71         } else {
72             return false;
73         }
74     }
75
76     public boolean isInternalNetworkOverlayReady(Node node) {
77         if (!this.isInternalNetworkNeutronReady(node)) {
78             return false;
79         }
80         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
81             return true;
82         } else {
83             return false;
84         }
85     }
86
87     /*
88      * Lets create these if not already present :
89      *
90        Bridge br-int
91             Port patch-tun
92                 Interface patch-tun
93                     type: patch
94                     options: {peer=patch-int}
95             Port br-int
96                 Interface br-int
97                     type: internal
98       Bridge br-tun
99             Port patch-int
100                 Interface patch-int
101                     type: patch
102                     options: {peer=patch-tun}
103             Port br-tun
104                 Interface br-tun
105                     type: internal
106      */
107     public void createInternalNetworkForOverlay(Node node) throws Exception {
108         String brTun = AdminConfigManager.getManager().getTunnelBridgeName();
109         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
110         String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
111         String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
112
113         Status status = this.addInternalBridge(node, brInt, patchTun, patchInt);
114         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
115         if (ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
116             status = this.addInternalBridge(node, brTun, patchInt, patchTun);
117             if (!status.isSuccess()) logger.debug("Tunnel Bridge Creation Status : "+status.toString());
118         }
119     }
120
121     /*
122      * Lets create these if not already present :
123      *
124        Bridge br-int
125             Port br-int
126                 Interface br-int
127                     type: internal
128      */
129     public void createInternalNetworkForNeutron(Node node) throws Exception {
130         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
131
132         Status status = this.addInternalBridge(node, brInt, null, null);
133         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
134     }
135
136     private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
137         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
138
139         String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
140         Bridge bridge = new Bridge();
141         if (bridgeUUID == null) {
142             bridge.setName(bridgeName);
143             if (!ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
144                 OvsDBSet<String> protocols = new OvsDBSet<String>();
145                 protocols.add("OpenFlow13");
146                 bridge.setProtocols(protocols);
147             }
148
149             StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
150             if (!statusWithUuid.isSuccess()) return statusWithUuid;
151             bridgeUUID = statusWithUuid.getUuid().toString();
152             Port port = new Port();
153             port.setName(bridgeName);
154             ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
155         } else if (!ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
156             OvsDBSet<String> protocols = new OvsDBSet<String>();
157             protocols.add("OpenFlow13");
158             bridge.setProtocols(protocols);
159             ovsdbTable.updateRow(node, Bridge.NAME.getName(), null, bridgeUUID, bridge);
160         }
161
162         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
163         connectionService.setOFController(node, bridgeUUID);
164
165         if (localPathName != null && remotePatchName != null && ProviderNetworkManager.getManager().hasPerTenantTunneling()) {
166             return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
167         }
168         return new Status(StatusCode.SUCCESS);
169     }
170
171     private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
172         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
173
174         Port patchPort = new Port();
175         patchPort.setName(portName);
176         // Create patch port and interface
177         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
178         if (!statusWithUuid.isSuccess()) return statusWithUuid;
179
180         String patchPortUUID = statusWithUuid.getUuid().toString();
181
182         String interfaceUUID = null;
183         int timeout = 6;
184         while ((interfaceUUID == null) && (timeout > 0)) {
185             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
186             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
187             if (interfaces == null || interfaces.size() == 0) {
188                 // Wait for the OVSDB update to sync up the Local cache.
189                 Thread.sleep(500);
190                 timeout--;
191                 continue;
192             }
193             interfaceUUID = interfaces.toArray()[0].toString();
194         }
195
196         if (interfaceUUID == null) {
197             return new Status(StatusCode.INTERNALERROR);
198         }
199
200         Interface tunInterface = new Interface();
201         tunInterface.setType("patch");
202         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
203         options.put("peer", patchName);
204         tunInterface.setOptions(options);
205         return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
206     }
207
208     public void prepareInternalNetwork(Node node) {
209         try {
210             this.createInternalNetworkForOverlay(node);
211         } catch (Exception e) {
212             logger.error("Error creating internal network "+node.toString(), e);
213         }
214         ProviderNetworkManager.getManager().initializeFlowRules(node);
215     }
216 }