+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPort;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.sal.utils.Status;
+
+/**
+ * Represents the openflow plugin component in charge of programming the flows
+ * on the switch. It servers the install requests coming from the SAL layer.
+ *
+ *
+ *
+ */
+public class FlowProgrammerService implements IPluginInFlowProgrammerService {
+ private IController controller;
+
+ public FlowProgrammerService() {
+ controller = null;
+ }
+
+ public void setController(IController core) {
+ this.controller = core;
+ }
+
+ public void unsetController(IController core) {
+ if (this.controller == core) {
+ this.controller = null;
+ }
+ }
+
+ /**
+ * Function called by the dependency manager when all the required
+ * dependencies are satisfied
+ *
+ */
+ void init() {
+ }
+
+ /**
+ * 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
+ *
+ */
+ 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
+ *
+ */
+ void stop() {
+ }
+
+ @Override
+ 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"));
+ }
+
+ if (controller != null) {
+ ISwitch sw = controller.getSwitch((Long) node.getID());
+ if (sw != null) {
+ FlowConverter x = new FlowConverter(flow);
+ OFMessage msg = x.getOFFlowMod(OFFlowMod.OFPFC_ADD, null);
+
+ /*
+ * Synchronous message send
+ */
+ 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"));
+ } else if (result instanceof OFError) {
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("program", action, Utils
+ .getOFErrorString((OFError) result)));
+ } else {
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("send", action, "Internal Error"));
+ }
+ } else {
+ return new Status(StatusCode.GONE, errorString("send", action,
+ "Switch is not available"));
+ }
+ }
+ 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"));
+ }
+ 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 (oldFlow.getPriority() != newFlow.getPriority()
+ || !oldFlow.getMatch().equals(newFlow.getMatch())) {
+ msg1 = new FlowConverter(oldFlow).getOFFlowMod(
+ OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
+ msg2 = new FlowConverter(newFlow).getOFFlowMod(
+ OFFlowMod.OFPFC_ADD, null);
+ } else {
+ msg1 = new FlowConverter(newFlow).getOFFlowMod(
+ OFFlowMod.OFPFC_MODIFY_STRICT, null);
+ }
+ /*
+ * Synchronous message send
+ */
+ action = (msg2 == null) ? "modify" : "delete";
+ 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"));
+ } 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)));
+ } else {
+ 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"));
+ } else if (result instanceof OFError) {
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("program", action, Utils
+ .getOFErrorString((OFError) result)));
+ } else {
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("send", action, "Internal Error"));
+ }
+ }
+ } else {
+ return new Status(StatusCode.GONE, errorString("send", action,
+ "Switch is not available"));
+ }
+ }
+ 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"));
+ }
+ if (controller != null) {
+ ISwitch sw = controller.getSwitch((Long) node.getID());
+ if (sw != null) {
+ OFMessage msg = new FlowConverter(flow).getOFFlowMod(
+ 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"));
+ } else if (result instanceof OFError) {
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("program", action, Utils
+ .getOFErrorString((OFError) result)));
+ } else {
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("send", action, "Internal Error"));
+ }
+ } else {
+ return new Status(StatusCode.GONE, errorString("send", action,
+ "Switch is not available"));
+ }
+ }
+ return new Status(StatusCode.INTERNALERROR,
+ errorString("send", action, "Internal plugin error"));
+ }
+
+ @Override
+ public Status removeAllFlows(Node node) {
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ private String errorString(String phase, String action, String cause) {
+ return "Failed to "
+ + ((phase != null) ? phase + " the " + action
+ + " flow message: " : action + " the flow: ") + cause;
+ }
+
+}