Added the function to send ICMP response for switches
Change-Id: Ib3ecfc94cdc6e321d09119842b19ff2c160efe5a
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 5126958..a3cb50e 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
@@ -1,7 +1,10 @@
package net.onrc.onos.apps.segmentrouting;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Queue;
+import java.util.Vector;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
@@ -11,11 +14,15 @@
import net.onrc.onos.api.packet.IPacketService;
import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
import net.onrc.onos.core.packet.Ethernet;
+import net.onrc.onos.core.packet.ICMP;
import net.onrc.onos.core.packet.IPv4;
import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.Link;
import net.onrc.onos.core.topology.MutableTopology;
import net.onrc.onos.core.topology.Port;
import net.onrc.onos.core.topology.Switch;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.SwitchPort;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMatchV3;
@@ -82,45 +89,128 @@
if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
IPv4 ipv4 = (IPv4)payload.getPayload();
+
if (ipv4.getProtocol() == IPv4.PROTOCOL_ICMP) {
+ int destinationAddress = ipv4.getDestinationAddress();
- addRouteToHost(sw, ipv4);
+ // Check if it is ICMP request to the switch
+ String switchIpAddressSlash = sw.getStringAttribute("routerIp");
+ if (switchIpAddressSlash != null) {
+ String switchIpAddressStr = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
+ IPv4Address switchIpAddress = IPv4Address.of(switchIpAddressStr);
+ if (((ICMP)ipv4.getPayload()).getIcmpType() == 0x08 &&
+ destinationAddress == switchIpAddress.getInt()) {
+ sendICMPResponse(sw, inPort, payload);
+ return;
+ }
+ }
+
+ // Check if the destination is any host known to TopologyService
+ for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts()) {
+ IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
+ if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
+ byte[] destinationMacAddress = host.getMacAddress().toBytes();
+ addRouteToHost(sw, destinationAddress, destinationMacAddress);
+ return;
+ }
+ }
+
+ // What if the ICMP destination is neither to switch nor known to TopologyService ??
+ lookupPath(sw, inPort);
}
}
}
+
+ /**
+ * Test method for ECMP path computation
+ *
+ */
+ private void lookupPath(Switch sw, Port inPort) {
+ // TODO Auto-generated method stub
+
+ Queue<Dpid> switchQueue = new LinkedList();
+ Vector<Dpid> switchVectorDone = new Vector();
+ switchQueue.add(sw.getDpid());
+ Dpid dpid = null;
+ Switch s = null;
+
+ dpid = sw.getDpid();
+ while (dpid != null) {
+ s = mutableTopology.getSwitch(dpid);
+ for (Port port : mutableTopology.getPorts(s.getDpid())) {
+ SwitchPort sport1 = new SwitchPort(port.getDpid(), port.getPortNumber());
+ for (Link link : mutableTopology.getOutgoingLinks(sport1)) {
+ if (!switchVectorDone.contains(link.getDstSwitch().getDpid())) {
+ log.debug("{} --- {} ",link.getSrcSwitch().getDpid(), link.getDstSwitch().getDpid());
+ switchQueue.add(link.getDstSwitch().getDpid());
+ }
+ }
+ }
+ switchVectorDone.add(s.getDpid());
+ dpid = s.getDpid();
+ switchQueue.remove(dpid);
+ dpid = switchQueue.poll();
+
+ }
+
+
+ }
+
+ /**
+ * Send ICMP reply back
+ *
+ * @param sw Switch
+ * @param inPort Port the ICMP packet is forwarded from
+ * @param icmpRequest the ICMP request to handle
+ * @param destinationAddress destination address to send ICMP response to
+ */
+ private void sendICMPResponse(Switch sw, Port inPort, Ethernet icmpRequest) {
+
+ Ethernet icmpReplyEth = new Ethernet();
+
+ IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload();
+ IPv4 icmpReplyIpv4 = new IPv4();
+ int destAddress = icmpRequestIpv4.getDestinationAddress();
+ icmpReplyIpv4.setDestinationAddress(icmpRequestIpv4.getSourceAddress());
+ icmpReplyIpv4.setSourceAddress(destAddress);
+ icmpReplyIpv4.setTtl((byte)64);
+ icmpReplyIpv4.setChecksum((short)0);
+
+
+ ICMP icmpReply = (ICMP)icmpRequestIpv4.getPayload().clone();
+ icmpReply.setIcmpCode((byte)0x00);
+ icmpReply.setIcmpType((byte) 0x00);
+ icmpReply.setChecksum((short)0);
+
+ icmpReplyIpv4.setPayload(icmpReply);
+
+ icmpReplyEth.setPayload(icmpReplyIpv4);
+ icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4);
+ icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress());
+ icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress());
+
+ packetService.sendPacket(icmpReplyEth, new SwitchPort(sw.getDpid(), inPort.getPortNumber()));
+
+ log.debug("Send an ICMP response {}", icmpReplyIpv4.toString());
+
+ }
+
+
/**
* Add routing rules to forward packets to known hosts
*
* @param sw Switch
* @param hostIp Host IP address to forwards packets to
*/
- private void addRouteToHost(Switch sw, IPv4 hostIp) {
+ private void addRouteToHost(Switch sw, int destinationAddress, byte[] destinationMacAddress) {
IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
OFFactory factory = ofSwitch.getFactory();
- int destinationAddress = hostIp.getDestinationAddress();
- // Check APR entries
- byte[] destinationMacAddress = null;;
- // srManager.getMacAddressFromIpAddress(destinationAddress);
-
- // Check TopologyService
-
- for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts()) {
- IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
- if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
- destinationMacAddress = host.getMacAddress().toBytes();
- }
- }
-
-
- // If MAC address is not known to the host, just return
- if (destinationMacAddress == null)
- return;
OFOxmEthType ethTypeIp = factory.oxms()
.ethType(EthType.IPv4);