Learning switch functionality
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
index a0b6aa7..e69de29 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ArpHandler.java
@@ -1,273 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 Open Networking Laboratory.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License v2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- ******************************************************************************/
-
-package net.onrc.onos.apps.segmentrouting;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.api.packet.IPacketListener;
-import net.onrc.onos.api.packet.IPacketService;
-import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
-import net.onrc.onos.core.packet.ARP;
-import net.onrc.onos.core.packet.Ethernet;
-import net.onrc.onos.core.packet.IPv4;
-import net.onrc.onos.core.topology.ITopologyService;
-import net.onrc.onos.core.topology.MutableTopology;
-import net.onrc.onos.core.topology.Port;
-import net.onrc.onos.core.topology.Switch;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.U32;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.esotericsoftware.minlog.Log;
-
-/**
- * Handling ARP requests to switches for Segment Routing.
- * <p/>
- * The module is for handling ARP requests to switches. It sends ARP response for any known
- * hosts to the controllers.
- * TODO: need to check the network config file for all hosts and packets
- */
-public class ArpHandler implements IPacketListener {
-
- private static final Logger log = LoggerFactory
- .getLogger(ArpHandler.class);
-
- private IFloodlightProviderService floodlightProvider;
- private IPacketService packetService;
- private IFlowPusherService flowPusher;
- private ITopologyService topologyService;
- private MutableTopology mutableTopology;
- //private List<ArpEntry> arpEntries;
- private SegmentRoutingManager srManager;
-
- private static final short IDLE_TIMEOUT = 0;
- private static final short HARD_TIMEOUT = 0;
-
- private static final int TABLE_VLAN = 0;
- private static final int TABLE_TMAC = 1;
- private static final int TABLE_IPv4_UNICAST = 2;
- private static final int TABLE_MPLS = 3;
- private static final int TABLE_META = 4;
- private static final int TABLE_ACL = 5;
-
- private static final short MAX_PRIORITY = (short) 0xffff;
- private static final short SLASH_24_PRIORITY = (short) 0xfff0;
- private static final short SLASH_16_PRIORITY = (short) 0xff00;
- private static final short SLASH_8_PRIORITY = (short) 0xf000;
- private static final short MIN_PRIORITY = 0x0;
-
-
- /*
- * Default Constructor
- */
- public ArpHandler(FloodlightModuleContext context, SegmentRoutingManager segmentRoutingManager) {
-
- this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
- this.packetService = context.getServiceImpl(IPacketService.class);
- this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
- this.topologyService = context.getServiceImpl(ITopologyService.class);
- this.srManager = segmentRoutingManager;
- this.mutableTopology = topologyService.getTopology();
-
- packetService.registerPacketListener(this);
- //arpEntries = new ArrayList<ArpEntry>();
-
- Log.debug("Arp Handler is initialized");
-
- }
-
- @Override
- public void receive(Switch sw, Port inPort, Ethernet payload) {
- log.debug("Received a packet {} from sw {} ", payload.toString(), sw.getDpid());
-
- if (payload.getEtherType() == Ethernet.TYPE_ARP) {
-
- ARP arp = (ARP)payload.getPayload();
- srManager.updateArpCache(arp);
-
- if (arp.getOpCode() == ARP.OP_REQUEST) {
- handleArpRequest(sw, inPort, arp);
- }
- else {
- byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
- String targetMacAddressStr = MacAddress.of(senderMacAddressByte).toString();
- if (targetMacAddressStr.equals(sw.getStringAttribute("routerMac"))) {
- IPv4Address hostIpAddress = IPv4Address.of(arp.getSenderProtocolAddress());
- srManager.addRouteToHost(sw,hostIpAddress.getInt(), senderMacAddressByte);
- }
- }
-
- }
-
- }
-
-
- /**
- * Send an ARP response for the ARP request to the known switches
- *
- * @param sw Switch
- * @param inPort port to send ARP response to
- * @param arpRequest ARP request packet to handle
- */
- private void handleArpRequest(Switch sw, Port inPort, ARP arpRequest) {
-
- List<String> subnetGatewayIPs = getSubnetGatewayIps(sw);
- String switchMacAddressStr = sw.getStringAttribute("routerMac");
- if (!subnetGatewayIPs.isEmpty()) {
- IPv4Address targetProtocolAddress = IPv4Address.of(arpRequest.getTargetProtocolAddress());
- // Do we have to check port also ??
- if (subnetGatewayIPs.contains(targetProtocolAddress.toString())) {
- MACAddress targetMac = MACAddress.valueOf(switchMacAddressStr);
-
- ARP arpReply = new ARP();
- arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
- .setProtocolType(ARP.PROTO_TYPE_IP)
- .setHardwareAddressLength(
- (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
- .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
- .setOpCode(ARP.OP_REPLY)
- .setSenderHardwareAddress(targetMac.toBytes())
- .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
- .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
- .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
-
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
- .setSourceMACAddress(targetMac.toBytes())
- .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
-
- sendPacketOut(sw, eth, inPort.getPortNumber().shortValue());
- }
- }
- }
-
- /**
- * Retrieve Gateway IP address of all subnets defined in net config file
- *
- * @param sw Switch to retrieve subnet GW IPs for
- * @return list of GW IP addresses for all subnets
- */
- private List<String> getSubnetGatewayIps(Switch sw) {
-
- List<String> gatewayIps = new ArrayList<String>();
-
- String subnets = sw.getStringAttribute("subnets");
- try {
- JSONArray arry = new JSONArray(subnets);
- for (int i = 0; i < arry.length(); i++) {
- String subnetIpSlash = (String) arry.getJSONObject(i).get("subnetIp");
- if (subnetIpSlash != null) {
- String subnetIp = subnetIpSlash.substring(0, subnetIpSlash.indexOf('/'));
- gatewayIps.add(subnetIp);
- }
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- return gatewayIps;
- }
-
- /**
- * Send an ARP request
- *
- * @param sw Switch
- * @param targetAddress Target IP address
- * @param inPort Port to send the ARP request
- *
- */
- public void sendArpRequest(Switch sw, int targetAddressInt, Port inPort) {
-
- IPv4Address targetAddress = IPv4Address.of(targetAddressInt);
- String senderMacAddressStr = sw.getStringAttribute("routerMac");
- String senderIpAddressSlash = sw.getStringAttribute("routerIp");
- if (senderMacAddressStr == null || senderIpAddressSlash == null)
- return;
- String senderIpAddressStr =
- senderIpAddressSlash.substring(0, senderIpAddressSlash.indexOf('/'));
- byte[] senderMacAddress = MacAddress.of(senderMacAddressStr).getBytes();
- byte[] senderIpAddress = IPv4Address.of(senderIpAddressStr).getBytes();
-
- ARP arpRequest = new ARP();
- arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
- .setProtocolType(ARP.PROTO_TYPE_IP)
- .setHardwareAddressLength(
- (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
- .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
- .setOpCode(ARP.OP_REQUEST)
- .setSenderHardwareAddress(senderMacAddress)
- .setTargetHardwareAddress(MacAddress.NONE.getBytes())
- .setSenderProtocolAddress(senderIpAddress)
- .setTargetProtocolAddress(targetAddress.getBytes());
-
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(MacAddress.BROADCAST.getBytes())
- .setSourceMACAddress(senderMacAddress)
- .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
-
- sendPacketOut(sw, eth, (short)-1);
-
- }
-
- /**
- * Send PACKET_OUT packet to switch
- *
- * @param sw Switch to send the packet to
- * @param packet Packet to send
- * @param switchPort port to send (if -1, broadcast)
- */
- private void sendPacketOut(Switch sw, Ethernet packet, short port) {
-
- IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
- OFFactory factory = ofSwitch.getFactory();
-
- List<OFAction> actions = new ArrayList<>();
-
- if (port > 0) {
- OFAction outport = factory.actions().output(OFPort.of(port), Short.MAX_VALUE);
- actions.add(outport);
- }
- else {
- Iterator<Port> iter = sw.getPorts().iterator();
- while (iter.hasNext()) {
- Port p = iter.next();
- int pnum = p.getPortNumber().shortValue();
- if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
- OFAction outport = factory.actions().output(OFPort.of(p.getNumber().shortValue()),
- Short.MAX_VALUE);
- actions.add(outport);
- }
- }
- }
-
- OFPacketOut po = factory.buildPacketOut()
- .setData(packet.serialize())
- .setActions(actions)
- .build();
-
- flowPusher.add(sw.getDpid(), po);
- }
-
-}
diff --git a/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java b/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java
index 5fa76ca..a5df74b 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/ECMPShortestPathGraph.java
@@ -203,10 +203,11 @@
ArrayList<ArrayList<Dpid>>>> getAllLearnedSwitchesAndVia() {
HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>>
- switchViaMap = new HashMap();
+ switchViaMap = new HashMap<Integer, HashMap<Switch, ArrayList<ArrayList<Dpid>>>>();
for (Integer itrIndx : distanceSwitchMap.keySet()) {
- HashMap<Switch, ArrayList<ArrayList<Dpid>>> swMap = new HashMap();
+ HashMap<Switch, ArrayList<ArrayList<Dpid>>> swMap =
+ new HashMap<Switch, ArrayList<ArrayList<Dpid>>>();
for (Switch sw : distanceSwitchMap.get(itrIndx)) {
ArrayList<ArrayList<Dpid>> swViaArray = new ArrayList<>();
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 7e6d2ac..e04ae85 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/GenericIpHandler.java
@@ -76,8 +76,11 @@
@Override
public void receive(Switch sw, Port inPort, Ethernet payload) {
// TODO Auto-generated method stub
- if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
+ if ((payload.getEtherType() == Ethernet.TYPE_IPV4) &&
+ (((IPv4)payload.getPayload()).getProtocol() != IPv4.PROTOCOL_ICMP)){
+ log.debug("GenericIPHandler: Received a IP packet {} from sw {} ",
+ payload.toString(), sw.getDpid());
IPv4 ipv4 = (IPv4)payload.getPayload();
int destinationAddress = ipv4.getDestinationAddress();
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 b548e18..b8bbc99 100644
--- a/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
+++ b/src/main/java/net/onrc/onos/apps/segmentrouting/IcmpHandler.java
@@ -12,6 +12,7 @@
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.Host;
import net.onrc.onos.core.topology.ITopologyService;
import net.onrc.onos.core.topology.MutableTopology;
import net.onrc.onos.core.topology.Port;
@@ -92,6 +93,9 @@
IPv4 ipv4 = (IPv4)payload.getPayload();
if (ipv4.getProtocol() == IPv4.PROTOCOL_ICMP) {
+
+ log.debug("ICMPHandler: Received a ICMP packet {} from sw {} ",
+ payload.toString(), sw.getDpid());
int destinationAddress = ipv4.getDestinationAddress();
String destAddressStr = IPv4Address.of(destinationAddress).toString();
@@ -105,10 +109,35 @@
if (((ICMP)ipv4.getPayload()).getIcmpType() == ICMP_TYPE_ECHO &&
(destinationAddress == switchIpAddress.getInt() ||
gatewayIps.contains(destAddressStr))) {
+ log.debug("ICMPHandler: ICMP packet for sw {} and "
+ + "sending ICMP response ", sw.getDpid());
sendICMPResponse(sw, inPort, payload);
return;
}
}
+
+ /* Check if ICMP is for any switch known host */
+ for (Host host: sw.getHosts()) {
+ IPv4Address hostIpAddress =
+ IPv4Address.of(host.getIpAddress());
+ if (hostIpAddress != null &&
+ hostIpAddress.equals(destinationAddress)) {
+ /* TODO: We should not have come here as ARP itself
+ * would have installed a Route to the host. See if
+ * we can remove this code
+ */
+ log.debug("ICMPHandler: ICMP request for known host {}",
+ hostIpAddress);
+ byte[] destinationMacAddress = host.getMacAddress().toBytes();
+ srManager.addRouteToHost(sw,
+ destinationAddress, destinationMacAddress);
+ return;
+ }
+ }
+ /* ICMP for an unknown host */
+ log.debug("ICMPHandler: ICMP request for unknown host {}"
+ + " and sending ARP request", destinationAddress);
+ srManager.sendArpRequest(sw, destinationAddress, inPort);
}
}