From: Hsin-Yi Shen Date: Mon, 5 May 2014 23:55:34 +0000 (-0400) Subject: BUG-954: Add support for Neutron port/network delete events for OF1.3 X-Git-Tag: release/helium~203 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=a16a1d44d3c16f92269fe56ebbe70389bec5258e;p=ovsdb.git BUG-954: Add support for Neutron port/network delete events for OF1.3 This commit will enable support for Neutron port delete and network delete events. It will also enable flow cleanup and tunnel port delete for ovsdb using OF 1.3 Signed-off-by: Hsin-Yi Shen Change-Id: Ic848125d21abc44c796ef2b1675cca9e50630f76 --- diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/NetworkHandler.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/NetworkHandler.java index 628804779..33fce3de6 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/NetworkHandler.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/NetworkHandler.java @@ -5,14 +5,24 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * - * Authors : Madhu Venugopal, Brent Salisbury + * Authors : Madhu Venugopal, Brent Salisbury, Hsin-Yi Shen */ package org.opendaylight.ovsdb.neutron; import java.net.HttpURLConnection; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkAware; +import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD; import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.utils.ServiceHelper; +import org.opendaylight.ovsdb.lib.table.Interface; +import org.opendaylight.ovsdb.lib.table.internal.Table; +import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal; +import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -112,6 +122,39 @@ public class NetworkHandler extends BaseHandler result); return; } + /* Is this the last Neutron tenant network */ + INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this); + List networks = new ArrayList(); + if (neutronNetworkService != null) { + networks = neutronNetworkService.getAllNetworks(); + OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this); + if (networks.isEmpty()) { + logger.trace("neutronNetworkDeleted: last tenant network, delete tunnel ports..."); + IConnectionServiceInternal connectionService = (IConnectionServiceInternal) + ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this); + List nodes = connectionService.getNodes(); + + for (Node node : nodes) { + try { + ConcurrentMap> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName()); + if (interfaces != null) { + for (String intfUUID : interfaces.keySet()) { + Interface intf = (Interface) interfaces.get(intfUUID); + String intfType = intf.getType(); + if (intfType.equalsIgnoreCase("vxlan") || intfType.equalsIgnoreCase("gre")) { + /* delete tunnel ports on this node */ + logger.trace("Delete tunnel intf {}", intf); + inventoryListener.rowRemoved(node, Interface.NAME.getName(), intfUUID, + intf, null); + } + } + } + } catch (Exception e) { + logger.error("Exception during handlingNeutron network delete"); + } + } + } + } TenantNetworkManager.getManager().networkDeleted(network.getID()); } } diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/PortHandler.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/PortHandler.java index d30d01f0a..ec2156154 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/PortHandler.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/PortHandler.java @@ -10,9 +10,20 @@ package org.opendaylight.ovsdb.neutron; import java.net.HttpURLConnection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronPortAware; +import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork; import org.opendaylight.controller.networkconfig.neutron.NeutronPort; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.utils.ServiceHelper; +import org.opendaylight.ovsdb.lib.table.Interface; +import org.opendaylight.ovsdb.lib.table.internal.Table; +import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal; +import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -118,9 +129,43 @@ public class PortHandler extends BaseHandler return; } + IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this); + INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this); + NeutronNetwork neutronNetwork = neutronNetworkService.getNetwork(port.getNetworkUUID()); + OVSDBInventoryListener inventoryListener = (OVSDBInventoryListener)ServiceHelper.getGlobalInstance(OVSDBInventoryListener.class, this); + List nodes = connectionService.getNodes(); + for (Node node : nodes) { + try { + ConcurrentMap> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName()); + if (interfaces != null) { + for (String intfUUID : interfaces.keySet()) { + Interface intf = (Interface) interfaces.get(intfUUID); + Map externalIds = intf.getExternal_ids(); + if (externalIds == null) { + logger.trace("No external_ids seen in {}", intf); + continue; + } + /* Compare Neutron port uuid */ + String neutronPortId = externalIds.get(TenantNetworkManager.EXTERNAL_ID_INTERFACE_ID); + if (neutronPortId == null) { + continue; + } + if (neutronPortId.equalsIgnoreCase(port.getPortUUID())) { + logger.trace("neutronPortDeleted: Delete interface {}", intf.getName()); + inventoryListener.rowRemoved(node, Interface.NAME.getName(), intfUUID, + intf, neutronNetwork); + break; + } + } + } + } catch (Exception e) { + logger.error("Exception during handlingNeutron network delete"); + } + } logger.debug(" PORT delete successful for tenant-id - {}, " + " network-id - {}, port-id - {}", port.getTenantID(), port.getNetworkUUID(), port.getID()); + } } diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundEvent.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundEvent.java index df3b734d8..70e69c814 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundEvent.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundEvent.java @@ -21,6 +21,7 @@ public class SouthboundEvent { private String tableName; private String uuid; private Table row; + private Object context; public SouthboundEvent(Node node, Action action) { super(); this.type = Type.NODE; @@ -36,6 +37,16 @@ public class SouthboundEvent { this.uuid = uuid; this.row = row; } + public SouthboundEvent(Node node, String tableName, String uuid, Table row, Object context, Action action) { + super(); + this.type = Type.ROW; + this.action = action; + this.node = node; + this.tableName = tableName; + this.uuid = uuid; + this.row = row; + this.context = context; + } public Type getType() { return type; } @@ -54,10 +65,13 @@ public class SouthboundEvent { public Table getRow() { return row; } + public Object getContext() { + return context; + } @Override public String toString() { return "SouthboundEvent [type=" + type + ", action=" + action + ", node=" + node + ", tableName=" + tableName - + ", uuid=" + uuid + ", row=" + row + "]"; + + ", uuid=" + uuid + ", row=" + row + ", context=" + context.toString() + "]"; } @Override public int hashCode() { diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java index dc8267bcc..2efdb2b16 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java @@ -70,7 +70,7 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList break; case ROW: try { - processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(), ev.getAction()); + processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(), ev.getContext(), ev.getAction()); } catch (Exception e) { logger.error("Exception caught in ProcessRowUpdate for node " + ev.getNode(), e); } @@ -134,14 +134,20 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList logger.trace("IGNORING Port Update : "+newRow.toString()); return false; } + } else if (newRow.getTableName().equals(Open_vSwitch.NAME)) { + /* print the row for now */ + Open_vSwitch oldOpenvSwitch = (Open_vSwitch) oldRow; + if (oldOpenvSwitch.getOther_config()== null) { + /* we are only interested in other_config field change */ + return false; + } } - return true; } @Override - public void rowRemoved(Node node, String tableName, String uuid, Table row) { - this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, SouthboundEvent.Action.DELETE)); + public void rowRemoved(Node node, String tableName, String uuid, Table row, Object context) { + this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, context, SouthboundEvent.Action.DELETE)); } private void enqueueEvent (SouthboundEvent event) { @@ -160,12 +166,23 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList } private void processRowUpdate(Node node, String tableName, String uuid, Table row, - SouthboundEvent.Action action) { + Object context, SouthboundEvent.Action action) { if (action == SouthboundEvent.Action.DELETE) { if (Interface.NAME.getName().equalsIgnoreCase(tableName)) { + logger.debug("processRowUpdate: {} Deleted node: {}, uuid: {}, row: {}", tableName,node, uuid, row); Interface deletedIntf = (Interface)row; - NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(deletedIntf); - if (network != null && !network.getRouterExternal()) { + NeutronNetwork network = null; + if (context == null) { + network = TenantNetworkManager.getManager().getTenantNetworkForInterface(deletedIntf); + } else { + network = (NeutronNetwork)context; + } + logger.info("Delete interface " + deletedIntf.getName()); + if (deletedIntf.getType().equalsIgnoreCase("vxlan") || + deletedIntf.getType().equalsIgnoreCase("gre")) { + /* delete tunnel interfaces */ + this.handleInterfaceDelete(node, uuid, deletedIntf, false, null); + } else if (network != null && !network.getRouterExternal()) { try { ConcurrentMap> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName()); if (interfaces != null) { @@ -176,7 +193,7 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList NeutronNetwork neutronNetwork = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf); if (neutronNetwork != null && neutronNetwork.equals(network)) isLastInstanceOnNode = false; } - this.handleInterfaceDelete(node, uuid, deletedIntf, isLastInstanceOnNode); + this.handleInterfaceDelete(node, uuid, deletedIntf, isLastInstanceOnNode, network); } } catch (Exception e) { logger.error("Error fetching Interface Rows for node " + node, e); @@ -243,18 +260,23 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList network.getProviderSegmentationID(), node, intf); } } - private void handleInterfaceDelete (Node node, String uuid, Interface intf, boolean isLastInstanceOnNode) { - if (AdminConfigManager.getManager().getTunnelEndPoint(node) == null) { - logger.error("Tunnel end-point configuration missing. Please configure it in Open_vSwitch Table"); - return; - } - NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf); - if (network != null) { - if (isLastInstanceOnNode) { + private void handleInterfaceDelete (Node node, String uuid, Interface intf, boolean isLastInstanceOnNode, + NeutronNetwork network) { + if (intf.getType().equalsIgnoreCase("vxlan") || intf.getType().equalsIgnoreCase("gre")) { + /* delete tunnel interfaces */ + logger.debug("handlerInterfaceDelete: intf {}", intf); + ProviderNetworkManager.getManager().handleInterfaceDelete(intf.getType(), + null, node, intf, isLastInstanceOnNode); + } else if (network != null) { + if (AdminConfigManager.getManager().getTunnelEndPoint(node) == null) { + logger.error("Tunnel end-point configuration missing. Please configure it in Open_vSwitch Table"); + return; + } + if (isLastInstanceOnNode & ProviderNetworkManager.getManager().hasPerTenantTunneling()) { TenantNetworkManager.getManager().reclaimTennantNetworkInternalVlan(node, uuid, network); } ProviderNetworkManager.getManager().handleInterfaceDelete(network.getProviderNetworkType(), - network.getProviderSegmentationID(), node, intf, isLastInstanceOnNode); + network.getProviderSegmentationID(), node, intf, isLastInstanceOnNode); } } diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java index cf3743e4a..7131677c5 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10ProviderManager.java @@ -469,20 +469,36 @@ class OF10ProviderManager extends ProviderNetworkManager { @Override public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node srcNode, Interface intf, boolean isLastInstanceOnNode) { Status status = new Status(StatusCode.SUCCESS); - - IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this); - List nodes = connectionService.getNodes(); - nodes.remove(srcNode); - for (Node dstNode : nodes) { - InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode); - InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode); - this.removeTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true); - if (isLastInstanceOnNode) { - status = deleteTunnelPort(srcNode, tunnelType, src, dst, tunnelKey); + logger.debug("handleInterfaceDelete: networkType: {}, segmentationId: {}, srcNode: {}, intf:{}", + tunnelType, tunnelKey, srcNode, + intf.getName(), isLastInstanceOnNode); + if (intf.getType().equalsIgnoreCase("vxlan") || intf.getType().equalsIgnoreCase("gre")) { + /* Delete tunnel port */ + try { + OvsDBMap options = intf.getOptions(); + InetAddress src = InetAddress.getByName(options.get("local_ip")); + InetAddress dst = InetAddress.getByName(options.get("remote_ip")); + String key = options.get("key"); + status = deleteTunnelPort(srcNode, intf.getType(), src, dst, key); + } catch (Exception e) { + logger.error(e.getMessage(), e); } - this.removeTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false); - if (status.isSuccess() && isLastInstanceOnNode) { - deleteTunnelPort(dstNode, tunnelType, dst, src, tunnelKey); + } else { + /* delete all other interfaces */ + IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this); + List nodes = connectionService.getNodes(); + nodes.remove(srcNode); + for (Node dstNode : nodes) { + InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode); + InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode); + this.removeTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true); + if (isLastInstanceOnNode) { + status = deleteTunnelPort(srcNode, tunnelType, src, dst, tunnelKey); + } + this.removeTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false); + if (status.isSuccess() && isLastInstanceOnNode) { + deleteTunnelPort(dstNode, tunnelType, dst, src, tunnelKey); + } } } return status; diff --git a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java index 08ab0ce3c..1f864e0d7 100644 --- a/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java +++ b/neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13ProviderManager.java @@ -167,6 +167,19 @@ class OF13ProviderManager extends ProviderNetworkManager { return false; } + private String getPortUuid(Node node, String name, String bridgeUUID) throws Exception { + OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this); + Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID); + if (bridge != null) { + Set ports = bridge.getPorts(); + for (UUID portUUID : ports) { + Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString()); + if (port != null && port.getName().equalsIgnoreCase(name)) return portUUID.toString(); + } + } + return null; + } + private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) { try { String bridgeUUID = null; @@ -239,6 +252,51 @@ class OF13ProviderManager extends ProviderNetworkManager { } } + /* delete port from ovsdb port table */ + private Status deletePort(Node node, String bridgeName, String portName) { + try { + String bridgeUUID = null; + OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this); + Map> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName()); + if (bridgeTable != null) { + for (String uuid : bridgeTable.keySet()) { + Bridge bridge = (Bridge)bridgeTable.get(uuid); + if (bridge.getName().equals(bridgeName)) { + bridgeUUID = uuid; + break; + } + } + } + if (bridgeUUID == null) { + logger.debug("Could not find Bridge {} in {}", bridgeName, node); + return new Status(StatusCode.SUCCESS); + } + + String portUUID = this.getPortUuid(node, portName, bridgeUUID); + Status status = new Status(StatusCode.SUCCESS); + if (portUUID != null) { + status = ovsdbTable.deleteRow(node, Port.NAME.getName(), portUUID); + if (!status.isSuccess()) { + logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID, + status); + return status; + } + logger.debug("Port {} delete status : {}", portName, status); + } + return status; + } catch (Exception e) { + logger.error("Exception in deletePort", e); + return new Status(StatusCode.INTERNALERROR); + } + } + + private Status deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) { + String tunnelBridgeName = AdminConfigManager.getManager().getIntegrationBridgeName(); + String portName = getTunnelName(tunnelType, dst); + Status status = deletePort(node, tunnelBridgeName, portName); + return status; + } + private void programLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) { /* * Table(0) Rule #3 @@ -247,7 +305,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * Action:Action: Set Tunnel ID and GOTO Local Table (5) */ - writeLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac); + handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, true); /* * Table(0) Rule #4 @@ -256,7 +314,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * Action: Drop w/ a low priority */ - writeDropSrcIface(dpid, localPort); + handleDropSrcIface(dpid, localPort, true); /* * Table(2) Rule #1 @@ -266,7 +324,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 */ - writeLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac); + handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true); /* * Table(2) Rule #2 @@ -276,7 +334,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=output:2,3,4,5 */ - writeLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort); + handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true); /* * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment. @@ -290,7 +348,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=1,priority=8192,tun_id=0x5 actions=goto_table:2 */ - writeTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId); + handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true); /* * Table(2) Rule #3 @@ -300,7 +358,47 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=2,priority=8192,tun_id=0x5 actions=drop */ - writeLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId); + handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true); + } + + private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) { + /* + ** Table(0) Rule #3 + ** ---------------- + ** Match: VM sMac and Local Ingress Port + ** Action:Action: Set Tunnel ID and GOTO Local Table (5) + **/ + + handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false); + + /* + ** Table(0) Rule #4 + ** ---------------- + ** Match: Drop any remaining Ingress Local VM Packets + ** Action: Drop w/ a low priority + **/ + + handleDropSrcIface(dpid, localPort, false); + + /* + ** Table(2) Rule #1 + ** ---------------- + ** Match: Match TunID and Destination DL/dMAC Addr + ** Action: Output Port + ** table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 + **/ + + handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false); + + /* + ** Table(2) Rule #2 + ** ---------------- + ** Match: Tunnel ID and dMAC (::::FF:FF) + ** table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \ + ** actions=output:2,3,4,5 + **/ + + handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false); } private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) { @@ -308,10 +406,10 @@ class OF13ProviderManager extends ProviderNetworkManager { * Table(0) Rule #2 * ---------------- * Match: Ingress Port, Tunnel ID - * Action: GOTO Local Table (10) + * Action: GOTO Local Table (20) */ - writeTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort); + handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true); /* * Table(1) Rule #2 @@ -323,7 +421,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=output:10,output:11,goto_table:2 */ - writeTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort); + handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true); } @@ -338,7 +436,69 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=output:11,goto_table:2 */ - writeTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac); + handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true); + } + + private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) { + /* + ** Table(1) Rule #1 + ** ---------------- + ** Match: Drop any remaining Ingress Local VM Packets + ** Action: Drop w/ a low priority + ** ------------------------------------------- + ** table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \ + ** actions=output:11,goto_table:2 + **/ + + handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false); + } + + /* Remove tunnel rules if last node in this tenant network */ + private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) { + /* + ** TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment. + **/ + /* + ** Table(1) Rule #3 + ** ---------------- + ** Match: Any remaining Ingress Local VM Packets + ** Action: Drop w/ a low priority + ** ------------------------------------------- + ** table=1,priority=8192,tun_id=0x5 actions=goto_table:2 + **/ + + handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false); + + /* + ** Table(2) Rule #3 + ** ---------------- + ** Match: Any Remaining Flows w/a TunID + ** Action: Drop w/ a low priority + ** table=2,priority=8192,tun_id=0x5 actions=drop + **/ + + handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false); + + /* + ** Table(0) Rule #2 + ** ---------------- + ** Match: Ingress Port, Tunnel ID + ** Action: GOTO Local Table (10) + **/ + + handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false); + + /* + ** Table(1) Rule #2 + ** ---------------- + ** Match: Match Tunnel ID and L2 ::::FF:FF Flooding + ** Action: Flood to selected destination TEPs + ** ------------------------------------------- + ** table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \ + ** actions=output:10,output:11,goto_table:2 + **/ + + handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false); } private Long getIntegrationBridgeOFDPID (Node node) { @@ -393,6 +553,45 @@ class OF13ProviderManager extends ProviderNetworkManager { } } + private void removeLocalRules (String networkType, String segmentationId, Node node, Interface intf) { + try { + Long dpid = this.getIntegrationBridgeOFDPID(node); + if (dpid == 0L) { + logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node); + return; + } + + Set of_ports = intf.getOfport(); + if (of_ports == null || of_ports.size() <= 0) { + logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node); + return; + } + long localPort = ((BigInteger)of_ports.toArray()[0]).longValue(); + + Map externalIds = intf.getExternal_ids(); + if (externalIds == null) { + logger.error("No external_ids seen in {}", intf); + return; + } + + String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC); + if (attachedMac == null) { + logger.error("No AttachedMac seen in {}", intf); + return; + } + + /* Program local rules based on network type */ + if (networkType.equalsIgnoreCase("gre") || + networkType.equalsIgnoreCase("vxlan")) { + logger.debug("Remove local bridge rules for interface {}", intf.getName()); + removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort); + } + } catch (Exception e) { + logger.error("Exception in removing Local Rules for "+intf+" on "+node, e); + } + } + + private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node, Interface intf, boolean local) { try { @@ -444,7 +643,73 @@ class OF13ProviderManager extends ProviderNetworkManager { if (!local) { programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort); } - programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort); + logger.trace("program local ingress tunnel rules: node" + node.getNodeIDString() + " intf " + intf.getName()); + if (local) { + programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort); + } + return; + } + } + } + } catch (Exception e) { + logger.error("", e); + } + } + + private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node, + Interface intf, boolean local, boolean isLastInstanceOnNode) { + try { + + Long dpid = this.getIntegrationBridgeOFDPID(node); + if (dpid == 0L) { + logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node); + return; + } + OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this); + + Set of_ports = intf.getOfport(); + if (of_ports == null || of_ports.size() <= 0) { + logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node); + return; + } + long localPort = ((BigInteger)of_ports.toArray()[0]).longValue(); + + Map externalIds = intf.getExternal_ids(); + if (externalIds == null) { + logger.error("No external_ids seen in {}", intf); + return; + } + + String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC); + if (attachedMac == null) { + logger.error("No AttachedMac seen in {}", intf); + return; + } + + Map> intfs = ovsdbTable.getRows(node, Interface.NAME.getName()); + if (intfs != null) { + for (org.opendaylight.ovsdb.lib.table.internal.Table row : intfs.values()) { + Interface tunIntf = (Interface)row; + if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) { + of_ports = tunIntf.getOfport(); + if (of_ports == null || of_ports.size() <= 0) { + logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node); + continue; + } + long tunnelOFPort = ((BigInteger)of_ports.toArray()[0]).longValue(); + + if (tunnelOFPort == -1) { + logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node); + return; + } + logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node); + + if (!local) { + removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort); + } + if (local && isLastInstanceOnNode) { + removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort); + } return; } } @@ -532,10 +797,44 @@ class OF13ProviderManager extends ProviderNetworkManager { } @Override - public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node source, Interface intf, + public Status handleInterfaceDelete(String tunnelType, String tunnelKey, Node srcNode, Interface intf, boolean isLastInstanceOnNode) { - // TODO Auto-generated method stub - return null; + Status status = new Status(StatusCode.SUCCESS); + IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this); + List nodes = connectionService.getNodes(); + nodes.remove(srcNode); + + logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode); + if (intf.getType().equalsIgnoreCase("vxlan") || intf.getType().equalsIgnoreCase("gre")) { + /* Delete tunnel port */ + try { + OvsDBMap options = intf.getOptions(); + InetAddress src = InetAddress.getByName(options.get("local_ip")); + InetAddress dst = InetAddress.getByName(options.get("remote_ip")); + status = deleteTunnelPort(srcNode, intf.getType(), src, dst); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } else { + /* delete all other interfaces */ + this.removeLocalRules(tunnelType, tunnelKey, + srcNode, intf); + + if (tunnelType.equalsIgnoreCase("gre") + || tunnelType.equalsIgnoreCase("vxlan")) { + for (Node dstNode : nodes) { + InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode); + InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode); + logger.info("Remove tunnel rules for interface " + intf.getName() + " on srcNode" + srcNode.getNodeIDString()); + this.removeTunnelRules(tunnelType, tunnelKey, + dst, srcNode, intf, true, isLastInstanceOnNode); + logger.info("Remove tunnel rules for interface " + intf.getName() + " on dstNode" + dstNode.getNodeIDString()); + this.removeTunnelRules(tunnelType, tunnelKey, + src, dstNode, intf, false, isLastInstanceOnNode); + } + } + } + return status; } @Override @@ -623,7 +922,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=0,tun_id=0x5,in_port=10, actions=goto_table:2 */ - private void writeTunnelIn(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, Long ofPort) { + private void handleTunnelIn(Long dpidLong, Short writeTable, Short goToTableId, + String segmentationId, Long ofPort, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -636,24 +936,26 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, tunnelId).build()); flowBuilder.setMatch(createInPortMatch(matchBuilder, dpidLong, ofPort).build()); - // Create the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); + if (write) { + // Create the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // Call the InstructionBuilder Methods Containing Actions - createGotoTableInstructions(ib, goToTableId); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); + // Call the InstructionBuilder Methods Containing Actions + createGotoTableInstructions(ib, goToTableId); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + } String flowId = "TunnelIn_"+segmentationId+"_"+ofPort; // Add Flow Attributes @@ -666,7 +968,12 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setFlowName(flowId); flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - writeFlow(flowBuilder, nodeBuilder); + + if (write) { + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } /* @@ -677,7 +984,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=set_field:5->tun_id,goto_table=1" */ - private void writeLocalInPort(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, Long inPort, String attachedMac) { + private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId, + String segmentationId, Long inPort, String attachedMac, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -702,31 +1010,35 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - // Instantiate the Builders for the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); + if (write) { + // Instantiate the Builders for the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // GOTO Instuctions Need to be added first to the List - createGotoTableInstructions(ib, goToTableId); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); - // TODO Broken SetTunID - createSetTunnelIdInstructions(ib, new BigInteger(segmentationId)); - ib.setOrder(1); - ib.setKey(new InstructionKey(1)); - instructions.add(ib.build()); + // GOTO Instuctions Need to be added first to the List + createGotoTableInstructions(ib, goToTableId); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); + // TODO Broken SetTunID + createSetTunnelIdInstructions(ib, new BigInteger(segmentationId)); + ib.setOrder(1); + ib.setKey(new InstructionKey(1)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); - writeFlow(flowBuilder, nodeBuilder); + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } /* @@ -737,7 +1049,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=0,priority=16384,in_port=1 actions=drop" */ - private void writeDropSrcIface(Long dpidLong, Long inPort) { + private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -748,24 +1060,26 @@ class OF13ProviderManager extends ProviderNetworkManager { // Create the OF Match using MatchBuilder flowBuilder.setMatch(createInPortMatch(matchBuilder, dpidLong, inPort).build()); - // Instantiate the Builders for the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); + if (write) { + // Instantiate the Builders for the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // Call the InstructionBuilder Methods Containing Actions - createDropInstructions(ib); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); + // Call the InstructionBuilder Methods Containing Actions + createDropInstructions(ib); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + } String flowId = "DropFilter_"+inPort; // Add Flow Attributes @@ -779,7 +1093,11 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setPriority(8192); flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - writeFlow(flowBuilder, nodeBuilder); + if (write) { + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } /* @@ -790,7 +1108,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=output:10,goto_table:2" */ - private void writeTunnelOut(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId , Long OFPortOut, String attachedMac) { + private void handleTunnelOut(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, + Long OFPortOut, String attachedMac, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -813,31 +1132,36 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setFlowName(flowId); flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - // Instantiate the Builders for the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + if (write) { + // Instantiate the Builders for the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // GOTO Instuctions - createGotoTableInstructions(ib, goToTableId); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); - // Set the Output Port/Iface - createOutputPortInstructions(ib, dpidLong, OFPortOut); - ib.setOrder(1); - ib.setKey(new InstructionKey(1)); - instructions.add(ib.build()); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // GOTO Instuctions + createGotoTableInstructions(ib, goToTableId); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); + // Set the Output Port/Iface + createOutputPortInstructions(ib, dpidLong, OFPortOut); + ib.setOrder(1); + ib.setKey(new InstructionKey(1)); + instructions.add(ib.build()); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - writeFlow(flowBuilder, nodeBuilder); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } /* @@ -848,7 +1172,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=output:10,output:11,goto_table:2 */ - private void writeTunnelFloodOut(Long dpidLong, Short writeTable, Short localTable, String segmentationId, Long OFPortOut) { + private void handleTunnelFloodOut(Long dpidLong, Short writeTable, Short localTable, + String segmentationId, Long OFPortOut, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -887,24 +1212,45 @@ class OF13ProviderManager extends ProviderNetworkManager { existingInstructions = ins.getInstruction(); } } - // GOTO Instuction - createGotoTableInstructions(ib, localTable); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); - // Set the Output Port/Iface - createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions); - ib.setOrder(1); - ib.setKey(new InstructionKey(1)); - instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + if (write) { + // GOTO Instuction + createGotoTableInstructions(ib, localTable); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); + // Set the Output Port/Iface + createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions); + ib.setOrder(1); + ib.setKey(new InstructionKey(1)); + instructions.add(ib.build()); + + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); + + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + + writeFlow(flowBuilder, nodeBuilder); + } else { + /* remove port from action list */ + boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,OFPortOut, existingInstructions); + if (flowRemove) { + /* if all port are removed, remove the flow too. */ + removeFlow(flowBuilder, nodeBuilder); + } else { + /* Install instruction with new output port list*/ + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - writeFlow(flowBuilder, nodeBuilder); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + } + } } /* @@ -914,7 +1260,7 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=2,priority=8192,tun_id=0x5 actions=drop */ - private void writeTunnelMiss(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId) { + private void handleTunnelMiss(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -925,24 +1271,26 @@ class OF13ProviderManager extends ProviderNetworkManager { // Create Match(es) and Set them in the FlowBuilder Object flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build()); - // Create the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); + if (write) { + // Create the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // Call the InstructionBuilder Methods Containing Actions - createGotoTableInstructions(ib, goToTableId); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); + // Call the InstructionBuilder Methods Containing Actions + createGotoTableInstructions(ib, goToTableId); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + } String flowId = "TunnelMiss_"+segmentationId; // Add Flow Attributes @@ -956,7 +1304,11 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setFlowName(flowId); flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - writeFlow(flowBuilder, nodeBuilder); + if (write) { + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } /* @@ -966,7 +1318,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2 */ - private void writeLocalUcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort, String attachedMac) { + private void handleLocalUcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort, + String attachedMac, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -990,25 +1343,29 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - // Instantiate the Builders for the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); + if (write) { + // Instantiate the Builders for the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // Set the Output Port/Iface - createOutputPortInstructions(ib, dpidLong, localPort); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); + // Set the Output Port/Iface + createOutputPortInstructions(ib, dpidLong, localPort); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); - writeFlow(flowBuilder, nodeBuilder); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } /* @@ -1018,7 +1375,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * actions=output:2,3,4,5 */ - private void writeLocalBcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort) { + private void handleLocalBcastOut(Long dpidLong, Short writeTable, String segmentationId, + Long localPort, boolean write) { String nodeName = "openflow:" + dpidLong; @@ -1055,19 +1413,41 @@ class OF13ProviderManager extends ProviderNetworkManager { } } - // Broken OutPort TODO: localPort needs to be a list of Ports) - createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); + if (write) { + // Create output port list + createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); - writeFlow(flowBuilder, nodeBuilder); + writeFlow(flowBuilder, nodeBuilder); + } else { + boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong, + localPort, existingInstructions); + if (flowRemove) { + /* if all ports are removed, remove flow */ + removeFlow(flowBuilder, nodeBuilder); + } else { + /* Install instruction with new output port list*/ + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); + + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); + + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + + writeFlow(flowBuilder, nodeBuilder); + } + } } /* @@ -1077,7 +1457,8 @@ class OF13ProviderManager extends ProviderNetworkManager { * table=2,priority=8192,tun_id=0x5 actions=drop */ - private void writeLocalTableMiss(Long dpidLong, Short writeTable, String segmentationId) { + private void handleLocalTableMiss(Long dpidLong, Short writeTable, String segmentationId, + boolean write) { String nodeName = "openflow:" + dpidLong; @@ -1088,24 +1469,26 @@ class OF13ProviderManager extends ProviderNetworkManager { // Create Match(es) and Set them in the FlowBuilder Object flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build()); - // Create the OF Actions and Instructions - InstructionBuilder ib = new InstructionBuilder(); - InstructionsBuilder isb = new InstructionsBuilder(); + if (write) { + // Create the OF Actions and Instructions + InstructionBuilder ib = new InstructionBuilder(); + InstructionsBuilder isb = new InstructionsBuilder(); - // Instructions List Stores Individual Instructions - List instructions = new ArrayList(); + // Instructions List Stores Individual Instructions + List instructions = new ArrayList(); - // Call the InstructionBuilder Methods Containing Actions - createDropInstructions(ib); - ib.setOrder(0); - ib.setKey(new InstructionKey(0)); - instructions.add(ib.build()); + // Call the InstructionBuilder Methods Containing Actions + createDropInstructions(ib); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + instructions.add(ib.build()); - // Add InstructionBuilder to the Instruction(s)Builder List - isb.setInstruction(instructions); + // Add InstructionBuilder to the Instruction(s)Builder List + isb.setInstruction(instructions); - // Add InstructionsBuilder to FlowBuilder - flowBuilder.setInstructions(isb.build()); + // Add InstructionsBuilder to FlowBuilder + flowBuilder.setInstructions(isb.build()); + } String flowId = "LocalTableMiss_"+segmentationId; // Add Flow Attributes @@ -1119,7 +1502,11 @@ class OF13ProviderManager extends ProviderNetworkManager { flowBuilder.setFlowName(flowId); flowBuilder.setHardTimeout(0); flowBuilder.setIdleTimeout(0); - writeFlow(flowBuilder, nodeBuilder); + if (write) { + writeFlow(flowBuilder, nodeBuilder); + } else { + removeFlow(flowBuilder, nodeBuilder); + } } private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) { @@ -1175,6 +1562,41 @@ class OF13ProviderManager extends ProviderNetworkManager { } } + private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) { + IMDSALConsumer mdsalConsumer = (IMDSALConsumer) ServiceHelper.getInstance(IMDSALConsumer.class, "default", this); + if (mdsalConsumer == null) { + logger.error("ERROR finding MDSAL Service."); + return; + } + + dataBrokerService = mdsalConsumer.getDataBrokerService(); + + if (dataBrokerService == null) { + logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SALsupport on the Controller."); + return; + } + DataModification, DataObject> modification = dataBrokerService.beginTransaction(); + InstanceIdentifier path1 = InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory + .rev130819.nodes.Node.class, nodeBuilder.getKey()) + .augmentation(FlowCapableNode.class).child(Table.class, + new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build(); + //modification.removeOperationalData(nodeBuilderToInstanceId(nodeBuilder)); + modification.removeOperationalData(path1); + //modification.removeConfigurationData(nodeBuilderToInstanceId(nodeBuilder)); + modification.removeConfigurationData(path1); + Future> commitFuture = modification.commit(); + try { + RpcResult result = commitFuture.get(); + TransactionStatus status = result.getResult(); + logger.debug("Transaction Status "+status.toString()+" for Flow "+flowBuilder.getFlowName()); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } catch (ExecutionException e) { + logger.error(e.getMessage(), e); + } + } + /** * Create Ingress Port Match dpidLong, inPort * @@ -1529,6 +1951,60 @@ class OF13ProviderManager extends ProviderNetworkManager { return ib; } + /** + * Remove Output Port from Instruction + * + * @param ib Map InstructionBuilder without any instructions + * @param dpidLong Long the datapath ID of a switch/node + * @param port Long representing a port on a switch/node + * @return ib InstructionBuilder Map with instructions + */ + protected static boolean removeOutputPortFromInstructions(InstructionBuilder ib, + Long dpidLong, Long port , List instructions) { + + NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port); + logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions); + + List actionList = new ArrayList(); + ActionBuilder ab = new ActionBuilder(); + + List existingActions = null; + if (instructions != null) { + for (Instruction in : instructions) { + if (in.getInstruction() instanceof ApplyActionsCase) { + existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction()); + actionList.addAll(existingActions); + break; + } + } + } + + int numOutputPort = 0; + for (Action action : actionList) { + if (action.getAction() instanceof OutputActionCase) { + numOutputPort++; + OutputActionCase opAction = (OutputActionCase)action.getAction(); + if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) { + /* Find the output port in action list and remove */ + actionList.remove(action); + numOutputPort--; + break; + } + } + } + + /* Put new action list in Apply Action instruction */ + if (numOutputPort > 0) { + ApplyActionsBuilder aab = new ApplyActionsBuilder(); + aab.setAction(actionList); + ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build()); + return false; + } else { + /* if all output port are removed. Return true to indicate flow remove */ + return true; + } + } + /** * Create Set Vlan ID Instruction * diff --git a/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java b/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java index e195f1a82..a1bac127b 100644 --- a/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java +++ b/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java @@ -199,7 +199,7 @@ public class InventoryService implements IPluginInInventoryService, InventorySer } } else if (oldRow != null) { if (inventoryListener != null) { - inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow); + inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow, null); } db.removeRow(name.getName(), uuid); } diff --git a/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/OVSDBInventoryListener.java b/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/OVSDBInventoryListener.java index 3dec8a531..e0bdc1e4c 100644 --- a/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/OVSDBInventoryListener.java +++ b/ovsdb/src/main/java/org/opendaylight/ovsdb/plugin/OVSDBInventoryListener.java @@ -17,5 +17,5 @@ public interface OVSDBInventoryListener { public void nodeRemoved(Node node); public void rowAdded(Node node, String tableName, String uuid, Table row); public void rowUpdated(Node node, String tableName, String uuid, Table old, Table row); - public void rowRemoved(Node node, String tableName, String uuid, Table row); + public void rowRemoved(Node node, String tableName, String uuid, Table row, Object context); }