Adding support for MatchAction to FlowPusher

Also, refacted MatchActionComponent to use the new API

Change-Id: I227ed178ab56e370d5c970d7d88df9408e261ff7
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java
index aa1c057..824ed4f 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowPusher.java
@@ -24,16 +24,42 @@
 import net.floodlightcontroller.core.internal.OFMessageFuture;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.core.intent.FlowEntry;
+import net.onrc.onos.core.matchaction.MatchAction;
+import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
+import net.onrc.onos.core.matchaction.MatchActionOperations.Operator;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
+import net.onrc.onos.core.matchaction.action.ModifySrcMacAction;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
 import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.IPv4Net;
+import net.onrc.onos.core.util.SwitchPort;
 
 import org.apache.commons.lang3.tuple.Pair;
+import org.projectfloodlight.openflow.protocol.OFActionType;
 import org.projectfloodlight.openflow.protocol.OFBarrierReply;
 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActions;
+import org.projectfloodlight.openflow.protocol.match.Match.Builder;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -591,6 +617,144 @@
         pushFlowEntries(entries, priority);
     }
 
+    public static final int PRIORITY_DEFAULT = 32768; // Default Flow Priority
+
+    @Override
+    public void pushMatchAction(MatchActionOperationEntry matchActionOp) {
+        final MatchAction matchAction = matchActionOp.getTarget();
+
+        // Get the switch and its OFFactory
+        final SwitchPort srcPort = matchAction.getSwitchPort();
+        final Dpid dpid = srcPort.getDpid();
+        IOFSwitch sw = floodlightProvider.getMasterSwitch(dpid.value());
+        if (sw == null) {
+            log.warn("Couldn't find switch {} when pushing message", dpid);
+            return;
+        }
+        OFFactory factory = sw.getFactory();
+
+        // Build Match
+        final Match match = matchAction.getMatch();
+        Builder matchBuilder = factory.buildMatch();
+        if (match instanceof PacketMatch) {
+            final PacketMatch packetMatch = (PacketMatch) match;
+            final MACAddress srcMac = packetMatch.getSrcMacAddress();
+            final MACAddress dstMac = packetMatch.getDstMacAddress();
+            final Short etherType = packetMatch.getEtherType();
+            final IPv4Net srcIp = packetMatch.getSrcIpAddress();
+            final IPv4Net dstIp = packetMatch.getDstIpAddress();
+            final Byte ipProto = packetMatch.getIpProtocolNumber();
+            final Short srcTcpPort = packetMatch.getSrcTcpPortNumber();
+            final Short dstTcpPort = packetMatch.getDstTcpPortNumber();
+
+            if (srcMac != null) {
+                matchBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(srcMac.toLong()));
+            }
+            if (dstMac != null) {
+                matchBuilder.setExact(MatchField.ETH_DST, MacAddress.of(dstMac.toLong()));
+            }
+            if (etherType != null) {
+                matchBuilder.setExact(MatchField.ETH_TYPE, EthType.of(etherType));
+            }
+            if (srcIp != null) {
+                matchBuilder.setMasked(MatchField.IPV4_SRC,
+                        IPv4Address.of(srcIp.address().value())
+                                .withMaskOfLength(srcIp.prefixLen()));
+            }
+            if (dstIp != null) {
+                matchBuilder.setMasked(MatchField.IPV4_DST,
+                        IPv4Address.of(dstIp.address().value())
+                                .withMaskOfLength(dstIp.prefixLen()));
+            }
+            if (ipProto != null) {
+                matchBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(ipProto));
+            }
+            if (srcTcpPort != null) {
+                matchBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(srcTcpPort));
+            }
+            if (dstTcpPort != null) {
+                matchBuilder.setExact(MatchField.TCP_DST, TransportPort.of(dstTcpPort));
+            }
+            matchBuilder.setExact(MatchField.IN_PORT,
+                    OFPort.of(srcPort.getPortNumber().shortValue()));
+        } else {
+            log.warn("Unsupported Match type: {}", match.getClass().getName());
+            return;
+        }
+
+        // Build Actions
+        List<OFAction> actionList = new ArrayList<>(matchAction.getActions().size());
+        OFActions ofActionTypes = factory.actions();
+        for (Action action : matchAction.getActions()) {
+            OFAction ofAction = null;
+            if (action instanceof OutputAction) {
+                OutputAction outputAction = (OutputAction) action;
+                // short or int?
+                OFPort port = OFPort.of((int) outputAction.getPortNumber().value());
+                ofAction = ofActionTypes.output(port, Short.MAX_VALUE);
+            } else if (action instanceof ModifyDstMacAction) {
+                ModifyDstMacAction dstMacAction = (ModifyDstMacAction) action;
+                ofActionTypes.setDlDst(MacAddress.of(dstMacAction.getDstMac().toLong()));
+            } else if (action instanceof ModifySrcMacAction) {
+                ModifySrcMacAction srcMacAction = (ModifySrcMacAction) action;
+                ofActionTypes.setDlSrc(MacAddress.of(srcMacAction.getSrcMac().toLong()));
+            } else {
+                log.warn("Unsupported Action type: {}", action.getClass().getName());
+                continue;
+            }
+            actionList.add(ofAction);
+        }
+
+        // Construct a FlowMod message builder
+        OFFlowMod.Builder fmBuilder = null;
+        switch (matchActionOp.getOperator()) {
+        case ADD:
+            fmBuilder = factory.buildFlowAdd();
+            break;
+        case REMOVE:
+            fmBuilder = factory.buildFlowDeleteStrict();
+            break;
+        // case MODIFY: // TODO
+        // fmBuilder = factory.buildFlowModifyStrict();
+        // break;
+        default:
+            log.warn("Unsupported MatchAction Operator: {}", matchActionOp.getOperator());
+            return;
+        }
+
+        // Add output port for OF1.0
+        OFPort outp = OFPort.of((short) 0xffff); // OF1.0 OFPP.NONE
+        if (matchActionOp.getOperator() == Operator.REMOVE) {
+            if (actionList.size() == 1) {
+                if (actionList.get(0).getType() == OFActionType.OUTPUT) {
+                    OFActionOutput oa = (OFActionOutput) actionList.get(0);
+                    outp = oa.getPort();
+                }
+            }
+        }
+
+
+        // Build OFFlowMod
+        fmBuilder.setMatch(matchBuilder.build())
+                .setActions(actionList)
+                .setIdleTimeout(0) // hardcoded to zero for now
+                .setHardTimeout(0) // hardcoded to zero for now
+                .setCookie(U64.of(matchAction.getId().value()))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setPriority(PRIORITY_DEFAULT)
+                .setOutPort(outp);
+
+        // Build the message and add it to the queue
+        add(dpid, fmBuilder.build());
+    }
+
+    @Override
+    public void pushMatchActions(Collection<MatchActionOperationEntry> matchActionOps) {
+        for (MatchActionOperationEntry matchActionOp : matchActionOps) {
+            pushMatchAction(matchActionOp);
+        }
+    }
+
     /**
      * Create a message from FlowEntry and add it to the queue of the switch.
      * <p>