Merge "- Addressed Queue/QoS special parent column type dependency - New files found...
[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.List;
5 import java.util.Map;
6 import java.util.Set;
7
8 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
9 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
10 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
11 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
12 import org.opendaylight.controller.sal.action.ActionType;
13 import org.opendaylight.controller.sal.core.Node;
14 import org.opendaylight.controller.sal.utils.EtherTypes;
15 import org.opendaylight.controller.sal.utils.HexEncode;
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.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 = 500;
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         status = this.addInternalBridge(node, brTun, patchInt, patchTun);
116         if (!status.isSuccess()) logger.debug("Tunnel Bridge Creation Status : "+status.toString());
117     }
118
119     /*
120      * Lets create these if not already present :
121      *
122        Bridge br-int
123             Port br-int
124                 Interface br-int
125                     type: internal
126      */
127     public void createInternalNetworkForNeutron(Node node) throws Exception {
128         String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
129
130         Status status = this.addInternalBridge(node, brInt, null, null);
131         if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
132     }
133
134     private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
135         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
136
137         String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
138         if (bridgeUUID == null) {
139             Bridge bridge = new Bridge();
140             bridge.setName(bridgeName);
141
142             StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
143             if (!statusWithUuid.isSuccess()) return statusWithUuid;
144             bridgeUUID = statusWithUuid.getUuid().toString();
145             Port port = new Port();
146             port.setName(bridgeName);
147             ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
148         }
149
150         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
151         connectionService.setOFController(node, bridgeUUID);
152
153         if (localPathName != null && remotePatchName != null) {
154             return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
155         }
156         return new Status(StatusCode.SUCCESS);
157     }
158
159     private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
160         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
161
162         Port patchPort = new Port();
163         patchPort.setName(portName);
164         // Create patch port and interface
165         StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
166         if (!statusWithUuid.isSuccess()) return statusWithUuid;
167
168         String patchPortUUID = statusWithUuid.getUuid().toString();
169
170         String interfaceUUID = null;
171         int timeout = 6;
172         while ((interfaceUUID == null) && (timeout > 0)) {
173             patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
174             OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
175             if (interfaces == null || interfaces.size() == 0) {
176                 // Wait for the OVSDB update to sync up the Local cache.
177                 Thread.sleep(500);
178                 timeout--;
179                 continue;
180             }
181             interfaceUUID = interfaces.toArray()[0].toString();
182         }
183
184         if (interfaceUUID == null) {
185             return new Status(StatusCode.INTERNALERROR);
186         }
187
188         Interface tunInterface = new Interface();
189         tunInterface.setType("patch");
190         OvsDBMap<String, String> options = new OvsDBMap<String, String>();
191         options.put("peer", patchName);
192         tunInterface.setOptions(options);
193         return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
194     }
195
196     private void prepareInternalNetwork (NeutronNetwork network, Node node) {
197         // vlan, vxlan, and gre
198         if (network.getProviderNetworkType().equalsIgnoreCase("gre") ||
199                 network.getProviderNetworkType().equalsIgnoreCase("vxlan") ||
200                 network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
201
202             try {
203                 this.createInternalNetworkForOverlay(node);
204             } catch (Exception e) {
205                 logger.error("Failed to create internal network for overlay on node " + node, e);
206             }
207         } else {
208             try {
209                 this.createInternalNetworkForNeutron(node);
210             } catch (Exception e) {
211                 logger.error("Failed to create internal network for overlay on node " + node, e);
212             }
213         }
214
215         this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
216         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
217         this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
218     }
219
220     private void initializeOFNormalFlowRules(Node node, String bridgeName) {
221         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
222         if (brIntId == null) {
223             logger.error("Failed to initialize Flow Rules for {}", node);
224             return;
225         }
226         try {
227             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
228             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
229             Set<String> dpids = bridge.getDatapath_id();
230             if (dpids == null || dpids.size() ==  0) return;
231             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
232             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
233             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
234                     IForwardingRulesManager.class, "default", this);
235             String flowName = ActionType.HW_PATH.toString();
236             if (frm.getStaticFlow(flowName, ofNode) != null) {
237                 logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
238                 return;
239             }
240             FlowConfig flow = new FlowConfig();
241             flow.setName("IntegrationBridgeNormal");
242             flow.setNode(ofNode);
243             flow.setPriority(NORMAL_PRIORITY+"");
244             List<String> normalAction = new ArrayList<String>();
245             normalAction.add(flowName);
246             flow.setActions(normalAction);
247             Status status = frm.addStaticFlow(flow);
248             logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
249         } catch (Exception e) {
250             logger.error("Failed to initialize Flow Rules for {}", node, e);
251         }
252     }
253
254     private void initializeLLDPFlowRules(Node node, String bridgeName) {
255         String brIntId = this.getInternalBridgeUUID(node, bridgeName);
256         if (brIntId == null) {
257             logger.error("Failed to initialize Flow Rules for {}", node);
258             return;
259         }
260         try {
261             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
262             Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
263             Set<String> dpids = bridge.getDatapath_id();
264             if (dpids == null || dpids.size() ==  0) return;
265             Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
266             Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
267             IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
268                     IForwardingRulesManager.class, "default", this);
269             String flowName = "PuntLLDP";
270             if (frm.getStaticFlow(flowName, ofNode) != null) {
271                 logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
272                 return;
273             }
274
275             List<String> puntAction = new ArrayList<String>();
276             puntAction.add(ActionType.CONTROLLER.toString());
277
278             FlowConfig allowLLDP = new FlowConfig();
279             allowLLDP.setInstallInHw(true);
280             allowLLDP.setName(flowName);
281             allowLLDP.setPriority(LLDP_PRIORITY+"");
282             allowLLDP.setNode(ofNode);
283             allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
284                     .toUpperCase());
285             allowLLDP.setActions(puntAction);
286             Status status = frm.addStaticFlow(allowLLDP);
287             logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
288         } catch (Exception e) {
289             logger.error("Failed to initialize Flow Rules for {}", node, e);
290         }
291     }
292
293     public void prepareInternalNetwork(NeutronNetwork network) {
294         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
295         List<Node> nodes = connectionService.getNodes();
296         for (Node node : nodes) {
297             prepareInternalNetwork(network, node);
298         }
299     }
300
301     public void prepareInternalNetwork(Node node) {
302         INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
303         List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
304         for (NeutronNetwork network : networks) {
305             prepareInternalNetwork(network, node);
306         }
307     }
308 }