Added an L3 mode to ProxyArpModule which limits the ports ARPs are sent out based on IP address. This should prevent leaking ARPs from one network into another
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index 278fb86..d72c52c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -24,7 +24,6 @@
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.core.util.SingletonTask;
-import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.restserver.IRestApiService;
@@ -81,7 +80,6 @@
protected IFloodlightProviderService floodlightProvider;
protected ITopologyService topology;
protected ITopoRouteService topoRouteService;
- protected IDeviceService devices;
protected IRestApiService restApi;
protected ProxyArpManager proxyArp;
@@ -116,6 +114,7 @@
protected Map<String, Interface> interfaces;
protected Map<InetAddress, BgpPeer> bgpPeers;
protected SwitchPort bgpdAttachmentPoint;
+ protected MACAddress bgpdMacAddress;
//True when all switches have connected
protected volatile boolean switchesConnected = false;
@@ -193,6 +192,7 @@
new Dpid(config.getBgpdAttachmentDpid()),
new Port(config.getBgpdAttachmentPort()));
+ bgpdMacAddress = config.getBgpdMacAddress();
} catch (JsonParseException e) {
log.error("Error in JSON file", e);
System.exit(1);
@@ -233,7 +233,6 @@
= new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
l.add(ITopologyService.class);
- l.add(IDeviceService.class);
l.add(IRestApiService.class);
return l;
}
@@ -250,12 +249,11 @@
// Register floodlight provider and REST handler.
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
topology = context.getServiceImpl(ITopologyService.class);
- devices = context.getServiceImpl(IDeviceService.class);
restApi = context.getServiceImpl(IRestApiService.class);
//TODO We'll initialise this here for now, but it should really be done as
//part of the controller core
- proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
+ proxyArp = new ProxyArpManager(floodlightProvider, topology);
linkUpdates = new ArrayList<LDUpdate>();
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@@ -300,6 +298,8 @@
log.debug("Config file set to {}", configFilename);
readGatewaysConfiguration(configFilename);
+
+ proxyArp.setL3Mode(interfacePtrie, bgpdMacAddress);
}
@Override
@@ -307,6 +307,8 @@
restApi.addRestletRoutable(new BgpRouteWebRoutable());
topology.addListener(this);
+ proxyArp.startUp();
+
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
//Retrieve the RIB from BGPd during startup
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
index 4b623e4..1d90edc 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
@@ -3,12 +3,15 @@
import java.util.Collections;
import java.util.List;
+import net.floodlightcontroller.util.MACAddress;
+
import org.codehaus.jackson.annotate.JsonProperty;
import org.openflow.util.HexString;
public class Configuration {
private long bgpdAttachmentDpid;
private short bgpdAttachmentPort;
+ private MACAddress bgpdMacAddress;
private List<String> switches;
private List<Interface> interfaces;
private List<BgpPeer> peers;
@@ -34,6 +37,15 @@
public void setBgpdAttachmentPort(short bgpdAttachmentPort) {
this.bgpdAttachmentPort = bgpdAttachmentPort;
}
+
+ public MACAddress getBgpdMacAddress() {
+ return bgpdMacAddress;
+ }
+
+ @JsonProperty("bgpdMacAddress")
+ public void setBgpdMacAddress(String strMacAddress) {
+ this.bgpdMacAddress = MACAddress.valueOf(strMacAddress);
+ }
public List<String> getSwitches() {
return Collections.unmodifiableList(switches);
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 521ba0f..ca84bc0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -17,11 +17,14 @@
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.bgproute.IPatriciaTrie;
+import net.onrc.onos.ofcontroller.bgproute.Interface;
+import net.onrc.onos.ofcontroller.bgproute.Prefix;
+import net.onrc.onos.ofcontroller.util.SwitchPort;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
@@ -48,12 +51,18 @@
protected IFloodlightProviderService floodlightProvider;
protected ITopologyService topology;
- protected IDeviceService devices;
protected Map<InetAddress, ArpTableEntry> arpTable;
protected SetMultimap<InetAddress, ArpRequest> arpRequests;
+ public enum Mode {L2_MODE, L3_MODE}
+
+ private Mode mode;
+ private IPatriciaTrie<Interface> interfacePtrie = null;
+ private MACAddress routerMacAddress = null;
+ //private SwitchPort bgpdAttachmentPoint = null;
+
private class ArpRequest {
private IArpRequester requester;
private boolean retry;
@@ -88,16 +97,26 @@
}
public ProxyArpManager(IFloodlightProviderService floodlightProvider,
- ITopologyService topology, IDeviceService devices){
+ ITopologyService topology){
this.floodlightProvider = floodlightProvider;
this.topology = topology;
- this.devices = devices;
arpTable = new HashMap<InetAddress, ArpTableEntry>();
arpRequests = Multimaps.synchronizedSetMultimap(
HashMultimap.<InetAddress, ArpRequest>create());
+ mode = Mode.L2_MODE;
+ }
+
+ public void setL3Mode(IPatriciaTrie<Interface> interfacePtrie, MACAddress routerMacAddress) {
+ this.interfacePtrie = interfacePtrie;
+ this.routerMacAddress = routerMacAddress;
+ //this.bgpdAttachmentPoint = bgpdAttachmentPoint;
+ mode = Mode.L3_MODE;
+ }
+
+ public void startUp() {
Timer arpTimer = new Timer();
arpTimer.scheduleAtFixedRate(new TimerTask() {
@Override
@@ -205,23 +224,31 @@
protected void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp) {
log.debug("ARP request received for {}",
bytesToStringAddr(arp.getTargetProtocolAddress()));
+
+ InetAddress target;
+ try {
+ target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
+ } catch (UnknownHostException e) {
+ log.debug("Invalid address in ARP request", e);
+ return;
+ }
+
+ if (mode == Mode.L3_MODE) {
+ Interface intf = interfacePtrie.match(new Prefix(target.getAddress(), 32));
+ if (intf != null && target.equals(intf.getIpAddress())) {
+ //ARP request for one of our interfaces, we can reply straight away
+ sendArpReply(arp, sw.getId(), pi.getInPort(), routerMacAddress.toBytes());
+ return;
+ }
+ }
byte[] mac = lookupArpTable(arp.getTargetProtocolAddress());
if (mac == null){
//Mac address is not in our arp table.
- //TODO check what the DeviceManager thinks
-
//Record where the request came from so we know where to send the reply
- InetAddress target;
- try {
- target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
- } catch (UnknownHostException e) {
- log.debug("Invalid address in ARP request", e);
- //return Command.CONTINUE; //Continue or stop?
- return;
- }
+
//Should we just broadcast all received requests here? Or rate limit
//if we know we just sent an request?
@@ -229,7 +256,8 @@
new HostArpRequester(this, arp, sw.getId(), pi.getInPort()), false));
//Flood the request out edge ports
- broadcastArpRequestOutEdge(pi.getPacketData(), sw.getId(), pi.getInPort());
+ //broadcastArpRequestOutEdge(pi.getPacketData(), sw.getId(), pi.getInPort());
+ sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
}
else {
//We know the address, so send a reply
@@ -279,7 +307,7 @@
ArpTableEntry arpEntry = arpTable.get(addr);
if (arpEntry == null){
- log.debug("MAC for {} unknown", bytesToStringAddr(ipAddress));
+ //log.debug("MAC for {} unknown", bytesToStringAddr(ipAddress));
return null;
}
@@ -332,18 +360,46 @@
.setProtocolAddressLength((byte)4) //can't find the constant anywhere
.setOpCode(ARP.OP_REQUEST)
.setSenderHardwareAddress(bgpdMac)
- .setSenderProtocolAddress(zeroIpv4)
+ //.setSenderProtocolAddress(zeroIpv4)
.setTargetHardwareAddress(zeroMac)
.setTargetProtocolAddress(ipAddress.getAddress());
-
+
+ byte[] senderIPAddress = zeroIpv4;
+ if (mode == Mode.L3_MODE) {
+ Interface intf = interfacePtrie.match(new Prefix(ipAddress.getAddress(), 32));
+ if (intf != null) {
+ senderIPAddress = intf.getIpAddress().getAddress();
+ }
+ }
+
+ arpRequest.setSenderProtocolAddress(senderIPAddress);
+
Ethernet eth = new Ethernet();
- //eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
eth.setSourceMACAddress(bgpdMac)
.setDestinationMACAddress(broadcastMac)
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(arpRequest);
- broadcastArpRequestOutEdge(eth.serialize(), 0, OFPort.OFPP_NONE.getValue());
+ //broadcastArpRequestOutEdge(eth.serialize(), 0, OFPort.OFPP_NONE.getValue());
+ sendArpRequestToSwitches(ipAddress, eth.serialize());
+ }
+
+ private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
+ sendArpRequestToSwitches(dstAddress, arpRequest, 0, OFPort.OFPP_NONE.getValue());
+ }
+ private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
+ long inSwitch, short inPort) {
+ if (mode == Mode.L2_MODE) {
+ log.debug("mode is l2");
+ broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+ }
+ else if (mode == Mode.L3_MODE) {
+ log.debug("mode is l3");
+ Interface intf = interfacePtrie.match(new Prefix(dstAddress.getAddress(), 32));
+ if (intf != null) {
+ sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
+ }
+ }
}
private void broadcastArpRequestOutEdge(byte[] arpRequest, long inSwitch, short inPort) {
@@ -394,6 +450,37 @@
}
}
+ private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
+ log.debug("Sending ARP request out {}/{}", HexString.toHexString(dpid), port);
+
+ OFPacketOut po = new OFPacketOut();
+ po.setInPort(OFPort.OFPP_NONE)
+ .setBufferId(-1)
+ .setPacketData(arpRequest);
+
+ List<OFAction> actions = new ArrayList<OFAction>();
+ actions.add(new OFActionOutput(port));
+ po.setActions(actions);
+ short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
+ po.setActionsLength(actionsLength);
+ po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
+ + arpRequest.length);
+
+ IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+
+ if (sw == null) {
+ log.debug("Switch not found when sending ARP request");
+ return;
+ }
+
+ try {
+ sw.write(po, null);
+ sw.flush();
+ } catch (IOException e) {
+ log.error("Failure writing packet out to switch", e);
+ }
+ }
+
public void sendArpReply(ARP arpRequest, long dpid, short port, byte[] targetMac) {
ARP arpReply = new ARP();
arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)