Merge "Added the missing Copyright headers to most of the java files."
[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.ArrayList;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
18 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
19 import org.opendaylight.controller.sal.action.ActionType;
20 import org.opendaylight.controller.sal.core.Node;
21 import org.opendaylight.controller.sal.utils.EtherTypes;
22 import org.opendaylight.controller.sal.utils.HexEncode;
23 import org.opendaylight.controller.sal.utils.ServiceHelper;
24 import org.opendaylight.controller.sal.utils.Status;
25 import org.opendaylight.controller.sal.utils.StatusCode;
26 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
27 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
28 import org.opendaylight.ovsdb.lib.notation.UUID;
29 import org.opendaylight.ovsdb.lib.table.Bridge;
30 import org.opendaylight.ovsdb.lib.table.Interface;
31 import org.opendaylight.ovsdb.lib.table.Port;
32 import org.opendaylight.ovsdb.lib.table.internal.Table;
33 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
34 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
35 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * OpenStack Neutron with the OpenVswitch data plan relies on a typical OVS bridge configurations that
41  * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
42  *
43  * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
44  * Hence this class attempts to bring all the nodes to be elibible for OpenStack operations.
45  *
46  */
47 public class InternalNetworkManager {
48     static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
49     private static final int LLDP_PRIORITY = 1000;
50     private static final int NORMAL_PRIORITY = 0;
51
52     private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
53     private InternalNetworkManager() {
54     }
55
56     public static InternalNetworkManager getManager() {
57         return internalNetwork;
58     }
59
60     public String getInternalBridgeUUID (Node node, String bridgeName) {
61         try {
62             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
63             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
64             if (bridgeTable == null) return null;
65             for (String key : bridgeTable.keySet()) {
66                 Bridge bridge = (Bridge)bridgeTable.get(key);
67                 if (bridge.getName().equals(bridgeName)) return key;
68             }
69         } catch (Exception e) {
70             logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
71         }
72         return null;
73     }
74
75     public boolean isInternalNetworkNeutronReady(Node node) {
76         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
77             return true;
78         } else {
79             return false;
80         }
81     }
82
83     public boolean isInternalNetworkOverlayReady(Node node) {
84         if (!this.isInternalNetworkNeutronReady(node)) {
85             return false;
86         }
87         if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
88             return true;
89         } else {
90             return false;
91         }
92     }
93
94     /*
95      * Lets create these if not already present :
96      *
97        Bridge br-int
98             Port patch-tun
99                 Interface patch-tun
100                     type: patch
101                     options: {peer=patch-int}
102             Port br-int
103                 Interface br-int
104                     type: internal
105       Bridge br-tun
106             Port patch-int
107                 Interface patch-int
108                     type: patch
109                     options: {peer=patch-tun}
110             Port br-tun
111                 Interface br-tun
112                     type: internal
113      */
114     public void createInternalNetworkForOverlay(Node node) throws Exception {
115         String brTun = AdminConfigManager.getManager().getTunnelBridgeName();
116         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
117         String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
118         String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
119
120         Status status = this.addInternalBridge(node, brInt, patchTun, patchInt);
121         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
122         status = this.addInternalBridge(node, brTun, patchInt, patchTun);
123         if (!status.isSuccess()) logger.debug("Tunnel Bridge Creation Status : "+status.toString());
124     }
125
126     /*
127      * Lets create these if not already present :
128      *
129        Bridge br-int
130             Port br-int
131                 Interface br-int
132                     type: internal
133      */
134     public void createInternalNetworkForNeutron(Node node) throws Exception {
135         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
136
137         Status status = this.addInternalBridge(node, brInt, null, null);
138         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
139     }
140
141     private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
142         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
143
144         String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
145         if (bridgeUUID == null) {
146             Bridge bridge = new Bridge();
147             bridge.setName(bridgeName);
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         }
156
157         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
158         connectionService.setOFController(node, bridgeUUID);
159
160         if (localPathName != null && remotePatchName != null) {
161             return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
162         }
163         return new Status(StatusCode.SUCCESS);
164     }
165
166     private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
167         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
168
169         Port patchPort = new Port();
170         patchPort.setName(portName);
171         // Create patch port and interface
172         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
173         if (!statusWithUuid.isSuccess()) return statusWithUuid;
174
175         String patchPortUUID = statusWithUuid.getUuid().toString();
176
177         String interfaceUUID = null;
178         int timeout = 6;
179         while ((interfaceUUID == null) && (timeout > 0)) {
180             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
181             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
182             if (interfaces == null || interfaces.size() == 0) {
183                 // Wait for the OVSDB update to sync up the Local cache.
184                 Thread.sleep(500);
185                 timeout--;
186                 continue;
187             }
188             interfaceUUID = interfaces.toArray()[0].toString();
189         }
190
191         if (interfaceUUID == null) {
192             return new Status(StatusCode.INTERNALERROR);
193         }
194
195         Interface tunInterface = new Interface();
196         tunInterface.setType("patch");
197         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
198         options.put("peer", patchName);
199         tunInterface.setOptions(options);
200         return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
201     }
202
203     private void initializeOFNormalFlowRules(Node node, String bridgeName) {
204         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
205         if (brIntId == null) {
206             logger.error("Failed to initialize Flow Rules for {}", node);
207             return;
208         }
209         try {
210             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
211             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
212             Set<String> dpids = bridge.getDatapath_id();
213             if (dpids == null || dpids.size() ==  0) return;
214             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
215             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
216             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
217                     IForwardingRulesManager.class, "default", this);
218             String flowName = ActionType.HW_PATH.toString();
219             FlowConfig flow = new FlowConfig();
220             flow.setName("NORMAL");
221             flow.setNode(ofNode);
222             flow.setPriority(NORMAL_PRIORITY+"");
223             flow.setInstallInHw(true);
224             List<String> normalAction = new ArrayList<String>();
225             normalAction.add(flowName);
226             flow.setActions(normalAction);
227             Status status = null;
228             if (frm.getStaticFlow(flowName, ofNode) == null) {
229                 status = frm.addStaticFlow(flow);
230                 logger.debug("Flow Programming Add Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
231             } else {
232                 status = frm.modifyStaticFlow(flow);
233                 logger.debug("Flow Programming Modify Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
234             }
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             List<String> puntAction = new ArrayList<String>();
257             puntAction.add(ActionType.CONTROLLER.toString());
258
259             FlowConfig allowLLDP = new FlowConfig();
260             allowLLDP.setInstallInHw(true);
261             allowLLDP.setName(flowName);
262             allowLLDP.setPriority(LLDP_PRIORITY+"");
263             allowLLDP.setNode(ofNode);
264             allowLLDP.setInstallInHw(true);
265             allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
266                     .toUpperCase());
267             allowLLDP.setActions(puntAction);
268             Status status = null;
269             if (frm.getStaticFlow(flowName, ofNode) == null) {
270                 status = frm.addStaticFlow(allowLLDP);
271                 logger.debug("LLDP Flow Add Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
272             } else {
273                 status = frm.modifyStaticFlow(allowLLDP);
274                 logger.debug("LLDP Flow Modify Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
275             }
276         } catch (Exception e) {
277             logger.error("Failed to initialize Flow Rules for {}", node, e);
278         }
279     }
280
281     public void prepareInternalNetwork(Node node) {
282         try {
283             this.createInternalNetworkForOverlay(node);
284         } catch (Exception e) {
285             logger.error("Error creating internal network "+node.toString(), e);
286         }
287         //Install NORMAL flows on all the bridges to make sure that we dont end up punting traffic to the OF Controller
288         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
289         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName());
290         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
291         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
292         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
293     }
294 }