Performacne improvements via adding a netty-based openflowj and openflow plugin;...
[controller.git] / opendaylight / protocol_plugins / openflow_netty / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / internal / ReadServiceFilter.java
diff --git a/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java b/opendaylight/protocol_plugins/openflow_netty/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/ReadServiceFilter.java
new file mode 100644 (file)
index 0000000..73c703e
--- /dev/null
@@ -0,0 +1,421 @@
+
+/*
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
+import org.opendaylight.controller.protocol_plugin.openflow.IPluginReadServiceFilter;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.statistics.OFPortStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.ActionType;
+import org.opendaylight.controller.sal.action.Output;
+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.NodeConnector;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+
+/**
+ * Read Service shim layer which is in charge of filtering the flow statistics
+ * based on container. It is a Global instance.
+ *
+ *
+ *
+ */
+public class ReadServiceFilter implements IPluginReadServiceFilter,
+        IContainerListener {
+    private static final Logger logger = LoggerFactory
+            .getLogger(ReadServiceFilter.class);
+    private IController controller = null;
+    private IOFStatisticsManager statsMgr = null;
+    private Map<String, Set<NodeConnector>> containerToNc;
+
+    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() {
+        containerToNc = new HashMap<String, Set<NodeConnector>>();
+    }
+
+    /**
+     * 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() {
+    }
+
+    public void setService(IOFStatisticsManager service) {
+        this.statsMgr = service;
+    }
+
+    public void unsetService(IOFStatisticsManager service) {
+        this.statsMgr = null;
+    }
+
+    @Override
+    public FlowOnNode readFlow(String container, Node node, Flow flow,
+            boolean cached) {
+
+        if (controller == null) {
+            // Avoid to provide cached statistics if controller went down.
+            // They are not valid anymore anyway
+            logger.error("Internal plugin error");
+            return null;
+        }
+
+        long sid = (Long) node.getID();
+        OFMatch ofMatch = new FlowConverter(flow).getOFMatch();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFFlowStatistics(sid, ofMatch) : statsMgr.queryStatistics(
+                sid, OFStatisticsType.FLOW, ofMatch);
+
+        /*
+         * Convert and filter the statistics per container
+         */
+        List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
+                .getFlowOnNodeList(node);
+        List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
+                node, flowOnNodeList);
+
+        return (filteredList == null || filteredList.isEmpty()) ? null
+                : filteredList.get(0);
+    }
+
+    @Override
+    public List<FlowOnNode> readAllFlow(String container, Node node,
+            boolean cached) {
+
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFFlowStatistics(sid) : statsMgr.queryStatistics(sid,
+                OFStatisticsType.FLOW, null);
+
+        /*
+         * Convert and filter the statistics per container
+         */
+        List<FlowOnNode> flowOnNodeList = new FlowStatisticsConverter(ofList)
+                .getFlowOnNodeList(node);
+        List<FlowOnNode> filteredList = filterFlowListPerContainer(container,
+                node, flowOnNodeList);
+
+        return (filteredList == null) ? null : filteredList;
+
+    }
+
+    @Override
+    public NodeDescription readDescription(Node node, boolean cached) {
+
+        if (controller == null) {
+            logger.error("Internal plugin error");
+            return null;
+        }
+
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFDescStatistics(sid) : statsMgr.queryStatistics(sid,
+                OFStatisticsType.DESC, null);
+
+        return new DescStatisticsConverter(ofList).getHwDescription();
+    }
+
+    /**
+     * Filters a list of FlowOnNode elements based on the container
+     *
+     * @param container
+     * @param nodeId
+     * @param list
+     * @return
+     */
+    public List<FlowOnNode> filterFlowListPerContainer(String container,
+            Node nodeId, List<FlowOnNode> list) {
+        if (list == null) {
+            return null;
+        }
+
+        // Create new filtered list of flows
+        List<FlowOnNode> newList = new ArrayList<FlowOnNode>();
+
+        for (FlowOnNode target : list) {
+            // Check whether the described flow (match + actions) belongs to this container
+            if (flowBelongToContainer(container, nodeId, target.getFlow())) {
+                newList.add(target);
+            }
+        }
+
+        return newList;
+    }
+
+    /**
+     * Filters a list of FlowOnNode elements based on the container
+     *
+     * @param container
+     * @param nodeId
+     * @param list
+     * @return
+     */
+    public List<OFStatistics> filterPortListPerContainer(String container,
+            long switchId, List<OFStatistics> list) {
+        if (list == null) {
+            return null;
+        }
+
+        // Create new filtered list of flows
+        List<OFStatistics> newList = new ArrayList<OFStatistics>();
+
+        for (OFStatistics stat : list) {
+            OFPortStatisticsReply target = (OFPortStatisticsReply) stat;
+            NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(
+                    target.getPortNumber(), NodeCreator.createOFNode(switchId));
+            if (containerOwnsNodeConnector(container, nc)) {
+                newList.add(target);
+            }
+        }
+
+        return newList;
+    }
+
+    /**
+     * Returns whether the specified flow (flow match + actions)
+     * belongs to the container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @return true if it belongs
+     */
+    public boolean flowBelongToContainer(String container, Node node, Flow flow) {
+        // All flows belong to the default container
+        if (container.equals(GlobalConstants.DEFAULT.toString())) {
+            return true;
+        }
+        return (flowPortsBelongToContainer(container, node, flow)
+                && flowVlanBelongsToContainer(container, node, flow) && flowSpecAllowsFlow(
+                container, flow.getMatch()));
+    }
+
+    /**
+     * Returns whether the passed NodeConnector belongs to the container
+     *
+     * @param container    container name
+     * @param p        node connector to test
+     * @return         true if belongs false otherwise
+     */
+    public boolean containerOwnsNodeConnector(String container, NodeConnector p) {
+        // All node connectors belong to the default container
+        if (container.equals(GlobalConstants.DEFAULT.toString())) {
+            return true;
+        }
+        Set<NodeConnector> portSet = containerToNc.get(container);
+        return (portSet == null) ? false : portSet.contains(p);
+    }
+
+    /**
+     * Returns whether the container flowspec allows the passed flow
+     *
+     * @param container
+     * @param match
+     * @return
+     */
+    private boolean flowSpecAllowsFlow(String container, Match match) {
+        return true; // Always true for now
+    }
+
+    /**
+     * Check whether the vlan field in the flow match is the same
+     * of the static vlan configured for the container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @return
+     */
+    private boolean flowVlanBelongsToContainer(String container, Node node,
+            Flow flow) {
+        return true; // Always true for now
+    }
+
+    /**
+     * Check whether the ports in the flow match and flow actions for
+     * the specified node belong to the container
+     *
+     * @param container
+     * @param node
+     * @param flow
+     * @return
+     */
+    private boolean flowPortsBelongToContainer(String container, Node node,
+            Flow flow) {
+        Match m = flow.getMatch();
+        if (m.isPresent(MatchType.IN_PORT)) {
+            NodeConnector inPort = (NodeConnector) m
+                    .getField(MatchType.IN_PORT).getValue();
+
+            // If the incoming port is specified, check if it belongs to
+            if (!containerOwnsNodeConnector(container, inPort)) {
+                return false;
+            }
+        }
+
+        // If an outgoing port is specified, it must belong to this container
+        for (Action action : flow.getActions()) {
+            if (action.getType() == ActionType.OUTPUT) {
+                NodeConnector outPort = (NodeConnector) ((Output) action)
+                        .getPort();
+                if (!containerOwnsNodeConnector(container, outPort)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @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 tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+        // Not interested in this event
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+        // do nothing
+    }
+
+    @Override
+    public NodeConnectorStatistics readNodeConnector(String containerName,
+            NodeConnector connector, boolean cached) {
+        if (!containerOwnsNodeConnector(containerName, connector)) {
+            return null;
+        }
+        Node node = connector.getNode();
+        long sid = (Long) node.getID();
+        short portId = (Short) connector.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFPortStatistics(sid, portId) : statsMgr.queryStatistics(
+                sid, OFStatisticsType.PORT, portId);
+
+        List<NodeConnectorStatistics> ncStatistics = new PortStatisticsConverter(
+                sid, ofList).getNodeConnectorStatsList();
+        return (ncStatistics.isEmpty()) ? new NodeConnectorStatistics()
+                : ncStatistics.get(0);
+    }
+
+    @Override
+    public List<NodeConnectorStatistics> readAllNodeConnector(
+            String containerName, Node node, boolean cached) {
+
+        long sid = (Long) node.getID();
+        List<OFStatistics> ofList = (cached == true) ? statsMgr
+                .getOFPortStatistics(sid) : statsMgr.queryStatistics(sid,
+                OFStatisticsType.FLOW, null);
+
+        List<OFStatistics> filteredList = filterPortListPerContainer(
+                containerName, sid, ofList);
+
+        return new PortStatisticsConverter(sid, filteredList)
+                .getNodeConnectorStatsList();
+    }
+
+    @Override
+    public long getTransmitRate(String containerName, NodeConnector connector) {
+        if (!containerOwnsNodeConnector(containerName, connector)) {
+            return 0;
+        }
+
+        long switchId = (Long) connector.getNode().getID();
+        short port = (Short) connector.getID();
+
+        return statsMgr.getTransmitRate(switchId, port);
+    }
+
+}