1 package org.opendaylight.ovsdb.neutron.provider;
3 import java.math.BigInteger;
4 import java.net.InetAddress;
5 import java.util.ArrayList;
10 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
11 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
12 import org.opendaylight.controller.sal.action.ActionType;
13 import org.opendaylight.controller.sal.core.Node;
14 import org.opendaylight.controller.sal.utils.HexEncode;
15 import org.opendaylight.controller.sal.utils.ServiceHelper;
16 import org.opendaylight.controller.sal.utils.Status;
17 import org.opendaylight.controller.sal.utils.StatusCode;
18 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
19 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
20 import org.opendaylight.ovsdb.lib.notation.UUID;
21 import org.opendaylight.ovsdb.lib.table.Bridge;
22 import org.opendaylight.ovsdb.lib.table.Interface;
23 import org.opendaylight.ovsdb.lib.table.Port;
24 import org.opendaylight.ovsdb.lib.table.internal.Table;
25 import org.opendaylight.ovsdb.neutron.AdminConfigManager;
26 import org.opendaylight.ovsdb.neutron.InternalNetworkManager;
27 import org.opendaylight.ovsdb.neutron.TenantNetworkManager;
28 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
29 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 class OF10ProviderManager extends ProviderNetworkManager {
35 private static final Logger logger = LoggerFactory.getLogger(OF10ProviderManager.class);
38 public boolean hasPerTenantTunneling() {
42 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
43 InetAddress srcTunnelEndPoint = AdminConfigManager.getManager().getTunnelEndPoint(node);
44 if (srcTunnelEndPoint == null) {
45 logger.error("Tunnel Endpoint not configured for Node {}", node);
46 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
50 if (!InternalNetworkManager.getManager().isInternalNetworkOverlayReady(node)) {
51 logger.error(node+" is not Overlay ready");
52 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
54 } catch (Exception e) {
55 logger.error(node+" is not Overlay ready");
56 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
59 if (!TenantNetworkManager.getManager().isTenantNetworkPresentInNode(node, tunnelKey)) {
60 logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
61 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
63 return new Status(StatusCode.SUCCESS);
66 private void programLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, String attachedMac,
67 int internalVlan, int patchPort) {
68 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
69 if (brIntId == null) {
70 logger.error("Failed to initialize Flow Rules for {}", node);
74 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
75 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
76 Set<String> dpids = bridge.getDatapath_id();
77 if (dpids == null || dpids.size() == 0) return;
78 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
79 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
80 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
81 IForwardingRulesManager.class, "default", this);
82 FlowConfig flow = new FlowConfig();
83 flow.setName("TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac));
85 flow.setPriority("100");
86 flow.setDstMac(attachedMac);
87 flow.setIngressPort(tunnelOFPort+"");
88 List<String> actions = new ArrayList<String>();
89 actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
90 actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
91 flow.setActions(actions);
92 Status status = frm.addStaticFlow(flow);
93 logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
94 } catch (Exception e) {
95 logger.error("Failed to initialize Flow Rules for {}", node, e);
99 private void programRemoteEgressTunnelBridgeRules(Node node, int patchPort, String attachedMac,
100 int internalVlan, int tunnelOFPort) {
101 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
102 if (brIntId == null) {
103 logger.error("Failed to initialize Flow Rules for {}", node);
107 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
108 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
109 Set<String> dpids = bridge.getDatapath_id();
110 if (dpids == null || dpids.size() == 0) return;
111 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
112 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
113 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
114 IForwardingRulesManager.class, "default", this);
115 FlowConfig flow = new FlowConfig();
116 flow.setName("TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac));
117 flow.setNode(ofNode);
118 flow.setPriority("100");
119 flow.setDstMac(attachedMac);
120 flow.setIngressPort(patchPort+"");
121 flow.setVlanId(internalVlan+"");
122 List<String> actions = new ArrayList<String>();
123 actions.add(ActionType.POP_VLAN.toString());
124 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
125 flow.setActions(actions);
126 Status status = frm.addStaticFlow(flow);
127 logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
128 } catch (Exception e) {
129 logger.error("Failed to initialize Flow Rules for {}", node, e);
133 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
134 Interface intf, boolean local) {
135 String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
136 if (networkId == null) {
137 logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
140 int internalVlan = TenantNetworkManager.getManager().getInternalVlan(networkId);
141 if (internalVlan == 0) {
142 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
145 Map<String, String> externalIds = intf.getExternal_ids();
146 if (externalIds == null) {
147 logger.error("No external_ids seen in {}", intf);
151 String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
152 if (attachedMac == null) {
153 logger.error("No AttachedMac seen in {}", intf);
156 String patchInt = "";
158 patchInt = AdminConfigManager.getManager().getPatchToIntegration();
160 patchInt = AdminConfigManager.getManager().getPatchToTunnel();
163 int patchOFPort = -1;
165 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
166 Map<String, Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
168 for (Table<?> row : intfs.values()) {
169 Interface patchIntf = (Interface)row;
170 if (patchIntf.getName().equalsIgnoreCase(patchInt)) {
171 Set<BigInteger> of_ports = patchIntf.getOfport();
172 if (of_ports == null || of_ports.size() <= 0) {
173 logger.error("Could NOT Identified Patch port {} -> OF ({}) on {}", patchInt, node);
176 patchOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
177 logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
181 if (patchOFPort == -1) {
182 logger.error("Cannot identify {} interface on {}", patchInt, node);
184 for (Table<?> row : intfs.values()) {
185 Interface tunIntf = (Interface)row;
186 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
187 Set<BigInteger> of_ports = tunIntf.getOfport();
188 if (of_ports == null || of_ports.size() <= 0) {
189 logger.error("Could NOT Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), node);
192 int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
193 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
196 programLocalIngressTunnelBridgeRules(node, tunnelOFPort, attachedMac, internalVlan, patchOFPort);
198 programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
204 } catch (Exception e) {
209 public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
210 Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
211 if (!status.isSuccess()) return status;
213 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
214 List<Node> nodes = connectionService.getNodes();
215 nodes.remove(srcNode);
216 for (Node dstNode : nodes) {
217 status = getTunnelReadinessStatus(dstNode, tunnelKey);
218 if (!status.isSuccess()) continue;
219 InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
220 InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
221 status = addTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
222 if (status.isSuccess()) {
223 this.programTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
225 addTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
226 if (status.isSuccess()) {
227 this.programTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
230 return new Status(StatusCode.SUCCESS);
234 private String getTunnelName(String tunnelType, String key, InetAddress dst) {
235 return tunnelType+"-"+key+"-"+dst.getHostAddress();
238 private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
240 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
241 String portName = getTunnelName(tunnelType, key, dst);
243 Map<String, Table<?>> tunIntfs = ovsdbTable.getRows(node, Interface.NAME.getName());
244 if (tunIntfs != null) {
245 for (Table<?> row : tunIntfs.values()) {
246 Interface tunIntf = (Interface)row;
247 if (tunIntf.getName().equals(portName)) return tunIntf;
251 } catch (Exception e) {
257 private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
258 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
259 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
260 if (bridge != null) {
261 Set<UUID> ports = bridge.getPorts();
262 for (UUID portUUID : ports) {
263 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
264 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
270 private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
272 String bridgeUUID = null;
273 String tunnelBridgeName = AdminConfigManager.getManager().getTunnelBridgeName();
274 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
275 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
276 if (bridgeTable != null) {
277 for (String uuid : bridgeTable.keySet()) {
278 Bridge bridge = (Bridge)bridgeTable.get(uuid);
279 if (bridge.getName().equals(tunnelBridgeName)) {
285 if (bridgeUUID == null) {
286 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
287 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
289 String portName = getTunnelName(tunnelType, key, dst);
291 if (this.isTunnelPresent(node, portName, bridgeUUID)) {
292 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
293 return new Status(StatusCode.SUCCESS);
296 Port tunnelPort = new Port();
297 tunnelPort.setName(portName);
298 Status status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, tunnelPort);
299 if (!status.isSuccess()) {
300 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
304 String tunnelPortUUID = status.getDescription();
306 String interfaceUUID = null;
308 while ((interfaceUUID == null) && (timeout > 0)) {
309 tunnelPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), tunnelPortUUID);
310 OvsDBSet<UUID> interfaces = tunnelPort.getInterfaces();
311 if (interfaces == null || interfaces.size() == 0) {
312 // Wait for the OVSDB update to sync up the Local cache.
317 interfaceUUID = interfaces.toArray()[0].toString();
318 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
319 if (intf == null) interfaceUUID = null;
322 if (interfaceUUID == null) {
323 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
324 return new Status(StatusCode.INTERNALERROR);
327 Interface tunInterface = new Interface();
328 tunInterface.setType(tunnelType);
329 OvsDBMap<String, String> options = new OvsDBMap<String, String>();
330 options.put("key", key);
331 options.put("local_ip", src.getHostAddress());
332 options.put("remote_ip", dst.getHostAddress());
333 tunInterface.setOptions(options);
334 status = ovsdbTable.updateRow(node, Interface.NAME.getName(), tunnelPortUUID, interfaceUUID, tunInterface);
335 logger.debug("Tunnel {} add status : {}", tunInterface, status);
337 } catch (Exception e) {
339 return new Status(StatusCode.INTERNALERROR);
344 public Status createTunnels(String tunnelType, String tunnelKey) {
345 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
346 List<Node> nodes = connectionService.getNodes();
347 for (Node srcNode : nodes) {
348 this.createTunnels(tunnelType, tunnelKey, srcNode, null);
350 return new Status(StatusCode.SUCCESS);