1 package org.opendaylight.ovsdb.neutron;
3 import java.util.ArrayList;
8 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
9 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
10 import org.opendaylight.controller.sal.action.ActionType;
11 import org.opendaylight.controller.sal.core.Node;
12 import org.opendaylight.controller.sal.utils.EtherTypes;
13 import org.opendaylight.controller.sal.utils.HexEncode;
14 import org.opendaylight.controller.sal.utils.ServiceHelper;
15 import org.opendaylight.controller.sal.utils.Status;
16 import org.opendaylight.controller.sal.utils.StatusCode;
17 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
18 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
19 import org.opendaylight.ovsdb.lib.notation.UUID;
20 import org.opendaylight.ovsdb.lib.table.Bridge;
21 import org.opendaylight.ovsdb.lib.table.Interface;
22 import org.opendaylight.ovsdb.lib.table.Port;
23 import org.opendaylight.ovsdb.lib.table.internal.Table;
24 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
25 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
26 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * OpenStack Neutron with the OpenVswitch data plan relies on a typical OVS bridge configurations that
32 * consists of br-int (Integration Bridge), br-tun (Tunnel bridge), br-ex (External bridge).
34 * In DevStack like setups, the br-tun is not automatically created on the controller nodes.
35 * Hence this class attempts to bring all the nodes to be elibible for OpenStack operations.
38 public class InternalNetworkManager {
39 static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
40 private static final int LLDP_PRIORITY = 1000;
41 private static final int NORMAL_PRIORITY = 0;
43 private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
44 private InternalNetworkManager() {
47 public static InternalNetworkManager getManager() {
48 return internalNetwork;
51 public String getInternalBridgeUUID (Node node, String bridgeName) {
53 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
54 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
55 if (bridgeTable == null) return null;
56 for (String key : bridgeTable.keySet()) {
57 Bridge bridge = (Bridge)bridgeTable.get(key);
58 if (bridge.getName().equals(bridgeName)) return key;
60 } catch (Exception e) {
61 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
66 public boolean isInternalNetworkNeutronReady(Node node) {
67 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
74 public boolean isInternalNetworkOverlayReady(Node node) {
75 if (!this.isInternalNetworkNeutronReady(node)) {
78 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
86 * Lets create these if not already present :
92 options: {peer=patch-int}
100 options: {peer=patch-tun}
105 public void createInternalNetworkForOverlay(Node node) throws Exception {
106 String brTun = AdminConfigManager.getManager().getTunnelBridgeName();
107 String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
108 String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
109 String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
111 Status status = this.addInternalBridge(node, brInt, patchTun, patchInt);
112 if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
113 status = this.addInternalBridge(node, brTun, patchInt, patchTun);
114 if (!status.isSuccess()) logger.debug("Tunnel Bridge Creation Status : "+status.toString());
118 * Lets create these if not already present :
125 public void createInternalNetworkForNeutron(Node node) throws Exception {
126 String brInt = AdminConfigManager.getManager().getIntegrationBridgeName();
128 Status status = this.addInternalBridge(node, brInt, null, null);
129 if (!status.isSuccess()) logger.debug("Integration Bridge Creation Status : "+status.toString());
132 private Status addInternalBridge (Node node, String bridgeName, String localPathName, String remotePatchName) throws Exception {
133 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
135 String bridgeUUID = this.getInternalBridgeUUID(node, bridgeName);
136 if (bridgeUUID == null) {
137 Bridge bridge = new Bridge();
138 bridge.setName(bridgeName);
140 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, bridge);
141 if (!statusWithUuid.isSuccess()) return statusWithUuid;
142 bridgeUUID = statusWithUuid.getUuid().toString();
143 Port port = new Port();
144 port.setName(bridgeName);
145 ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
148 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
149 connectionService.setOFController(node, bridgeUUID);
151 if (localPathName != null && remotePatchName != null) {
152 return addPatchPort(node, bridgeUUID, localPathName, remotePatchName);
154 return new Status(StatusCode.SUCCESS);
157 private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
158 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
160 Port patchPort = new Port();
161 patchPort.setName(portName);
162 // Create patch port and interface
163 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
164 if (!statusWithUuid.isSuccess()) return statusWithUuid;
166 String patchPortUUID = statusWithUuid.getUuid().toString();
168 String interfaceUUID = null;
170 while ((interfaceUUID == null) && (timeout > 0)) {
171 patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
172 OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
173 if (interfaces == null || interfaces.size() == 0) {
174 // Wait for the OVSDB update to sync up the Local cache.
179 interfaceUUID = interfaces.toArray()[0].toString();
182 if (interfaceUUID == null) {
183 return new Status(StatusCode.INTERNALERROR);
186 Interface tunInterface = new Interface();
187 tunInterface.setType("patch");
188 OvsDBMap<String, String> options = new OvsDBMap<String, String>();
189 options.put("peer", patchName);
190 tunInterface.setOptions(options);
191 return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
194 private void initializeOFNormalFlowRules(Node node, String bridgeName) {
195 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
196 if (brIntId == null) {
197 logger.error("Failed to initialize Flow Rules for {}", node);
201 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
202 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
203 Set<String> dpids = bridge.getDatapath_id();
204 if (dpids == null || dpids.size() == 0) return;
205 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
206 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
207 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
208 IForwardingRulesManager.class, "default", this);
209 String flowName = ActionType.HW_PATH.toString();
210 FlowConfig flow = new FlowConfig();
211 flow.setName("NORMAL");
212 flow.setNode(ofNode);
213 flow.setPriority(NORMAL_PRIORITY+"");
214 flow.setInstallInHw(true);
215 List<String> normalAction = new ArrayList<String>();
216 normalAction.add(flowName);
217 flow.setActions(normalAction);
218 Status status = null;
219 if (frm.getStaticFlow(flowName, ofNode) == null) {
220 status = frm.addStaticFlow(flow);
221 logger.debug("Flow Programming Add Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
223 status = frm.modifyStaticFlow(flow);
224 logger.debug("Flow Programming Modify Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
226 } catch (Exception e) {
227 logger.error("Failed to initialize Flow Rules for {}", node, e);
231 private void initializeLLDPFlowRules(Node node, String bridgeName) {
232 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
233 if (brIntId == null) {
234 logger.error("Failed to initialize Flow Rules for {}", node);
238 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
239 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
240 Set<String> dpids = bridge.getDatapath_id();
241 if (dpids == null || dpids.size() == 0) return;
242 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
243 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
244 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
245 IForwardingRulesManager.class, "default", this);
246 String flowName = "PuntLLDP";
247 List<String> puntAction = new ArrayList<String>();
248 puntAction.add(ActionType.CONTROLLER.toString());
250 FlowConfig allowLLDP = new FlowConfig();
251 allowLLDP.setInstallInHw(true);
252 allowLLDP.setName(flowName);
253 allowLLDP.setPriority(LLDP_PRIORITY+"");
254 allowLLDP.setNode(ofNode);
255 allowLLDP.setInstallInHw(true);
256 allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
258 allowLLDP.setActions(puntAction);
259 Status status = null;
260 if (frm.getStaticFlow(flowName, ofNode) == null) {
261 status = frm.addStaticFlow(allowLLDP);
262 logger.debug("LLDP Flow Add Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
264 status = frm.modifyStaticFlow(allowLLDP);
265 logger.debug("LLDP Flow Modify Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
267 } catch (Exception e) {
268 logger.error("Failed to initialize Flow Rules for {}", node, e);
272 public void prepareInternalNetwork(Node node) {
274 this.createInternalNetworkForOverlay(node);
275 } catch (Exception e) {
276 logger.error("Error creating internal network "+node.toString(), e);
278 //Install NORMAL flows on all the bridges to make sure that we dont end up punting traffic to the OF Controller
279 this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
280 this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName());
281 this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
282 this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
283 this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());