2 * Copyright (C) 2013 Red Hat, Inc.
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
8 * Authors : Madhu Venugopal, Brent Salisbury
10 package org.opendaylight.ovsdb.neutron;
12 import java.util.ArrayList;
13 import java.util.List;
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;
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).
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.
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;
52 private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
53 private InternalNetworkManager() {
56 public static InternalNetworkManager getManager() {
57 return internalNetwork;
60 public String getInternalBridgeUUID (Node node, String bridgeName) {
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;
69 } catch (Exception e) {
70 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
75 public boolean isInternalNetworkNeutronReady(Node node) {
76 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
83 public boolean isInternalNetworkOverlayReady(Node node) {
84 if (!this.isInternalNetworkNeutronReady(node)) {
87 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
95 * Lets create these if not already present :
101 options: {peer=patch-int}
109 options: {peer=patch-tun}
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();
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());
127 * Lets create these if not already present :
134 public void createInternalNetworkForNeutron(Node node) throws Exception {
135 String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
137 Status status = this.addInternalBridge(node, brInt, null, null);
138 if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
141 private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
142 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
144 String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
145 if (bridgeUUID == null) {
146 Bridge bridge = new Bridge();
147 bridge.setName(bridgeName);
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);
157 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
158 connectionService.setOFController(node, bridgeUUID);
160 if (localPathName != null && remotePatchName != null) {
161 return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
163 return new Status(StatusCode.SUCCESS);
166 private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
167 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
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;
175 String patchPortUUID = statusWithUuid.getUuid().toString();
177 String interfaceUUID = null;
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.
188 interfaceUUID = interfaces.toArray()[0].toString();
191 if (interfaceUUID == null) {
192 return new Status(StatusCode.INTERNALERROR);
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);
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);
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);
232 status = frm.modifyStaticFlow(flow);
233 logger.debug("Flow Programming Modify Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
235 } catch (Exception e) {
236 logger.error("Failed to initialize Flow Rules for {}", node, e);
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);
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());
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())
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);
273 status = frm.modifyStaticFlow(allowLLDP);
274 logger.debug("LLDP Flow Modify Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
276 } catch (Exception e) {
277 logger.error("Failed to initialize Flow Rules for {}", node, e);
281 public void prepareInternalNetwork(Node node) {
283 this.createInternalNetworkForOverlay(node);
284 } catch (Exception e) {
285 logger.error("Error creating internal network "+node.toString(), e);
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());