blob: 9f0fa86428de262034f28f8994ee4698aa4e640c [file] [log] [blame]
/*******************************************************************************
* 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.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import net.floodlightcontroller.core.IFloodlightProviderService;
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 net.onrc.onos.core.util.SwitchPort;
import org.projectfloodlight.openflow.types.IPv4Address;
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);
}
}
}
/**
* 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) {
String switchIpAddressSlash = sw.getStringAttribute("routerIp");
String switchMacAddressStr = sw.getStringAttribute("routerMac");
if (switchIpAddressSlash != null && switchMacAddressStr != null) {
String switchIpAddressStr = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
IPv4Address switchIpAddress = IPv4Address.of(switchIpAddressStr);
IPv4Address targetProtocolAddress = IPv4Address.of(arpRequest.getTargetProtocolAddress());
if (targetProtocolAddress.equals(switchIpAddress)) {
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);
packetService.sendPacket(eth, new SwitchPort(sw.getDpid(), inPort.getPortNumber()));
}
}
}
/**
* The function checks if given IP matches to the given subnet mask
*
* @param addr - subnet address to match
* @param addr1 - IP address to check
* @return true if the IP address matches to the subnet, otherwise false
*/
public static boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
String[] parts = addr.split("/");
String ip = parts[0];
int prefix;
if (parts.length < 2) {
prefix = 0;
} else {
prefix = Integer.parseInt(parts[1]);
}
Inet4Address a =null;
Inet4Address a1 =null;
try {
a = (Inet4Address) InetAddress.getByName(ip);
a1 = (Inet4Address) InetAddress.getByName(addr1);
} catch (UnknownHostException e){}
byte[] b = a.getAddress();
int ipInt = ((b[0] & 0xFF) << 24) |
((b[1] & 0xFF) << 16) |
((b[2] & 0xFF) << 8) |
((b[3] & 0xFF) << 0);
byte[] b1 = a1.getAddress();
int ipInt1 = ((b1[0] & 0xFF) << 24) |
((b1[1] & 0xFF) << 16) |
((b1[2] & 0xFF) << 8) |
((b1[3] & 0xFF) << 0);
int mask = ~((1 << (32 - prefix)) - 1);
if ((ipInt & mask) == (ipInt1 & mask)) {
return true;
}
else {
return false;
}
}
}