- Fix minor issues in ICMP handler
 - Now use the flushFlow function to populate the tables

Change-Id: If4468aeadcc9b801f2f2c1f451b29ea8f4a1852b
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
index 0784144..b0b8cb3 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
@@ -104,6 +104,12 @@
      */
     public void addRouteToHost(Switch sw, int destinationAddress, byte[] destinationMacAddress) {
 
+        // If we do not know the host, then we cannot set the forwarding rule
+        net.onrc.onos.core.topology.Host host = mutableTopology.getHostByMac(MACAddress.valueOf(destinationMacAddress));
+        if (host == null) {
+            return;
+        }
+
         IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
         OFFactory factory = ofSwitch.getFactory();
 
@@ -158,13 +164,10 @@
         */
 
         // Set output port
-        net.onrc.onos.core.topology.Host host = mutableTopology.getHostByMac(MACAddress.valueOf(destinationMacAddress));
-        if (host != null) {
-            for (Port port: host.getAttachmentPoints()) {
-                OFAction out = factory.actions().buildOutput()
-                                .setPort(OFPort.of(port.getPortNumber().shortValue())).build();
-                actionList.add(out);
-            }
+        for (Port port: host.getAttachmentPoints()) {
+            OFAction out = factory.actions().buildOutput()
+                    .setPort(OFPort.of(port.getPortNumber().shortValue())).build();
+            actionList.add(out);
         }
 
         OFInstruction writeInstr = factory.instructions().buildWriteActions()
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
index 2f5576a..21b197b 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
@@ -235,10 +235,12 @@
                 }
             }
 
-            // If the destination host is not attached in the switch, add MPLS label
-            if (!sameSubnet) {
-
-                IPv4Address targetAddress = IPv4Address.of(((IPv4)packet.getPayload()).getDestinationAddress());
+            IPv4Address targetAddress = IPv4Address.of(((IPv4)packet.getPayload()).getDestinationAddress());
+            String destMacAddress = packet.getDestinationMAC().toString();
+            // If the destination host is not attached in the switch
+            // and the destination is not the neighbor switch, then add MPLS label
+            String targetMac = getRouterMACFromConfig(targetAddress);
+            if (!sameSubnet && !targetMac.equals(destMacAddress)) {
                 int mplsLabel = getMplsLabelFromConfig(targetAddress);
                 if (mplsLabel > 0) {
                     OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
@@ -308,6 +310,35 @@
     }
 
 
+    /**
+     * Get Router MAC Address for the target address from the network config file
+     *
+     * @param targetAddress - IP address of the target host
+     * @return Router MAC of the switch to send packets to the target address
+     */
+    private String getRouterMACFromConfig(IPv4Address targetAddress) {
+
+        String routerMac = null;
+
+        for (Switch sw: mutableTopology.getSwitches()) {
+
+            String subnets = sw.getStringAttribute("subnets");
+            try {
+                JSONArray arry = new JSONArray(subnets);
+                for (int i = 0; i < arry.length(); i++) {
+                    String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
+                    if (srManager.netMatch(subnetIp, targetAddress.toString())) {
+                             routerMac = sw.getStringAttribute("routerMac");
+                    }
+                }
+            } catch (JSONException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+
+        return routerMac;
+    }
 
     /**
      * Add a new rule to VLAN table to forward packets from any port to the next table
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
index 5053163..3d0ad7d 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/SegmentRoutingManager.java
@@ -1,5 +1,6 @@
 package net.onrc.onos.apps.segmentrouting;
 
+import java.io.IOException;
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -13,7 +14,11 @@
 import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOF13Switch;
 import net.floodlightcontroller.core.IOF13Switch.NeighborSet;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
+import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -54,6 +59,7 @@
 
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.types.EthType;
 import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.util.HexString;
@@ -61,7 +67,7 @@
 import org.slf4j.LoggerFactory;
 
 public class SegmentRoutingManager implements IFloodlightModule,
-						ITopologyListener, IPacketListener {
+						ITopologyListener, IPacketListener, IOFSwitchListener {
 
     private static final Logger log = LoggerFactory
             .getLogger(SegmentRoutingManager.class);
@@ -76,6 +82,8 @@
     private boolean networkConverged;
     private IThreadPoolService threadPool;
     private SingletonTask discoveryTask;
+    private IFloodlightProviderService floodlightProvider;
+    private IOFSwitch masterSwitch;
 
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleServices() {
@@ -106,7 +114,7 @@
 
     @Override
     public void init(FloodlightModuleContext context) throws FloodlightModuleException {
-
+        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
         arpHandler = new ArpHandler(context, this);
         icmpHandler = new IcmpHandler(context, this);
         ipHandler = new GenericIpHandler(context, this);
@@ -118,11 +126,13 @@
 
         this.packetService = context.getServiceImpl(IPacketService.class);
         packetService.registerPacketListener(this);
+
     }
 
     @Override
     public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
         networkConverged = false;
+        floodlightProvider.addOFSwitchListener(this);
 
         ScheduledExecutorService ses = threadPool.getScheduledExecutor();
 
@@ -133,7 +143,7 @@
             }
         });
 
-        discoveryTask.reschedule(10, TimeUnit.SECONDS);
+        discoveryTask.reschedule(15, TimeUnit.SECONDS);
     }
 
     @Override
@@ -141,7 +151,8 @@
     	if (payload.getEtherType() == Ethernet.TYPE_ARP)
     		arpHandler.processPacketIn(sw, inPort, payload);
         if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
-        	if (((IPv4)payload.getPayload()).getProtocol() != IPv4.PROTOCOL_ICMP)
+            int protocol = ((IPv4)payload.getPayload()).getProtocol();
+        	if (((IPv4)payload.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP)
         		icmpHandler.processPacketIn(sw, inPort, payload);
         	else
         		ipHandler.processPacketIn(sw, inPort, payload);
@@ -359,7 +370,7 @@
             fwdToSw.add(destSw);
         }
 
-        // if it is an edge router, then set IP table
+        // if both target SW and dest SW are an edge router, then set IP table
         if (IsEdgeRouter(targetSw.getDpid().toString()) &&
                 IsEdgeRouter(destSw)) {
             // We assume that there is at least one transit router b/w edge routers
@@ -380,7 +391,7 @@
             String routerIp = destSwitch.getStringAttribute("routerIp");
             setIpTableRouter(targetSw, routerIp, getMplsLabel(destSw), fwdToSw);
         }
-        // if the target switch is the edge router, then set the IP rule to router IPs
+        // Only if the target switch is the edge router, then set the IP rules
         else if (IsEdgeRouter(targetSw.getDpid().toString())) {
             // We assume that there is at least one transit router b/w edge routers
             Switch destSwitch = mutableTopology.getSwitch(new Dpid(destSw));
@@ -437,14 +448,8 @@
         List<Action> actions = new ArrayList<>();
 
         // If destination SW is the same as the fwd SW, then do not push MPLS label
-        if (fwdToSws.size() == 1) {
-            String fwdToSw = fwdToSws.get(0);
-            if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
-                DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
-                actions.add(decTtlAction);
-            }
-        }
-        else {
+
+        if (fwdToSws.size() > 1) {
             PushMplsAction pushMplsAction = new PushMplsAction();
             SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
             CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
@@ -453,6 +458,22 @@
             actions.add(setIdAction);
             actions.add(copyTtlOutAction);
         }
+        else {
+            String fwdToSw = fwdToSws.get(0);
+            if (getMplsLabel(fwdToSw).equals(mplsLabel)) {
+                DecNwTtlAction decTtlAction = new DecNwTtlAction(1);
+                actions.add(decTtlAction);
+            }
+            else {
+                PushMplsAction pushMplsAction = new PushMplsAction();
+                SetMplsIdAction setIdAction = new SetMplsIdAction(Integer.parseInt(mplsLabel));
+                CopyTtlOutAction copyTtlOutAction = new CopyTtlOutAction();
+
+                actions.add(pushMplsAction);
+                actions.add(setIdAction);
+                actions.add(copyTtlOutAction);
+            }
+        }
 
         GroupAction groupAction = new GroupAction();
 
@@ -470,11 +491,38 @@
                     net.onrc.onos.core.matchaction.MatchActionOperations.Operator.ADD,
                     matchAction);
 
-        printMatchActionOperationEntry(sw, maEntry);
+
+       // IOF13Switch sw13 = (IOF13Switch)masterSwitch;
+        IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
+                getSwId(sw.getDpid().toString()));
+
+        try {
+            printMatchActionOperationEntry(sw, maEntry);
+            sw13.pushFlow(maEntry);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+
+        sw13.flush();
+
+        //printMatchActionOperationEntry(sw, maEntry);
 
     }
 
 
+    private long getSwId(String dpid) {
+
+        long swId = 0;
+
+        String swIdStr = dpid.substring(dpid.lastIndexOf(":")+1);
+        if (swIdStr != null)
+            swId = Integer.parseInt(swIdStr);
+
+        return swId;
+    }
+
     /**
      * Set MPLS forwarding rules to MPLS table
      *   - If the destination is the same as the next hop to forward packets
@@ -490,22 +538,25 @@
         MplsMatch mplsMatch = new MplsMatch(Integer.parseInt(mplsLabel));
 
         List<Action> actions = new ArrayList<Action>();
-        // Either when packet is forwarded to edge router or the dest is the router
 
-        if (fwdSws.size() == 1) {
-            String fwdSw = fwdSws.get(0);
-            if (mplsLabel.equals(getMplsLabel(fwdSw))) {
-                PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
-                CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
-
-                actions.add(popAction);
-                actions.add(copyTtlInAction);
-            }
-        }
-        else {
+        if (fwdSws.size() > 1) {
             DecMplsTtlAction decMplsTtlAction = new DecMplsTtlAction(1);
             actions.add(decMplsTtlAction);
         }
+        // If the destination is the same as the next hop, then pop MPLS
+        else {
+            String fwdMplsId = getMplsLabel(fwdSws.get(0));
+            if (fwdMplsId.equals(mplsLabel)) {
+                String fwdSw = fwdSws.get(0);
+                if (mplsLabel.equals(getMplsLabel(fwdSw))) {
+                    PopMplsAction popAction = new PopMplsAction(EthType.IPv4);
+                    CopyTtlInAction copyTtlInAction = new CopyTtlInAction();
+
+                    actions.add(popAction);
+                    actions.add(copyTtlInAction);
+                }
+            }
+        }
 
         GroupAction groupAction = new GroupAction();
         for (String fwdSw: fwdSws)
@@ -520,7 +571,21 @@
                     net.onrc.onos.core.matchaction.MatchActionOperations.Operator.ADD,
                     matchAction);
 
-        printMatchActionOperationEntry(sw, maEntry);
+        //printMatchActionOperationEntry(sw, maEntry);
+        //IOF13Switch sw13 = (IOF13Switch)masterSwitch;
+        IOF13Switch sw13 = (IOF13Switch)floodlightProvider.getMasterSwitch(
+                getSwId(sw.getDpid().toString()));
+
+        try {
+            printMatchActionOperationEntry(sw, maEntry);
+            sw13.pushFlow(maEntry);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+
+        sw13.flush();
 
     }
 
@@ -660,4 +725,46 @@
         ipHandler.addRouteToHost(sw, hostIpAddress, hostMacAddress);
 
     }
+
+    @Override
+    public String getName() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void switchActivatedMaster(long swId) {
+        masterSwitch = floodlightProvider.getMasterSwitch(swId);
+
+    }
+
+    @Override
+    public void switchActivatedEqual(long swId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void switchMasterToEqual(long swId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void switchEqualToMaster(long swId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void switchDisconnected(long swId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void switchPortChanged(long swId, OFPortDesc port, PortChangeType changeType) {
+        // TODO Auto-generated method stub
+
+    }
 }