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=e2fa8d5f1e4f89e0980da755c340d4585a78c379;hb=cbdf09d099f297db7712c3dd4637475c88f92113;hp=0dd0ca736b8962335272bc540532be1dbc1f7f0e;hpb=184e4f61d034f6c83da75de288d4f56ec48f60bf;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 0dd0ca736b..e2fa8d5f1e 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 @@ -23,7 +23,9 @@ import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExtern 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.sal.connection.IPluginOutConnectionService; import org.opendaylight.controller.sal.core.ContainerFlow; +import org.opendaylight.controller.sal.core.IContainerAware; import org.opendaylight.controller.sal.core.IContainerListener; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.Node.NodeIDType; @@ -34,6 +36,7 @@ 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.EtherTypes; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.HexEncode; import org.opendaylight.controller.sal.utils.NodeCreator; @@ -57,7 +60,7 @@ import org.slf4j.LoggerFactory; */ public class FlowProgrammerService implements IPluginInFlowProgrammerService, IMessageListener, IContainerListener, IInventoryShimExternalListener, - CommandProvider { + CommandProvider, IContainerAware { private static final Logger log = LoggerFactory .getLogger(FlowProgrammerService.class); private IController controller; @@ -65,6 +68,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, private Map> containerToNc; private ConcurrentMap> xid2rid; private int barrierMessagePriorCount = getBarrierMessagePriorCount(); + private IPluginOutConnectionService connectionOutService; public FlowProgrammerService() { controller = null; @@ -83,6 +87,16 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, } } + void setIPluginOutConnectionService(IPluginOutConnectionService s) { + connectionOutService = s; + } + + void unsetIPluginOutConnectionService(IPluginOutConnectionService s) { + if (connectionOutService == s) { + connectionOutService = null; + } + } + public void setFlowProgrammerNotifier(Map props, IFlowProgrammerNotifier s) { if (props == null || props.get("containerName") == null) { @@ -110,7 +124,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ void init() { this.controller.addMessageListener(OFType.FLOW_REMOVED, this); @@ -122,7 +136,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, * 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() { } @@ -130,7 +144,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, /** * 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() { } @@ -139,39 +153,69 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, * 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) { + if (!connectionOutService.isLocal(node)) { + log.debug("Add flow will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + return addFlowInternal(node, flow, 0); } @Override public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) { + if (!connectionOutService.isLocal(node)) { + log.debug("Modify flow will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + return modifyFlowInternal(node, oldFlow, newFlow, 0); } @Override public Status removeFlow(Node node, Flow flow) { + if (!connectionOutService.isLocal(node)) { + log.debug("Remove flow will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + return removeFlowInternal(node, flow, 0); } @Override public Status addFlowAsync(Node node, Flow flow, long rid) { + if (!connectionOutService.isLocal(node)) { + log.debug("Add flow Async will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + return addFlowInternal(node, flow, rid); } @Override public Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) { + if (!connectionOutService.isLocal(node)) { + log.debug("Modify flow async will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + return modifyFlowInternal(node, oldFlow, newFlow, rid); } @Override public Status removeFlowAsync(Node node, Flow flow, long rid) { + if (!connectionOutService.isLocal(node)) { + log.debug("Remove flow async will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + return removeFlowInternal(node, flow, rid); } @@ -182,6 +226,11 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, action, "Invalid node type")); } + Status status = validateFlow(flow); + if (!status.isSuccess()) { + return status; + } + if (controller != null) { ISwitch sw = controller.getSwitch((Long) node.getID()); if (sw != null) { @@ -201,7 +250,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, * will be inserted automatically to synchronize the * progression. */ - result = asyncMsgSend(node, sw, msg, rid); + result = asyncMsgSend(node, sw, msg, rid); } return getStatusInternal(result, action, rid); } else { @@ -213,12 +262,52 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, "Internal plugin error")); } + /* + * Method which runs openflow 1.0 specific validation on the requested flow + * This validation is needed because the openflow switch will silently accept + * the request and install only the applicable match fields + */ + private Status validateFlow(Flow flow) { + Match m = flow.getMatch(); + boolean isIPEthertypeSet = m.isPresent(MatchType.DL_TYPE) + && (m.getField(MatchType.DL_TYPE).getValue().equals(EtherTypes.IPv4.shortValue()) || m + .getField(MatchType.DL_TYPE).getValue().equals(EtherTypes.IPv6.shortValue())); + + // network address check + if ((m.isPresent(MatchType.NW_SRC) || m.isPresent(MatchType.NW_DST)) && !isIPEthertypeSet) { + return new Status(StatusCode.NOTACCEPTABLE, + "The match on network source or destination address cannot be accepted if the match " + + "on proper ethertype is missing"); + } + + // transport protocol check + if (m.isPresent(MatchType.NW_PROTO) && !isIPEthertypeSet) { + return new Status(StatusCode.NOTACCEPTABLE, + "The match on network protocol cannot be accepted if the match on proper ethertype is missing"); + } + + // transport ports check + if ((m.isPresent(MatchType.TP_SRC) || m.isPresent(MatchType.TP_DST)) + && (!isIPEthertypeSet || m.isAny(MatchType.NW_PROTO))) { + return new Status( + StatusCode.NOTACCEPTABLE, + "The match on transport source or destination port cannot be accepted if the match on network protocol and match on IP ethertype are missing"); + } + return new Status(StatusCode.SUCCESS); + } + private Status modifyFlowInternal(Node node, Flow oldFlow, Flow newFlow, long rid) { String action = "modify"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { return new Status(StatusCode.NOTACCEPTABLE, errorString("send", action, "Invalid node type")); } + + Status status = validateFlow(newFlow); + if (!status.isSuccess()) { + return status; + } + if (controller != null) { ISwitch sw = controller.getSwitch((Long) node.getID()); if (sw != null) { @@ -324,7 +413,12 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, @Override public Status removeAllFlows(Node node) { - return new Status(StatusCode.SUCCESS, null); + if (!connectionOutService.isLocal(node)) { + log.debug("Remove all flows will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + + return new Status(StatusCode.SUCCESS); } private String errorString(String phase, String action, String cause) { @@ -367,7 +461,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, */ if (inPort == null || container.equals(GlobalConstants.DEFAULT.toString()) - || this.containerToNc.get(container).contains(inPort)) { + || (containerToNc.containsKey(container) && containerToNc.get(container).contains(inPort))) { notifier.flowRemoved(node, flow); } } @@ -392,7 +486,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, if ((rid == null) || (rid == 0)) { return; } - + /* * Notifies the caller that error has been reported for a previous flow * programming request @@ -400,7 +494,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, for (Map.Entry containerNotifier : flowProgrammerNotifiers .entrySet()) { IFlowProgrammerNotifier notifier = containerNotifier.getValue(); - notifier.flowErrorReported(node, rid, errorMsg); + notifier.flowErrorReported(node, rid, Utils.getOFErrorString(errorMsg)); } } @@ -418,8 +512,6 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, @Override public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType type) { - Set target = null; - switch (type) { case ADDED: if (!containerToNc.containsKey(containerName)) { @@ -430,7 +522,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, case CHANGED: break; case REMOVED: - target = containerToNc.get(containerName); + Set target = containerToNc.get(containerName); if (target != null) { target.remove(p); } @@ -445,7 +537,12 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, } @Override - public Status sendBarrierMessage(Node node) { + public Status syncSendBarrierMessage(Node node) { + if (!connectionOutService.isLocal(node)) { + log.debug("Sync Send Barrier will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + if (!node.getType().equals(NodeIDType.OPENFLOW)) { return new Status(StatusCode.NOTACCEPTABLE, "The node does not support Barrier message."); @@ -455,9 +552,9 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, long swid = (Long) node.getID(); ISwitch sw = controller.getSwitch(swid); if (sw != null) { - sw.sendBarrierMessage(); + sw.syncSendBarrierMessage(); clearXid2Rid(swid); - return (new Status(StatusCode.SUCCESS, null)); + return (new Status(StatusCode.SUCCESS)); } else { return new Status(StatusCode.GONE, "The node does not have a valid Switch reference."); @@ -466,14 +563,42 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, return new Status(StatusCode.INTERNALERROR, "Failed to send Barrier message."); } - + + @Override + public Status asyncSendBarrierMessage(Node node) { + if (!connectionOutService.isLocal(node)) { + log.debug("ASync Send Barrier will not be processed in a non-master controller for node " + node); + return new Status(StatusCode.NOTALLOWED, "This is not the master controller for " + node); + } + + if (!node.getType().equals(NodeIDType.OPENFLOW)) { + return new Status(StatusCode.NOTACCEPTABLE, + "The node does not support Barrier message."); + } + + if (controller != null) { + long swid = (Long) node.getID(); + ISwitch sw = controller.getSwitch(swid); + if (sw != null) { + sw.asyncSendBarrierMessage(); + clearXid2Rid(swid); + return (new Status(StatusCode.SUCCESS)); + } else { + return new Status(StatusCode.GONE, + "The node does not have a valid Switch reference."); + } + } + return new Status(StatusCode.INTERNALERROR, + "Failed to send Barrier message."); + } + /** * This method sends the message asynchronously until the number of messages * sent reaches a threshold. Then a Barrier message is sent automatically * for sync purpose. An unique Request ID associated with the message is * passed down by the caller. The Request ID will be returned to the caller * when an error message is received from the switch. - * + * * @param node * The node * @param msg @@ -491,25 +616,25 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, xid = sw.asyncSend(msg); addXid2Rid(swid, xid, rid); - + Map swxid2rid = this.xid2rid.get(swid); if (swxid2rid == null) { return result; } - + int size = swxid2rid.size(); if (size % barrierMessagePriorCount == 0) { - result = sendBarrierMessage(node); + result = asyncSendBarrierMessage(node); } - + return result; } - + /** * A number of async messages are sent followed by a synchronous Barrier * message. This method returns the maximum async messages that can be sent * before the Barrier message. - * + * * @return The max count of async messages sent prior to Barrier message */ private int getBarrierMessagePriorCount() { @@ -525,11 +650,11 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, return rv; } - + /** * This method returns the message Request ID previously assigned by the * caller for a given OF message xid - * + * * @param swid * The switch id * @param xid @@ -553,14 +678,14 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, /** * This method returns a copy of outstanding xid to rid mappings.for a given * switch - * + * * @param swid * The switch id * @return a copy of xid2rid mappings */ public Map getSwXid2Rid(long swid) { Map swxid2rid = this.xid2rid.get(swid); - + if (swxid2rid != null) { return new HashMap(swxid2rid); } else { @@ -570,7 +695,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, /** * Adds xid to rid mapping to the local DB - * + * * @param swid * The switch id * @param xid @@ -588,7 +713,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, /** * When an Error message is received, this method will be invoked to remove * the offending xid from the local DB. - * + * * @param swid * The switch id * @param xid @@ -603,7 +728,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, /** * Convert various result into Status - * + * * @param result * The returned result from previous action * @param action @@ -629,11 +754,11 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, "send", action, "Internal Error")); } } - + /** * When a Barrier reply is received, this method will be invoked to clear * the local DB - * + * * @param swid * The switch id */ @@ -647,7 +772,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, @Override public void updateNode(Node node, UpdateType type, Set props) { long swid = (Long)node.getID(); - + switch (type) { case ADDED: Map swxid2rid = new HashMap(); @@ -689,7 +814,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, ci.println("Please enter a valid node id"); return; } - + long sid; try { sid = HexEncode.stringToLong(st); @@ -697,7 +822,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, ci.println("Please enter a valid node id"); return; } - + Map swxid2rid = this.xid2rid.get(sid); if (swxid2rid == null) { ci.println("The node id entered does not exist"); @@ -705,7 +830,7 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, } ci.println("xid rid"); - + Set xidSet = swxid2rid.keySet(); if (xidSet == null) { return; @@ -720,4 +845,14 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService, ci.println("Max num of async messages sent prior to the Barrier message is " + barrierMessagePriorCount); } + + @Override + public void containerCreate(String containerName) { + // do nothing + } + + @Override + public void containerDestroy(String containerName) { + containerToNc.remove(containerName); + } }