Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
320 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
client-level/fl-ho-cl/src/main/java/net/floodlightcontroller/ARPRewrite
Submodule ARPRewrite
deleted from
06e5cf
312 changes: 312 additions & 0 deletions
312
client-level/fl-ho-cl/src/main/java/net/floodlightcontroller/ARPRewrite/ARPRewrite.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,312 @@ | ||
package net.floodlightcontroller.ARPRewrite; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Map; | ||
|
||
import net.floodlightcontroller.core.FloodlightContext; | ||
import net.floodlightcontroller.core.IFloodlightProviderService; | ||
import net.floodlightcontroller.core.IOFSwitch; | ||
import net.floodlightcontroller.core.module.FloodlightModuleContext; | ||
import net.floodlightcontroller.core.module.FloodlightModuleException; | ||
import net.floodlightcontroller.core.module.IFloodlightModule; | ||
import net.floodlightcontroller.core.module.IFloodlightService; | ||
import net.floodlightcontroller.forwarding.Forwarding; | ||
import net.floodlightcontroller.packet.ARP; | ||
import net.floodlightcontroller.packet.Ethernet; | ||
import net.floodlightcontroller.packet.IPacket; | ||
import net.floodlightcontroller.packet.IPv4; | ||
import net.floodlightcontroller.routing.IRoutingDecision; | ||
import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; | ||
import net.floodlightcontroller.storage.IStorageSourceService; | ||
import net.floodlightcontroller.util.MACAddress; | ||
|
||
import org.openflow.protocol.OFFlowMod; | ||
import org.openflow.protocol.OFPacketIn; | ||
import org.openflow.protocol.OFPacketOut; | ||
import org.openflow.protocol.OFType; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class ARPRewrite extends Forwarding implements | ||
IFloodlightModule { | ||
protected static Logger log = LoggerFactory.getLogger(ARPRewrite.class); | ||
// proxyArp MAC address - can replace with other values in future | ||
public static String TAP_MAC_ADDRESS = "12:51:16:90:8f:ee"; // Tap | ||
public static String IFACE1_MAC_ADDRESS = "00:1d:e1:3b:48:1d"; // WiMAX | ||
public static String IFACE2_MAC_ADDRESS = "00:23:15:81:8b:f8"; // WiFi | ||
public static String IFACE3_MAC_ADDRESS = "00:23:15:81:8b:f8"; // WiFi #2 (Not Used, GEC18) | ||
public static String IFACE4_MAC_ADDRESS = "00:1d:e1:3b:48:1d"; // WiMAX #2 (Not Used, GEC18) | ||
public static String BROADCAST_MAC = "ff:ff:ff:ff:ff:ff"; | ||
|
||
public static String IFACE1_DPID; | ||
public static String IFACE2_DPID; | ||
public static String IFACE3_DPID; | ||
public static String IFACE4_DPID; | ||
public static String TAP_DPID; | ||
|
||
protected MACAddress TAP_MAC; | ||
protected MACAddress IFACE1_MAC; | ||
protected MACAddress IFACE2_MAC; | ||
protected MACAddress IFACE3_MAC; | ||
protected MACAddress IFACE4_MAC; | ||
protected MACAddress BCAST_MAC; | ||
|
||
protected IStaticFlowEntryPusherService sfep; | ||
protected IFloodlightProviderService floodlightProvider; | ||
|
||
@Override | ||
public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { | ||
Collection<Class<? extends IFloodlightService>> l = | ||
new ArrayList<Class<? extends IFloodlightService>>(); | ||
l.add(IFloodlightProviderService.class); | ||
l.add(IStorageSourceService.class); | ||
l.add(IStaticFlowEntryPusherService.class); | ||
return l; | ||
} | ||
|
||
@Override | ||
public void init(FloodlightModuleContext context) | ||
throws FloodlightModuleException { | ||
|
||
sfep = context.getServiceImpl(IStaticFlowEntryPusherService.class); | ||
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); | ||
|
||
/* read our config options */ | ||
Map<String, String> configOptions = context.getConfigParams(this); | ||
|
||
TAP_MAC_ADDRESS = configOptions.get("tap-mac-address"); | ||
IFACE1_MAC_ADDRESS = configOptions.get("wimax-mac-address"); | ||
IFACE2_MAC_ADDRESS = configOptions.get("wifi-mac-address"); | ||
IFACE3_MAC_ADDRESS = configOptions.get("iface3-mac-address"); | ||
IFACE4_MAC_ADDRESS = configOptions.get("iface4-mac-address"); | ||
|
||
TAP_DPID = configOptions.get("tap-dpid"); | ||
IFACE1_DPID = configOptions.get("wimax-dpid"); | ||
IFACE2_DPID = configOptions.get("wifi-dpid"); | ||
IFACE3_DPID = configOptions.get("iface3-dpid"); | ||
IFACE4_DPID = configOptions.get("iface4-dpid"); | ||
|
||
TAP_MAC = MACAddress.valueOf(TAP_MAC_ADDRESS); | ||
IFACE1_MAC = MACAddress.valueOf(IFACE1_MAC_ADDRESS); | ||
IFACE2_MAC = MACAddress.valueOf(IFACE2_MAC_ADDRESS); | ||
IFACE3_MAC = MACAddress.valueOf(IFACE3_MAC_ADDRESS); | ||
IFACE4_MAC = MACAddress.valueOf(IFACE4_MAC_ADDRESS); | ||
BCAST_MAC = MACAddress.valueOf(BROADCAST_MAC); | ||
|
||
super.init(context); | ||
} | ||
|
||
|
||
@Override | ||
public void startUp(FloodlightModuleContext context) { | ||
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); | ||
} | ||
|
||
@Override | ||
public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, | ||
IRoutingDecision decision, FloodlightContext cntx) { | ||
Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, | ||
IFloodlightProviderService.CONTEXT_PI_PAYLOAD); | ||
if (eth.getEtherType() == Ethernet.TYPE_ARP) { | ||
|
||
// retrieve arp to determine addresses | ||
ARP arpPayload = (ARP) eth.getPayload(); | ||
|
||
// (1) Get flows from switch | ||
// (2) Find flow with matching ingress port | ||
// (3) Use matching flow and extract output port | ||
// (4) Use switch DPID and use correct (hard-coded) MAC of physical interface on that switch | ||
// This is only for ARP. DHCP is ethertype 0x800, which will work with existing flows. | ||
|
||
// (1) Get flows | ||
Map<String, OFFlowMod> flows; | ||
//long switchIDAsLong = sw.getId(); | ||
//String switchIDAsString = Long.toString(switchIDAsLong); | ||
//flows = sfep.getFlows("00:00:00:00:00:00:00:0".concat(switchIDAsString)); // This might not convert correctly | ||
flows = sfep.getFlows(sw.getStringId()); // This might not convert correctly | ||
Collection<OFFlowMod> flowsAsCollection; | ||
if (flows != null) { | ||
flowsAsCollection = flows.values(); | ||
} else { | ||
log.debug("No flows on switch " + sw.getStringId()); | ||
return Command.CONTINUE; | ||
} | ||
short inPort = pi.getInPort(); | ||
short outPort = 0; | ||
log.debug("Packet from switch " + sw.getStringId() + " on port " + inPort); | ||
|
||
|
||
// (2) and (3) Get output port from matching ingress port | ||
if (!flows.isEmpty()) { | ||
for (OFFlowMod myFlow : flowsAsCollection) { | ||
if (myFlow.getMatch().getInputPort() == inPort) { | ||
outPort = myFlow.getOutPort(); | ||
log.debug("Got (inPort, outPort) pair (" + inPort + ", " + outPort + ")"); | ||
break; | ||
} | ||
} | ||
} else { | ||
log.info("No flows returned for DPID " + sw.getStringId()); | ||
return Command.CONTINUE; | ||
} | ||
|
||
if (outPort == 0) { | ||
log.debug("No matching flow found"); | ||
return Command.CONTINUE; | ||
} | ||
|
||
// (4) Determine MAC address to rewrite | ||
// ingress on tap | ||
|
||
MACAddress targetMAC; | ||
MACAddress sourceMAC; | ||
MACAddress destinationMAC; | ||
boolean isIngress = false; | ||
boolean isRequest = false; | ||
short arpOpCode = arpPayload.getOpCode(); | ||
if (arpOpCode == ARP.OP_REQUEST) { | ||
log.info("ARP packet is a request"); | ||
destinationMAC = BCAST_MAC; | ||
isRequest = true; | ||
} else if (arpOpCode == ARP.OP_REPLY) { | ||
log.info("ARP packet is a reply"); | ||
} else { | ||
log.info("ARP packet was neither request nor reply"); | ||
return Command.CONTINUE; | ||
} | ||
if (sw.getStringId() == TAP_DPID) { | ||
if (outPort == 1 || outPort == 65534 || outPort == -1) { | ||
targetMAC = TAP_MAC; | ||
sourceMAC = null; | ||
isIngress = true; | ||
} else { | ||
targetMAC = null; | ||
sourceMAC = TAP_MAC; | ||
} | ||
} else if (sw.getStringId() == IFACE1_DPID) { | ||
if (outPort == 1 || outPort == 65534 || outPort == -1) { | ||
targetMAC = null; | ||
sourceMAC = IFACE1_MAC; | ||
} else { | ||
targetMAC = TAP_MAC; | ||
sourceMAC = null; | ||
isIngress = true; | ||
} | ||
} else if (sw.getStringId() == IFACE2_DPID) { | ||
if (outPort == 1 || outPort == 65534 || outPort == -1) { | ||
targetMAC = null; | ||
sourceMAC = IFACE2_MAC; | ||
} else { | ||
targetMAC = TAP_MAC; | ||
sourceMAC = null; | ||
isIngress = true; | ||
} | ||
} else if (sw.getStringId() == IFACE3_DPID) { | ||
if (outPort == 1 || outPort == 65534 || outPort == -1) { | ||
targetMAC = null; | ||
sourceMAC = IFACE3_MAC; | ||
} else { | ||
targetMAC = TAP_MAC; | ||
sourceMAC = null; | ||
isIngress = true; | ||
} | ||
} else if (sw.getStringId() == IFACE4_DPID) { | ||
if (outPort == 1 || outPort == 65534 || outPort == -1) { | ||
targetMAC = null; | ||
sourceMAC = IFACE4_MAC; | ||
} else { | ||
targetMAC = TAP_MAC; | ||
sourceMAC = null; | ||
isIngress = true; | ||
} | ||
} else { | ||
sourceMAC = null; | ||
targetMAC = null; | ||
log.debug("Did find a matching DPID"); | ||
} | ||
|
||
// 4 Cases: Only rewrite on non-TAP switch. The tap switch will have 4 flows for 0x800 and 0x806. | ||
// All rewrites source and destination will occur on the OVS switch at the physical interface. | ||
// (1) Ingress Packet, ARP Request -- rewrite nothing (need to find MAC aka request) | ||
// (2) Ingress Packet, ARP Reply -- rewrite destination MAC to tap | ||
// (3) Outbound Packet, ARP Request -- rewrite source MAC to physical (need to be able to respond and send on IFACE) | ||
// (4) Outbound Packet, ARP Reply -- rewrite source MAC to physical (need to be able to send on IFACE) | ||
if (isRequest && sw.getStringId() == TAP_DPID && isIngress) { | ||
log.debug("Sending request out with SRC " + sourceMAC.toString() + " DST " + MACAddress.valueOf(arpPayload.getTargetHardwareAddress()) | ||
+ " from port " + inPort + " to port " + outPort); | ||
destinationMAC = BCAST_MAC; | ||
sendARP(sw, pi, cntx, inPort, (short)65534, arpOpCode, | ||
arpPayload.getSenderHardwareAddress(), arpPayload.getTargetHardwareAddress(), destinationMAC.toBytes()); | ||
} else if (!isRequest && sw.getStringId() == TAP_DPID && isIngress) { | ||
log.debug("Sending reply out with SRC " + sourceMAC.toString() + " DST " + MACAddress.valueOf(arpPayload.getTargetHardwareAddress()) | ||
+ " from port " + inPort + " to port " + outPort); | ||
destinationMAC = targetMAC; | ||
sendARP(sw, pi, cntx, inPort, (short)65534, arpOpCode, | ||
arpPayload.getSenderHardwareAddress(), targetMAC.toBytes(), destinationMAC.toBytes()); | ||
} else if (isRequest && sw.getStringId() != TAP_DPID && !isIngress) { | ||
log.debug("Sending request out with SRC " + sourceMAC.toString() + " DST " + MACAddress.valueOf(arpPayload.getTargetHardwareAddress()) | ||
+ " from port " + inPort + " to port " + outPort); | ||
destinationMAC = BCAST_MAC; | ||
// removed (-) from outPort for testing | ||
sendARP(sw, pi, cntx, inPort, (short)-outPort, arpOpCode, | ||
sourceMAC.toBytes(), arpPayload.getTargetHardwareAddress(), destinationMAC.toBytes()); | ||
} else if (!isRequest && sw.getStringId() != TAP_DPID && !isIngress) { | ||
log.debug("Sending reply out with SRC " + sourceMAC.toString() + " DST " + MACAddress.valueOf(arpPayload.getTargetHardwareAddress()) | ||
+ " from port " + inPort + " to port " + outPort); | ||
destinationMAC = targetMAC; | ||
sendARP(sw, pi, cntx, inPort, (short)-outPort, arpOpCode, | ||
sourceMAC.toBytes(), arpPayload.getTargetHardwareAddress(), destinationMAC.toBytes()); | ||
} else { | ||
log.debug("Determining how to rewrite ARP packet failed!"); | ||
} | ||
} else { | ||
// Do nothing | ||
} | ||
|
||
return Command.CONTINUE; | ||
} | ||
|
||
protected void sendARP(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, short inPort, short outPort, | ||
short arpOpCode , byte[] sourceMACAddress, byte[] targetMACAddress, byte[] destinationMACAddress) { | ||
|
||
Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); | ||
// retrieve original ARP | ||
ARP arpPayload = (ARP) eth.getPayload(); | ||
log.debug("ARP to " + IPv4.fromIPv4Address(IPv4.toIPv4Address(arpPayload.getTargetProtocolAddress()))); | ||
|
||
// Modify original ARP packet | ||
IPacket newARPPacket = new Ethernet() | ||
.setSourceMACAddress(sourceMACAddress) | ||
.setDestinationMACAddress(destinationMACAddress) | ||
.setEtherType(Ethernet.TYPE_ARP) | ||
.setVlanID(eth.getVlanID()) | ||
.setPriorityCode(eth.getPriorityCode()) | ||
.setPayload( | ||
new ARP() | ||
.setHardwareType(ARP.HW_TYPE_ETHERNET) | ||
.setProtocolType(ARP.PROTO_TYPE_IP) | ||
.setHardwareAddressLength((byte) 6) | ||
.setProtocolAddressLength((byte) 4) | ||
.setOpCode(arpOpCode) | ||
.setSenderHardwareAddress(sourceMACAddress) | ||
.setSenderProtocolAddress( | ||
arpPayload.getSenderProtocolAddress()) | ||
.setTargetHardwareAddress( | ||
targetMACAddress) | ||
.setTargetProtocolAddress( | ||
arpPayload.getTargetProtocolAddress())); | ||
|
||
// push ARP out | ||
pushPacket(newARPPacket, sw, OFPacketOut.BUFFER_ID_NONE, inPort, outPort, cntx, true); | ||
log.debug("ARP packet pushed out PORT " + outPort + " on SWITCH " + sw.getStringId() + " with SRC " + MACAddress.valueOf(sourceMACAddress) | ||
+ " and TGT " + MACAddress.valueOf(targetMACAddress) + " and DST " + MACAddress.valueOf(destinationMACAddress)); | ||
return; | ||
} | ||
|
||
@Override | ||
public Collection<Class<? extends IFloodlightService>> getModuleServices() { | ||
return null; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters