1 package org.opendaylight.ovsdb.neutron;
3 import java.util.ArrayList;
4 import java.util.Collections;
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;
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).
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.
41 public class InternalNetworkManager {
42 static final Logger logger = LoggerFactory.getLogger(InternalNetworkManager.class);
43 private static final int LLDP_PRIORITY = 1000;
44 private static final int NORMAL_PRIORITY = 500;
46 private static InternalNetworkManager internalNetwork = new InternalNetworkManager();
47 private InternalNetworkManager() {
50 public static InternalNetworkManager getManager() {
51 return internalNetwork;
54 public String getInternalBridgeUUID (Node node, String bridgeName) {
56 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
57 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
58 if (bridgeTable == null) return null;
59 for (String key : bridgeTable.keySet()) {
60 Bridge bridge = (Bridge)bridgeTable.get(key);
61 if (bridge.getName().equals(bridgeName)) return key;
63 } catch (Exception e) {
64 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
69 public boolean isInternalNetworkNeutronReady(Node node) throws Exception {
70 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
77 public boolean isInternalNetworkOverlayReady(Node node) throws Exception {
78 if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
85 public Status createInternalNetworkForOverlay(Node node) throws Exception {
86 if (!isInternalNetworkNeutronReady(node)) {
87 logger.error("Integration Bridge is not available in Node {}", node);
88 return new Status(StatusCode.NOTACCEPTABLE, "Integration Bridge is not avaialble in Node " + node);
90 if (isInternalNetworkOverlayReady(node)) {
91 logger.error("Network Overlay Bridge is already present in Node {}", node);
92 return new Status(StatusCode.NOTACCEPTABLE, "Network Overlay Bridge is already present in Node " + node);
102 options: {peer=patch-tun}
108 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
109 Bridge brTun = new Bridge();
110 brTun.setName(AdminConfigManager.getManager().getTunnelBridgeName());
111 // Create br-tun bridge
112 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, brTun);
113 if (!statusWithUuid.isSuccess()) return statusWithUuid;
114 String bridgeUUID = statusWithUuid.getUuid().toString();
117 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
118 connectionService.setOFController(node, bridgeUUID);
120 Port port = new Port();
121 port.setName(brTun.getName());
122 statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
124 String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
125 String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
127 Status status = addPatchPort(node, bridgeUUID, patchInt, patchTun);
128 if (!status.isSuccess()) return status;
130 // Create the corresponding patch-tun port in br-int
131 Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
132 for (String brIntUUID : bridges.keySet()) {
133 Bridge brInt = (Bridge) bridges.get(brIntUUID);
134 if (brInt.getName().equalsIgnoreCase(AdminConfigManager.getManager().getIntegrationBridgeName())) {
135 return addPatchPort(node, brIntUUID, patchTun, patchInt);
142 private Status addPatchPort (Node node, String bridgeUUID, String portName, String patchName) throws Exception {
143 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
145 Port patchPort = new Port();
146 patchPort.setName(portName);
147 // Create patch-int port and interface
148 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, patchPort);
149 if (!statusWithUuid.isSuccess()) return statusWithUuid;
151 String patchPortUUID = statusWithUuid.getUuid().toString();
153 String interfaceUUID = null;
155 while ((interfaceUUID == null) && (timeout > 0)) {
156 patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
157 OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
158 if (interfaces == null || interfaces.size() == 0) {
159 // Wait for the OVSDB update to sync up the Local cache.
164 interfaceUUID = interfaces.toArray()[0].toString();
167 if (interfaceUUID == null) {
168 return new Status(StatusCode.INTERNALERROR);
171 Interface tunInterface = new Interface();
172 tunInterface.setType("patch");
173 OvsDBMap<String, String> options = new OvsDBMap<String, String>();
174 options.put("peer", patchName);
175 tunInterface.setOptions(options);
176 return ovsdbTable.updateRow(node, Interface.NAME.getName(), patchPortUUID, interfaceUUID, tunInterface);
179 private void prepareInternalNetwork (NeutronNetwork network, Node node) {
180 // vlan, vxlan, and gre
181 if (network.getProviderNetworkType().equalsIgnoreCase("gre") ||
182 network.getProviderNetworkType().equalsIgnoreCase("vxlan") ||
183 network.getProviderNetworkType().equalsIgnoreCase("vlan")) {
186 if (!this.isInternalNetworkOverlayReady(node)) {
187 this.createInternalNetworkForOverlay(node);
189 } catch (Exception e) {
190 logger.error("Failed to create internal network for overlay on node " + node, e);
194 if (!this.isInternalNetworkNeutronReady(node)) {
196 // this.createInternalNetworkForNeutron(node);
198 } catch (Exception e) {
199 logger.error("Failed to create internal network for overlay on node " + node, e);
203 this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
204 this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
205 this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
208 private void initializeOFNormalFlowRules(Node node, String bridgeName) {
209 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
210 if (brIntId == null) {
211 logger.error("Failed to initialize Flow Rules for {}", node);
215 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
216 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
217 Set<String> dpids = bridge.getDatapath_id();
218 if (dpids == null || dpids.size() == 0) return;
219 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
220 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
221 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
222 IForwardingRulesManager.class, "default", this);
223 String flowName = ActionType.HW_PATH.toString();
224 if (frm.getStaticFlow(flowName, ofNode) != null) {
225 logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
228 FlowConfig flow = new FlowConfig();
229 flow.setName("IntegrationBridgeNormal");
230 flow.setNode(ofNode);
231 flow.setPriority(NORMAL_PRIORITY+"");
232 List<String> normalAction = new ArrayList<String>();
233 normalAction.add(flowName);
234 flow.setActions(normalAction);
235 Status status = frm.addStaticFlow(flow);
236 logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
237 } catch (Exception e) {
238 logger.error("Failed to initialize Flow Rules for {}", node, e);
242 private void initializeLLDPFlowRules(Node node, String bridgeName) {
243 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
244 if (brIntId == null) {
245 logger.error("Failed to initialize Flow Rules for {}", node);
249 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
250 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
251 Set<String> dpids = bridge.getDatapath_id();
252 if (dpids == null || dpids.size() == 0) return;
253 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
254 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
255 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
256 IForwardingRulesManager.class, "default", this);
257 String flowName = "PuntLLDP";
258 if (frm.getStaticFlow(flowName, ofNode) != null) {
259 logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
263 List<String> puntAction = new ArrayList<String>();
264 puntAction.add(ActionType.CONTROLLER.toString());
266 FlowConfig allowLLDP = new FlowConfig();
267 allowLLDP.setInstallInHw(true);
268 allowLLDP.setName(flowName);
269 allowLLDP.setPriority(LLDP_PRIORITY+"");
270 allowLLDP.setNode(ofNode);
271 allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
273 allowLLDP.setActions(puntAction);
274 Status status = frm.addStaticFlow(allowLLDP);
275 logger.debug("Flow Programming 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(NeutronNetwork network) {
282 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
283 List<Node> nodes = connectionService.getNodes();
284 for (Node node : nodes) {
285 prepareInternalNetwork(network, node);
289 public void prepareInternalNetwork(Node node) {
290 INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
291 List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
292 for (NeutronNetwork network : networks) {
293 prepareInternalNetwork(network, node);
297 public static List safe( List other ) {
298 return other == null ? Collections.EMPTY_LIST : other;