-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
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;
/**
* 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<String, IFlowProgrammerNotifier> flowProgrammerNotifiers;
+ private Map<String, Set<NodeConnector>> containerToNc;
public FlowProgrammerService() {
controller = null;
+ flowProgrammerNotifiers = new ConcurrentHashMap<String, IFlowProgrammerNotifier>();
}
public void setController(IController core) {
}
}
+ public void setFlowProgrammerNotifier(Map<String, ?> 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<String, ?> 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() {
}
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) {
*/
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(
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"));
"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());
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
+ " 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<OFAction>(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<String, IFlowProgrammerNotifier> 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<NodeConnector> target = null;
+
+ switch (type) {
+ case ADDED:
+ if (!containerToNc.containsKey(containerName)) {
+ containerToNc.put(containerName, new HashSet<NodeConnector>());
+ }
+ 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) {
+
+ }
}