X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fprotocol_plugins%2Fopenflow%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fprotocol_plugin%2Fopenflow%2Finternal%2FFlowProgrammerService.java;h=2926c22c43f43d4c903157a4f09a1a6758c422a1;hb=refs%2Fchanges%2F12%2F212%2F2;hp=983c7c2190e09d19298f7454a093615956f91299;hpb=16a5e410667863944b3e83e9a853401ff55cebb4;p=controller.git diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java index 983c7c2190..2926c22c43 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -10,18 +9,38 @@ package org.opendaylight.controller.protocol_plugin.openflow.internal; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier; import org.opendaylight.controller.protocol_plugin.openflow.core.IController; +import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener; import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch; import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error; import org.openflow.protocol.OFError; import org.openflow.protocol.OFFlowMod; +import org.openflow.protocol.OFFlowRemoved; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPort; +import org.openflow.protocol.OFType; +import org.openflow.protocol.action.OFAction; +import org.opendaylight.controller.sal.core.ContainerFlow; +import org.opendaylight.controller.sal.core.IContainerListener; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.Node.NodeIDType; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService; +import org.opendaylight.controller.sal.match.Match; +import org.opendaylight.controller.sal.match.MatchType; +import org.opendaylight.controller.sal.utils.GlobalConstants; +import org.opendaylight.controller.sal.utils.NodeCreator; import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.controller.sal.utils.Status; import org.slf4j.Logger; @@ -29,18 +48,19 @@ import org.slf4j.LoggerFactory; /** * Represents the openflow plugin component in charge of programming the flows - * on the switch. It servers the install requests coming from the SAL layer. - * - * - * + * the flow programming and relay them to functional modules above SAL. */ -public class FlowProgrammerService implements IPluginInFlowProgrammerService { - private static final Logger log = LoggerFactory - .getLogger(FlowProgrammerService.class); +public class FlowProgrammerService implements IPluginInFlowProgrammerService, + IMessageListener, IContainerListener { + private static final Logger log = LoggerFactory + .getLogger(FlowProgrammerService.class); private IController controller; + private ConcurrentMap flowProgrammerNotifiers; + private Map> containerToNc; public FlowProgrammerService() { controller = null; + flowProgrammerNotifiers = new ConcurrentHashMap(); } public void setController(IController core) { @@ -53,37 +73,61 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { } } + public void setFlowProgrammerNotifier(Map props, + IFlowProgrammerNotifier s) { + if (props == null || props.get("containerName") == null) { + log.error("Didn't receive the service correct properties"); + return; + } + String containerName = (String) props.get("containerName"); + this.flowProgrammerNotifiers.put(containerName, s); + } + + public void unsetFlowProgrammerNotifier(Map props, + IFlowProgrammerNotifier s) { + if (props == null || props.get("containerName") == null) { + log.error("Didn't receive the service correct properties"); + return; + } + String containerName = (String) props.get("containerName"); + if (this.flowProgrammerNotifiers != null + && this.flowProgrammerNotifiers.containsKey(containerName) + && this.flowProgrammerNotifiers.get(containerName) == s) { + this.flowProgrammerNotifiers.remove(containerName); + } + } + /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ void init() { + this.controller.addMessageListener(OFType.FLOW_REMOVED, this); } /** - * Function called by the dependency manager when at least one - * dependency become unsatisfied or when the component is shutting - * down because for example bundle is being stopped. - * + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. + * */ void destroy() { } /** - * Function called by dependency manager after "init ()" is called - * and after the services provided by the class are registered in - * the service registry - * + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry + * */ void start() { } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls - * + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls + * */ void stop() { } @@ -92,8 +136,8 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { public Status addFlow(Node node, Flow flow) { String action = "add"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { - return new Status(StatusCode.NOTACCEPTABLE, - errorString("send", action, "Invalid node type")); + return new Status(StatusCode.NOTACCEPTABLE, errorString("send", + action, "Invalid node type")); } if (controller != null) { @@ -107,53 +151,52 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { */ Object result = sw.syncSend(msg); if (result instanceof Boolean) { - return ((Boolean) result == Boolean.TRUE) ? - new Status(StatusCode.SUCCESS, null) - : new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return ((Boolean) result == Boolean.TRUE) ? new Status( + StatusCode.SUCCESS, null) : new Status( + StatusCode.TIMEOUT, errorString(null, action, + "Request Timed Out")); } else if (result instanceof OFError) { - OFError res = (OFError) result; - if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) { - V6Error er = new V6Error(res); - byte[] b = res.getError(); - ByteBuffer bb = ByteBuffer.allocate(b.length); - bb.put(b); - bb.rewind(); - er.readFrom(bb); - log.trace("V6Error {}",er); - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, "Vendor Extension Internal Error")); - } - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, Utils - .getOFErrorString(res))); + OFError res = (OFError) result; + if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) { + V6Error er = new V6Error(res); + byte[] b = res.getError(); + ByteBuffer bb = ByteBuffer.allocate(b.length); + bb.put(b); + bb.rewind(); + er.readFrom(bb); + return new Status(StatusCode.INTERNALERROR, + errorString("program", action, + "Vendor Extension Internal Error")); + } + return new Status(StatusCode.INTERNALERROR, errorString( + "program", action, Utils.getOFErrorString(res))); } else { - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal Error")); + return new Status(StatusCode.INTERNALERROR, errorString( + "send", action, "Internal Error")); } } else { return new Status(StatusCode.GONE, errorString("send", action, - "Switch is not available")); + "Switch is not available")); } } - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal plugin error")); + return new Status(StatusCode.INTERNALERROR, errorString("send", action, + "Internal plugin error")); } @Override public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) { String action = "modify"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { - return new Status(StatusCode.NOTACCEPTABLE, - errorString("send", action, "Invalid node type")); + return new Status(StatusCode.NOTACCEPTABLE, errorString("send", + action, "Invalid node type")); } if (controller != null) { ISwitch sw = controller.getSwitch((Long) node.getID()); if (sw != null) { OFMessage msg1 = null, msg2 = null; - // If priority and match portion are the same, send a modification message + // If priority and match portion are the same, send a + // modification message if (oldFlow.getPriority() != newFlow.getPriority() || !oldFlow.getMatch().equals(newFlow.getMatch())) { msg1 = new FlowConverter(oldFlow).getOFFlowMod( @@ -171,34 +214,32 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { Object result = sw.syncSend(msg1); if (result instanceof Boolean) { if ((Boolean) result == Boolean.FALSE) { - return new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return new Status(StatusCode.TIMEOUT, errorString(null, + action, "Request Timed Out")); } else if (msg2 == null) { return new Status(StatusCode.SUCCESS, null); } } else if (result instanceof OFError) { - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, Utils - .getOFErrorString((OFError) result))); + return new Status(StatusCode.INTERNALERROR, errorString( + "program", action, + Utils.getOFErrorString((OFError) result))); } else { - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal Error")); + return new Status(StatusCode.INTERNALERROR, errorString( + "send", action, "Internal Error")); } if (msg2 != null) { action = "add"; result = sw.syncSend(msg2); if (result instanceof Boolean) { - return ((Boolean) result == Boolean.TRUE) ? - new Status(StatusCode.SUCCESS, null) - : new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return ((Boolean) result == Boolean.TRUE) ? new Status( + StatusCode.SUCCESS, null) : new Status( + StatusCode.TIMEOUT, errorString(null, action, + "Request Timed Out")); } else if (result instanceof OFError) { return new Status(StatusCode.INTERNALERROR, errorString("program", action, Utils - .getOFErrorString((OFError) result))); + .getOFErrorString((OFError) result))); } else { return new Status(StatusCode.INTERNALERROR, errorString("send", action, "Internal Error")); @@ -209,16 +250,16 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { "Switch is not available")); } } - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal plugin error")); + return new Status(StatusCode.INTERNALERROR, errorString("send", action, + "Internal plugin error")); } @Override public Status removeFlow(Node node, Flow flow) { String action = "remove"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { - return new Status(StatusCode.NOTACCEPTABLE, - errorString("send", action, "Invalid node type")); + return new Status(StatusCode.NOTACCEPTABLE, errorString("send", + action, "Invalid node type")); } if (controller != null) { ISwitch sw = controller.getSwitch((Long) node.getID()); @@ -227,26 +268,25 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE); Object result = sw.syncSend(msg); if (result instanceof Boolean) { - return ((Boolean) result == Boolean.TRUE) ? - new Status(StatusCode.SUCCESS, null) - : new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return ((Boolean) result == Boolean.TRUE) ? new Status( + StatusCode.SUCCESS, null) : new Status( + StatusCode.TIMEOUT, errorString(null, action, + "Request Timed Out")); } else if (result instanceof OFError) { - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, Utils - .getOFErrorString((OFError) result))); + return new Status(StatusCode.INTERNALERROR, errorString( + "program", action, + Utils.getOFErrorString((OFError) result))); } else { - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal Error")); + return new Status(StatusCode.INTERNALERROR, errorString( + "send", action, "Internal Error")); } } else { - return new Status(StatusCode.GONE, errorString("send", action, + return new Status(StatusCode.GONE, errorString("send", action, "Switch is not available")); } } - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal plugin error")); + return new Status(StatusCode.INTERNALERROR, errorString("send", action, + "Internal plugin error")); } @Override @@ -260,4 +300,82 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { + " flow message: " : action + " the flow: ") + cause; } + @Override + public void receive(ISwitch sw, OFMessage msg) { + if (msg instanceof OFFlowRemoved) { + handleFlowRemovedMessage(sw, (OFFlowRemoved) msg); + } + } + + private void handleFlowRemovedMessage(ISwitch sw, OFFlowRemoved msg) { + Node node = NodeCreator.createOFNode(sw.getId()); + Flow flow = new FlowConverter(msg.getMatch(), + new ArrayList(0)).getFlow(node); + flow.setPriority(msg.getPriority()); + flow.setIdleTimeout(msg.getIdleTimeout()); + flow.setId(msg.getCookie()); + + Match match = flow.getMatch(); + NodeConnector inPort = match.isPresent(MatchType.IN_PORT) ? (NodeConnector) match + .getField(MatchType.IN_PORT).getValue() : null; + + for (Map.Entry containerNotifier : flowProgrammerNotifiers + .entrySet()) { + String container = containerNotifier.getKey(); + IFlowProgrammerNotifier notifier = containerNotifier.getValue(); + /* + * Switch only provide us with the match information. For now let's + * try to identify the container membership only from the input port + * match field. In any case, upper layer consumers can derive + * whether the notification was not for them. More sophisticated + * filtering can be added later on. + */ + if (inPort == null + || container.equals(GlobalConstants.DEFAULT.toString()) + || this.containerToNc.get(container).contains(inPort)) { + notifier.flowRemoved(node, flow); + } + } + } + + @Override + public void tagUpdated(String containerName, Node n, short oldTag, + short newTag, UpdateType t) { + + } + + @Override + public void containerFlowUpdated(String containerName, + ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) { + } + + @Override + public void nodeConnectorUpdated(String containerName, NodeConnector p, + UpdateType type) { + Set target = null; + + switch (type) { + case ADDED: + if (!containerToNc.containsKey(containerName)) { + containerToNc.put(containerName, new HashSet()); + } + containerToNc.get(containerName).add(p); + break; + case CHANGED: + break; + case REMOVED: + target = containerToNc.get(containerName); + if (target != null) { + target.remove(p); + } + break; + default: + } + + } + + @Override + public void containerModeUpdated(UpdateType t) { + + } }