Merge "Fixed JSON Deserializer to retain empty objects as empty rather than NULL...
[netvirt.git] / neutron / src / main / java / org / opendaylight / ovsdb / neutron / InternalNetworkManager.java
1 package org.opendaylight.ovsdb.neutron;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Set;
8
9 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
10 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
11 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
12 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
13 import org.opendaylight.controller.sal.action.ActionType;
14 import org.opendaylight.controller.sal.core.Node;
15 import org.opendaylight.controller.sal.utils.EtherTypes;
16 import org.opendaylight.controller.sal.utils.HexEncode;
17 import org.opendaylight.controller.sal.utils.ServiceHelper;
18 import org.opendaylight.controller.sal.utils.Status;
19 import org.opendaylight.controller.sal.utils.StatusCode;
20 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
21 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
22 import org.opendaylight.ovsdb.lib.notation.UUID;
23 import org.opendaylight.ovsdb.lib.table.Bridge;
24 import org.opendaylight.ovsdb.lib.table.Interface;
25 import org.opendaylight.ovsdb.lib.table.Port;
26 import org.opendaylight.ovsdb.lib.table.internal.Table;
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 elibible for OpenStack operations.
39  *
40  */
41 public class InternalNetworkManager {
42     static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
43
44     private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
45     private InternalNetworkManager() {
46     }
47
48     public static InternalNetworkManager getManager() {
49         return internalNetwork;
50     }
51
52     public String getInternalBridgeUUID (Node node, String bridgeName) {
53         try {
54             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
55             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
56             if (bridgeTable == null) return null;
57             for (String key : bridgeTable.keySet()) {
58                 Bridge bridge = (Bridge)bridgeTable.get(key);
59                 if (bridge.getName().equals(bridgeName)) return key;
60             }
61         } catch (Exception e) {
62             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
63         }
64         return null;
65     }
66
67     public boolean isInternalNetworkNeutronReady(Node node) throws Exception {
68         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
69             return true;
70         } else {
71             return false;
72         }
73     }
74
75     public boolean isInternalNetworkOverlayReady(Node node) throws Exception {
76         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
77             return true;
78         } else {
79             return false;
80         }
81     }
82
83     public Status createInternalNetworkForOverlay(Node node) throws Exception {
84         if (!isInternalNetworkNeutronReady(node)) {
85             logger.error("Integration Bridge is not available in Node {}", node);
86             return new Status(StatusCode.NOTACCEPTABLE, "Integration Bridge is not avaialble in Node " + node);
87         }
88         if (isInternalNetworkOverlayReady(node)) {
89             logger.error("Network Overlay Bridge is already present in Node {}", node);
90             return new Status(StatusCode.NOTACCEPTABLE, "Network Overlay Bridge is already present in Node " + node);
91         }
92
93         /*
94          * Lets create this :
95          *
96          * Bridge br-tun
97                 Port patch-int
98                     Interface patch-int
99                         type: patch
100                         options: {peer=patch-tun}
101                 Port br-tun
102                     Interface br-tun
103                         type: internal
104          */
105
106         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
107         Bridge brTun = new Bridge();
108         brTun.setName(AdminConfigManager.getManager().getTunnelBridgeName());
109         // Create br-tun bridge
110         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, brTun);
111         if (!statusWithUuid.isSuccess()) return statusWithUuid;
112         String bridgeUUID = statusWithUuid.getUuid().toString();
113
114         // Set OF Controller
115         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
116         connectionService.setOFController(node, bridgeUUID);
117
118         Port port = new Port();
119         port.setName(brTun.getName());
120         statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
121
122         String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
123         String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
124
125         Status status = addPatchPort(node, bridgeUUID, patchInt, patchTun);
126         if (!status.isSuccess()) return status;
127
128         // Create the corresponding patch-tun port in br-int
129         Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
130         for (String brIntUUID : bridges.keySet()) {
131             Bridge brInt = (Bridge) bridges.get(brIntUUID);
132             if (brInt.getName().equalsIgnoreCase(AdminConfigManager.getManager().getIntegrationBridgeName())) {
133                 return addPatchPort(node, brIntUUID, patchTun, patchInt);
134             }
135         }
136
137         return status;
138     }
139
140     private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
141         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
142
143         Port patchPort = new Port();
144         patchPort.setName(portName);
145         // Create patch-int port and interface
146         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
147         if (!statusWithUuid.isSuccess()) return statusWithUuid;
148
149         String patchPortUUID = statusWithUuid.getUuid().toString();
150
151         String interfaceUUID = null;
152         int timeout = 6;
153         while ((interfaceUUID == null) && (timeout > 0)) {
154             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
155             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
156             if (interfaces == null || interfaces.size() == 0) {
157                 // Wait for the OVSDB update to sync up the Local cache.
158                 Thread.sleep(500);
159                 timeout--;
160                 continue;
161             }
162             interfaceUUID = interfaces.toArray()[0].toString();
163         }
164
165         if (interfaceUUID == null) {
166             return new Status(StatusCode.INTERNALERROR);
167         }
168
169         Interface tunInterface = new Interface();
170         tunInterface.setType("patch");
171         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
172         options.put("peer", patchName);
173         tunInterface.setOptions(options);
174         return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
175     }
176
177     private void prepareInternalNetwork (NeutronNetwork network, Node node) {
178         // vlan, vxlan, and gre
179         if (network.getProviderNetworkType().equalsIgnoreCase("gre") ||
180                 network.getProviderNetworkType().equalsIgnoreCase("vxlan") ||
181                 network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
182
183             try {
184                 if (!this.isInternalNetworkOverlayReady(node)) {
185                     this.createInternalNetworkForOverlay(node);
186                 }
187             } catch (Exception e) {
188                 logger.error("Failed to create internal network for overlay on node " + node, e);
189             }
190         } else {
191             try {
192                 if (!this.isInternalNetworkNeutronReady(node)) {
193                     // TODO : FILL IN
194                     // this.createInternalNetworkForNeutron(node);
195                 }
196             } catch (Exception e) {
197                 logger.error("Failed to create internal network for overlay on node " + node, e);
198             }
199         }
200
201         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
202         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
203         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
204     }
205
206     private void initializeOFNormalFlowRules(Node node, String bridgeName) {
207         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
208         if (brIntId == null) {
209             logger.error("Failed to initialize Flow Rules for {}", node);
210             return;
211         }
212         try {
213             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
214             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
215             Set<String> dpids = bridge.getDatapath_id();
216             if (dpids == null || dpids.size() ==  0) return;
217             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
218             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
219             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
220                     IForwardingRulesManager.class, "default", this);
221             String flowName = ActionType.HW_PATH.toString();
222             if (frm.getStaticFlow(flowName, ofNode) != null) {
223                 logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
224                 return;
225             }
226             FlowConfig flow = new FlowConfig();
227             flow.setName("IntegrationBridgeNormal");
228             flow.setNode(ofNode);
229             flow.setPriority("1");
230             List<String> normalAction = new ArrayList<String>();
231             normalAction.add(flowName);
232             flow.setActions(normalAction);
233             Status status = frm.addStaticFlow(flow);
234             logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
235         } catch (Exception e) {
236             logger.error("Failed to initialize Flow Rules for {}", node, e);
237         }
238     }
239
240     private void initializeLLDPFlowRules(Node node, String bridgeName) {
241         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
242         if (brIntId == null) {
243             logger.error("Failed to initialize Flow Rules for {}", node);
244             return;
245         }
246         try {
247             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
248             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
249             Set<String> dpids = bridge.getDatapath_id();
250             if (dpids == null || dpids.size() ==  0) return;
251             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
252             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
253             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
254                     IForwardingRulesManager.class, "default", this);
255             String flowName = "PuntLLDP";
256             if (frm.getStaticFlow(flowName, ofNode) != null) {
257                 logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
258                 return;
259             }
260
261             List<String> puntAction = new ArrayList<String>();
262             puntAction.add(ActionType.CONTROLLER.toString());
263
264             FlowConfig allowLLDP = new FlowConfig();
265             allowLLDP.setInstallInHw(true);
266             allowLLDP.setName(flowName);
267             allowLLDP.setPriority("10");
268             allowLLDP.setNode(ofNode);
269             allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
270                     .toUpperCase());
271             allowLLDP.setActions(puntAction);
272             Status status = frm.addStaticFlow(allowLLDP);
273             logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
274         } catch (Exception e) {
275             logger.error("Failed to initialize Flow Rules for {}", node, e);
276         }
277     }
278
279     public void prepareInternalNetwork(NeutronNetwork network) {
280         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
281         List<Node> nodes = connectionService.getNodes();
282         for (Node node : nodes) {
283             prepareInternalNetwork(network, node);
284         }
285     }
286
287     public void prepareInternalNetwork(Node node) {
288         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
289         List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
290         for (NeutronNetwork network : networks) {
291             prepareInternalNetwork(network, node);
292         }
293     }
294
295     public static List safe( List other ) {
296         return other == null ? Collections.EMPTY_LIST : other;
297     }
298 }