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.provider;
12 import java.math.BigInteger;
13 import java.net.InetAddress;
14 import java.util.ArrayList;
15 import java.util.List;
19 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
20 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
21 import org.opendaylight.controller.sal.action.ActionType;
22 import org.opendaylight.controller.sal.core.Node;
23 import org.opendaylight.controller.sal.utils.EtherTypes;
24 import org.opendaylight.controller.sal.utils.HexEncode;
25 import org.opendaylight.controller.sal.utils.ServiceHelper;
26 import org.opendaylight.controller.sal.utils.Status;
27 import org.opendaylight.controller.sal.utils.StatusCode;
28 import org.opendaylight.controller.switchmanager.ISwitchManager;
29 import org.opendaylight.controller.switchmanager.Switch;
30 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
31 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
32 import org.opendaylight.ovsdb.lib.notation.UUID;
33 import org.opendaylight.ovsdb.lib.table.Bridge;
34 import org.opendaylight.ovsdb.lib.table.Interface;
35 import org.opendaylight.ovsdb.lib.table.Port;
36 import org.opendaylight.ovsdb.lib.table.Table;
37 import org.opendaylight.ovsdb.neutron.AdminConfigManager;
38 import org.opendaylight.ovsdb.neutron.InternalNetworkManager;
39 import org.opendaylight.ovsdb.neutron.TenantNetworkManager;
40 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
41 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
42 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 class OF10ProviderManager extends ProviderNetworkManager {
48 private static final Logger logger = LoggerFactory.getLogger(OF10ProviderManager.class);
49 private static final int INGRESS_TUNNEL_FLOW_PRIORITY = 100;
50 private static final int EGRESS_TUNNEL_FLOW_PRIORITY = 100;
51 private static final int FLOOD_TUNNEL_FLOW_PRIORITY = 1;
54 public boolean hasPerTenantTunneling() {
58 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
59 InetAddress srcTunnelEndPoint = AdminConfigManager.getManager().getTunnelEndPoint(node);
60 if (srcTunnelEndPoint == null) {
61 logger.error("Tunnel Endpoint not configured for Node {}", node);
62 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
65 if (!InternalNetworkManager.getManager().isInternalNetworkOverlayReady(node)) {
66 logger.warn("{} is not Overlay ready. It might be an OpenStack Controller Node", node);
67 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
70 if (!TenantNetworkManager.getManager().isTenantNetworkPresentInNode(node, tunnelKey)) {
71 logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
72 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
74 return new Status(StatusCode.SUCCESS);
78 * Program OF1.0 Flow rules on br-tun on the ingress direction from the network towards the br-int.
79 * The logic is to simply match on the incoming tunnel OF-Port (which carries the TenantNetwork GRE-Key)
80 * and rewrite the Corresponding internal Vlan and pass it on to br-int via the patch port.
82 private void programLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, int internalVlan, int patchPort) {
83 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
84 if (brIntId == null) {
85 logger.error("Failed to initialize Flow Rules for {}", node);
89 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
90 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
91 Set<String> dpids = bridge.getDatapath_id();
92 if (dpids == null || dpids.size() == 0) return;
93 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
94 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
95 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
96 FlowConfig flow = new FlowConfig();
97 flow.setName(flowName);
99 flow.setInstallInHw(true);
100 flow.setPriority(INGRESS_TUNNEL_FLOW_PRIORITY+"");
101 flow.setIngressPort(tunnelOFPort+"");
102 List<String> actions = new ArrayList<String>();
103 actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
104 actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
105 flow.setActions(actions);
106 Status status = this.addStaticFlow(ofNode, flow);
107 logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
108 } catch (Exception e) {
109 logger.error("Failed to initialize Flow Rules for {}", node, e);
113 private void removeLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, int internalVlan, int patchPort) {
114 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
115 if (brIntId == null) {
116 logger.error("Failed to remove Flow Rules for {}", node);
120 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
121 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
122 Set<String> dpids = bridge.getDatapath_id();
123 if (dpids == null || dpids.size() == 0) return;
124 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
125 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
126 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
128 Status status = this.deleteStaticFlow(ofNode, flowName);
129 logger.debug("Local Ingress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
130 } catch (Exception e) {
131 logger.error("Failed to Remove Flow Rules for {}", node, e);
136 * Program OF1.0 Flow rules on br-tun on the remote Node on its egress direction towards the overlay network
137 * for a VM (with the attachedMac).
138 * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
139 * and output the traffic to the appropriate GRE Tunnel (which carries the GRE-Key for that Tenant Network).
140 * Also perform the Strip-Vlan action.
142 private void programRemoteEgressTunnelBridgeRules(Node node, int patchPort, String attachedMac,
143 int internalVlan, int tunnelOFPort) {
144 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
145 if (brIntId == null) {
146 logger.error("Failed to initialize Flow Rules for {}", node);
150 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
151 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
152 Set<String> dpids = bridge.getDatapath_id();
153 if (dpids == null || dpids.size() == 0) return;
154 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
155 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
156 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
157 FlowConfig flow = new FlowConfig();
158 flow.setName(flowName);
159 flow.setNode(ofNode);
160 flow.setInstallInHw(true);
161 flow.setPriority(EGRESS_TUNNEL_FLOW_PRIORITY+"");
162 flow.setDstMac(attachedMac);
163 flow.setIngressPort(patchPort+"");
164 flow.setVlanId(internalVlan+"");
165 List<String> actions = new ArrayList<String>();
166 actions.add(ActionType.POP_VLAN.toString());
167 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
168 flow.setActions(actions);
169 Status status = this.addStaticFlow(ofNode, flow);
170 logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
171 } catch (Exception e) {
172 logger.error("Failed to initialize Flow Rules for {}", node, e);
176 private void removeRemoteEgressTunnelBridgeRules(Node node, int patchPort, String attachedMac,
177 int internalVlan, int tunnelOFPort) {
178 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
179 if (brIntId == null) {
180 logger.error("Failed to initialize Flow Rules for {}", node);
184 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
185 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
186 Set<String> dpids = bridge.getDatapath_id();
187 if (dpids == null || dpids.size() == 0) return;
188 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
189 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
190 String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
191 Status status = this.deleteStaticFlow(ofNode, flowName);
192 logger.debug("Remote Egress Flow Removal Status {} for Flow {} on {} / {}", status, flowName, ofNode, node);
193 } catch (Exception e) {
194 logger.error("Failed to Remove Flow Rules for {}", node, e);
199 * Program OF1.0 Flow rules to flood the broadcast & unknown-unicast traffic over br-tun on the egress direction
200 * towards the network on all the overlay tunnels that corresponds to the tenant network.
201 * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
202 * and output the traffic to all the GRE-Tunnels for this Tenant Network (which carries the GRE-Key).
203 * Also perform the Strip-Vlan action.
205 private void programFloodEgressTunnelBridgeRules(Node node, int patchPort, int internalVlan, int tunnelOFPort) {
206 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
207 if (brIntId == null) {
208 logger.error("Failed to initialize Flow Rules for {}", node);
212 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
213 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
214 Set<String> dpids = bridge.getDatapath_id();
215 if (dpids == null || dpids.size() == 0) return;
216 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
217 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
218 String flowName = "TepFlood"+internalVlan;
219 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
220 IForwardingRulesManager.class, "default", this);
221 FlowConfig existingFlowConfig = frm.getStaticFlow(flowName, ofNode);
222 FlowConfig flow = existingFlowConfig;
223 Status status = null;
225 flow = new FlowConfig();
226 flow.setName(flowName);
227 flow.setNode(ofNode);
228 flow.setPriority(FLOOD_TUNNEL_FLOW_PRIORITY+"");
229 flow.setIngressPort(patchPort+"");
230 flow.setVlanId(internalVlan+"");
231 List<String> actions = new ArrayList<String>();
232 actions.add(ActionType.POP_VLAN.toString());
233 actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
234 flow.setActions(actions);
235 status = frm.addStaticFlow(flow);
236 logger.debug("Add Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
237 status, flow, ofNode, node);
239 flow = new FlowConfig(existingFlowConfig);
240 List<String> actions = flow.getActions();
241 String outputPort = ActionType.OUTPUT.toString()+"="+tunnelOFPort;
242 if (actions != null && !actions.contains(outputPort)) {
243 actions.add(outputPort);
244 flow.setActions(actions);
246 logger.debug("Flood Egress Flow already exists. Skipping modify for Flow {} on {} / {}",
250 status = frm.modifyStaticFlow(flow);
251 logger.debug("Modify Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
252 status, flow, ofNode, node);
254 } catch (Exception e) {
255 logger.error("Failed to initialize Flow Rules for {}", node, e);
259 private void removeFloodEgressTunnelBridgeRules(Node node, int patchPort, int internalVlan, int tunnelOFPort) {
260 String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
261 if (brIntId == null) {
262 logger.error("Failed to remove Flow Rules for {}", node);
266 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
267 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
268 Set<String> dpids = bridge.getDatapath_id();
269 if (dpids == null || dpids.size() == 0) return;
270 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
271 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
272 String flowName = "TepFlood"+internalVlan;
273 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
274 IForwardingRulesManager.class, "default", this);
275 FlowConfig flow = frm.getStaticFlow(flowName, ofNode);
276 Status status = null;
278 status = frm.removeStaticFlow(flowName, ofNode);
279 logger.debug("Remove Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
280 status, flow, ofNode, node);
283 logger.debug("Flood Egress Flow already removed. Skipping removal for Flow {} on {} / {}",
287 } catch (Exception e) {
288 logger.error("Failed to remove Flow Rules for {}", node, e);
292 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
293 Interface intf, boolean local) {
294 String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
295 if (networkId == null) {
296 logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
299 int internalVlan = TenantNetworkManager.getManager().getInternalVlan(node, networkId);
300 if (internalVlan == 0) {
301 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
304 Map<String, String> externalIds = intf.getExternal_ids();
305 if (externalIds == null) {
306 logger.error("No external_ids seen in {}", intf);
310 String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
311 if (attachedMac == null) {
312 logger.error("No AttachedMac seen in {}", intf);
315 String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
317 int patchOFPort = -1;
319 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
320 Map<String, Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
322 for (Table<?> row : intfs.values()) {
323 Interface patchIntf = (Interface)row;
324 if (patchIntf.getName().equalsIgnoreCase(patchInt)) {
325 Set<BigInteger> of_ports = patchIntf.getOfport();
326 if (of_ports == null || of_ports.size() <= 0) {
327 logger.error("Could NOT Identified Patch port {} on {}", patchInt, node);
330 patchOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
331 logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
335 if (patchOFPort == -1) {
336 logger.error("Cannot identify {} interface on {}", patchInt, node);
338 for (Table<?> row : intfs.values()) {
339 Interface tunIntf = (Interface)row;
340 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
341 Set<BigInteger> of_ports = tunIntf.getOfport();
342 if (of_ports == null || of_ports.size() <= 0) {
343 logger.warn("Could not Identify Tunnel port {} on {}. Don't panic. It might get converged soon...", tunIntf.getName(), node);
346 int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
348 if (tunnelOFPort == -1) {
349 logger.warn("Tunnel Port {} on node {}: OFPort = -1 . Don't panic. It might get converged soon...", tunIntf.getName(), node);
352 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
355 programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
357 programLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
358 programFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
363 } catch (Exception e) {
368 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
369 Interface intf, boolean local) {
370 String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
371 if (networkId == null) {
372 logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
375 int internalVlan = TenantNetworkManager.getManager().getInternalVlan(node,networkId);
376 if (internalVlan == 0) {
377 logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
380 Map<String, String> externalIds = intf.getExternal_ids();
381 if (externalIds == null) {
382 logger.error("No external_ids seen in {}", intf);
386 String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
387 if (attachedMac == null) {
388 logger.error("No AttachedMac seen in {}", intf);
391 String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
393 int patchOFPort = -1;
395 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
396 Map<String, Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
398 for (Table<?> row : intfs.values()) {
399 Interface patchIntf = (Interface)row;
400 if (patchIntf.getName().equalsIgnoreCase(patchInt)) {
401 Set<BigInteger> of_ports = patchIntf.getOfport();
402 if (of_ports == null || of_ports.size() <= 0) {
403 logger.error("Could NOT Identified Patch port {} on {}", patchInt, node);
406 patchOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
407 logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
411 if (patchOFPort == -1) {
412 logger.error("Cannot identify {} interface on {}", patchInt, node);
414 for (Table<?> row : intfs.values()) {
415 Interface tunIntf = (Interface)row;
416 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
417 Set<BigInteger> of_ports = tunIntf.getOfport();
418 if (of_ports == null || of_ports.size() <= 0) {
419 logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
422 int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
424 if (tunnelOFPort == -1) {
425 logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
428 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
431 removeRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
433 removeLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
434 removeFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
439 } catch (Exception e) {
445 public Status handleInterfaceUpdate(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
446 Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
447 if (!status.isSuccess()) return status;
449 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
450 List<Node> nodes = connectionService.getNodes();
451 nodes.remove(srcNode);
452 for (Node dstNode : nodes) {
453 status = getTunnelReadinessStatus(dstNode, tunnelKey);
454 if (!status.isSuccess()) continue;
455 InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
456 InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
457 status = addTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
458 if (status.isSuccess()) {
459 this.programTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
461 addTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
462 if (status.isSuccess()) {
463 this.programTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
466 return new Status(StatusCode.SUCCESS);
470 public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node srcNode, Interface intf, boolean isLastInstanceOnNode) {
471 Status status = new Status(StatusCode.SUCCESS);
473 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
474 List<Node> nodes = connectionService.getNodes();
475 nodes.remove(srcNode);
476 for (Node dstNode : nodes) {
477 InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
478 InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
479 this.removeTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
480 if (isLastInstanceOnNode) {
481 status = deleteTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
483 this.removeTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
484 if (status.isSuccess() && isLastInstanceOnNode) {
485 deleteTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
491 private String getTunnelName(String tunnelType, String key, InetAddress dst) {
492 return tunnelType+"-"+key+"-"+dst.getHostAddress();
495 private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
497 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
498 String portName = getTunnelName(tunnelType, key, dst);
500 Map<String, Table<?>> tunIntfs = ovsdbTable.getRows(node, Interface.NAME.getName());
501 if (tunIntfs != null) {
502 for (Table<?> row : tunIntfs.values()) {
503 Interface tunIntf = (Interface)row;
504 if (tunIntf.getName().equals(portName)) return tunIntf;
508 } catch (Exception e) {
514 private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
515 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
516 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
517 if (bridge != null) {
518 Set<UUID> ports = bridge.getPorts();
519 for (UUID portUUID : ports) {
520 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
521 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
527 private String getTunnelPortUuid(Node node, String tunnelName, String bridgeUUID) throws Exception {
528 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
529 Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
530 if (bridge != null) {
531 Set<UUID> ports = bridge.getPorts();
532 for (UUID portUUID : ports) {
533 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
534 if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return portUUID.toString();
540 private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
542 String bridgeUUID = null;
543 String tunnelBridgeName = AdminConfigManager.getManager().getTunnelBridgeName();
544 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
545 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
546 if (bridgeTable != null) {
547 for (String uuid : bridgeTable.keySet()) {
548 Bridge bridge = (Bridge)bridgeTable.get(uuid);
549 if (bridge.getName().equals(tunnelBridgeName)) {
555 if (bridgeUUID == null) {
556 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
557 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
559 String portName = getTunnelName(tunnelType, key, dst);
561 if (this.isTunnelPresent(node, portName, bridgeUUID)) {
562 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
563 return new Status(StatusCode.SUCCESS);
566 Port tunnelPort = new Port();
567 tunnelPort.setName(portName);
568 StatusWithUuid statusWithUuid = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, tunnelPort);
569 if (!statusWithUuid.isSuccess()) {
570 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
571 return statusWithUuid;
574 String tunnelPortUUID = statusWithUuid.getUuid().toString();
575 String interfaceUUID = null;
577 while ((interfaceUUID == null) && (timeout > 0)) {
578 tunnelPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), tunnelPortUUID);
579 OvsDBSet<UUID> interfaces = tunnelPort.getInterfaces();
580 if (interfaces == null || interfaces.size() == 0) {
581 // Wait for the OVSDB update to sync up the Local cache.
586 interfaceUUID = interfaces.toArray()[0].toString();
587 Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
588 if (intf == null) interfaceUUID = null;
591 if (interfaceUUID == null) {
592 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
593 return new Status(StatusCode.INTERNALERROR);
596 Interface tunInterface = new Interface();
597 tunInterface.setType(tunnelType);
598 OvsDBMap<String, String> options = new OvsDBMap<String, String>();
599 options.put("key", key);
600 options.put("local_ip", src.getHostAddress());
601 options.put("remote_ip", dst.getHostAddress());
602 tunInterface.setOptions(options);
603 Status status = ovsdbTable.updateRow(node, Interface.NAME.getName(), tunnelPortUUID, interfaceUUID, tunInterface);
604 logger.debug("Tunnel {} add status : {}", tunInterface, status);
606 } catch (Exception e) {
607 logger.error("Exception in addTunnelPort", e);
608 return new Status(StatusCode.INTERNALERROR);
612 private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
614 String bridgeUUID = null;
615 String tunnelBridgeName = AdminConfigManager.getManager().getTunnelBridgeName();
616 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
617 Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
618 if (bridgeTable != null) {
619 for (String uuid : bridgeTable.keySet()) {
620 Bridge bridge = (Bridge)bridgeTable.get(uuid);
621 if (bridge.getName().equals(tunnelBridgeName)) {
627 if (bridgeUUID == null) {
628 logger.debug("Could not find Bridge {} in {}", tunnelBridgeName, node);
629 return new Status(StatusCode.SUCCESS);
631 String portName = getTunnelName(tunnelType, key, dst);
632 String tunnelPortUUID = this.getTunnelPortUuid(node, portName, bridgeUUID);
633 Status status = ovsdbTable.deleteRow(node, Port.NAME.getName(), tunnelPortUUID);
634 if (!status.isSuccess()) {
635 logger.error("Failed to delete Tunnel port {} in {} status : {}", portName, bridgeUUID, status);
639 logger.debug("Tunnel {} delete status : {}", portName, status);
641 } catch (Exception e) {
642 logger.error("Exception in deleteTunnelPort", e);
643 return new Status(StatusCode.INTERNALERROR);
648 public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
649 IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
650 List<Node> nodes = connectionService.getNodes();
651 for (Node srcNode : nodes) {
652 this.handleInterfaceUpdate(tunnelType, tunnelKey, srcNode, null);
654 return new Status(StatusCode.SUCCESS);
658 public void initializeFlowRules(Node node) {
659 this.initializeFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
660 this.initializeFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
661 this.initializeFlowRules(node, AdminConfigManager.getManager().getExternalBridgeName());
664 private void initializeFlowRules(Node node, String bridgeName) {
665 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
666 if (brIntId == null) {
667 if (bridgeName == AdminConfigManager.getManager().getExternalBridgeName()){
668 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}. Is the Neutron L3 agent running on this node?");
671 logger.debug("Failed to initialize Flow Rules for bridge {} on node {}", bridgeName, node);
677 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
678 Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
679 Set<String> dpids = bridge.getDatapath_id();
680 if (dpids == null || dpids.size() == 0) return;
681 Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
682 Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
683 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, "default", this);
684 List<Switch> nodes = switchManager.getNetworkDevices();
686 logger.debug("No OF nodes learned yet in {}", node);
689 for (Switch device : nodes) {
690 if (device.getNode().equals(ofNode)) {
691 logger.debug("Initialize OF Flows on {}", ofNode);
692 initializeNormalFlowRules(ofNode);
696 logger.debug("Could not identify OF node {} for bridge {} in {}", ofNode.toString(), bridgeName, node.toString());
697 } catch (Exception e) {
698 logger.error("Failed to initialize Flow Rules for "+node.toString(), e);
703 public void initializeOFFlowRules(Node openflowNode) {
704 this.initializeNormalFlowRules(openflowNode);
705 this.initializeLLDPFlowRules(openflowNode);
708 private void initializeNormalFlowRules(Node ofNode) {
709 String flowName = ActionType.HW_PATH.toString();
710 FlowConfig flow = new FlowConfig();
711 flow.setName("NORMAL");
712 flow.setNode(ofNode);
713 flow.setPriority(NORMAL_PRIORITY+"");
714 flow.setInstallInHw(true);
715 List<String> normalAction = new ArrayList<String>();
716 normalAction.add(flowName);
717 flow.setActions(normalAction);
718 Status status = this.addStaticFlow(ofNode, flow);
719 logger.debug("Flow Programming Add Status {} for Flow {} on {}", status, flow, ofNode);
722 private void initializeLLDPFlowRules(Node ofNode) {
723 String flowName = "PuntLLDP";
724 List<String> puntAction = new ArrayList<String>();
725 puntAction.add(ActionType.CONTROLLER.toString());
727 FlowConfig allowLLDP = new FlowConfig();
728 allowLLDP.setName(flowName);
729 allowLLDP.setPriority(LLDP_PRIORITY+"");
730 allowLLDP.setNode(ofNode);
731 allowLLDP.setInstallInHw(true);
732 allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue()).toUpperCase());
733 allowLLDP.setActions(puntAction);
734 Status status = this.addStaticFlow(ofNode, allowLLDP);
735 logger.debug("LLDP Flow Add Status {} for Flow {} on {}", status, allowLLDP, ofNode);
738 private Status addStaticFlow (Node ofNode, FlowConfig flowConfig) {
739 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
740 IForwardingRulesManager.class, "default", this);
741 String flowName = flowConfig.getName();
742 if (frm.getStaticFlow(flowName, ofNode) != null) {
743 logger.debug("Flow already exists {} on {}. Skipping installation.", flowName, ofNode);
744 return new Status(StatusCode.CONFLICT, "Flow with name "+flowName+" exists in node "+ofNode.toString());
746 return frm.addStaticFlow(flowConfig);
749 private Status deleteStaticFlow (Node ofNode, String flowName) {
750 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
751 IForwardingRulesManager.class, "default", this);
752 if (frm.getStaticFlow(flowName, ofNode) == null) {
753 logger.debug("Flow doese not exist {} on {}. Skipping deletion.", flowName, ofNode);
754 return new Status(StatusCode.SUCCESS);
756 return frm.removeStaticFlow(flowName,ofNode);