/*
* Copyright (c) 2013 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.sdnplatform.netvirt.virtualrouting.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import static org.easymock.EasyMock.*;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFType;
import org.openflow.protocol.OFPacketIn.OFPacketInReason;
import org.openflow.protocol.factory.BasicFactory;
import org.openflow.util.HexString;
import org.sdnplatform.core.ListenerContext;
import org.sdnplatform.core.IControllerService;
import org.sdnplatform.core.IOFSwitch;
import org.sdnplatform.core.module.ModuleContext;
import org.sdnplatform.core.test.MockControllerProvider;
import org.sdnplatform.core.test.MockThreadPoolService;
import org.sdnplatform.devicemanager.IDevice;
import org.sdnplatform.devicemanager.IDeviceService;
import org.sdnplatform.devicemanager.IEntityClassifierService;
import org.sdnplatform.devicemanager.internal.BetterDeviceManagerImpl;
import org.sdnplatform.devicemanager.internal.DefaultEntityClassifier;
import org.sdnplatform.devicemanager.test.MockDeviceManager;
import org.sdnplatform.flowcache.IFlowCacheService;
import org.sdnplatform.flowcache.IFlowReconcileService;
import org.sdnplatform.netvirt.core.VNS;
import org.sdnplatform.netvirt.core.VNSInterface;
import org.sdnplatform.netvirt.core.VNS.ARPMode;
import org.sdnplatform.netvirt.core.VNS.BroadcastMode;
import org.sdnplatform.netvirt.manager.INetVirtListener;
import org.sdnplatform.netvirt.manager.INetVirtManagerService;
import org.sdnplatform.netvirt.virtualrouting.IVirtualRoutingService;
import org.sdnplatform.netvirt.virtualrouting.internal.ArpManager;
import org.sdnplatform.netvirt.virtualrouting.internal.VirtualRouting;
import org.sdnplatform.packet.ARP;
import org.sdnplatform.packet.Ethernet;
import org.sdnplatform.packet.IPacket;
import org.sdnplatform.packet.IPv4;
import org.sdnplatform.restserver.IRestApiService;
import org.sdnplatform.restserver.RestApiServer;
import org.sdnplatform.routing.IRoutingDecision;
import org.sdnplatform.routing.IRoutingDecision.RoutingAction;
import org.sdnplatform.storage.IStorageSourceService;
import org.sdnplatform.storage.memory.MemoryStorageSource;
import org.sdnplatform.tagmanager.ITagManagerService;
import org.sdnplatform.test.PlatformTestCase;
import org.sdnplatform.threadpool.IThreadPoolService;
import org.sdnplatform.topology.ITopologyService;
import org.sdnplatform.topology.NodePortTuple;
import org.sdnplatform.tunnelmanager.ITunnelManagerService;
public class ArpManagerTest extends PlatformTestCase {
private INetVirtManagerService netVirtManager;
private MockDeviceManager mockDeviceManager;
private MemoryStorageSource storageSource;
private VirtualRouting virtualRouting;
ITopologyService topology;
ITunnelManagerService tunnelManager;
private ArpManager arpManager;
private BetterDeviceManagerImpl tagManager;
private ModuleContext fmc;
private IFlowReconcileService flowReconcileMgr;
private IFlowCacheService betterFlowCacheMgr;
protected static OFPacketIn packetInARPRequest;
protected static IPacket arprequestPacket;
protected static byte[] arpRequestSerialized;
protected static OFPacketIn packetInARPRequestUnicast;
protected static IPacket arprequestPacketUnicast;
protected static byte[] arpRequestUnicastSerialized;
protected static OFPacketIn packetInGratARP;
protected static IPacket gratARPPacket;
protected static byte[] gratARPSerialized;
static {
ARP request = new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REQUEST)
.setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
.setTargetHardwareAddress(Ethernet.toMACAddress("FF:FF:FF:FF:FF:FF"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"));
arprequestPacket = new Ethernet()
.setSourceMACAddress("00:44:33:22:11:00")
.setDestinationMACAddress("FF:FF:FF:FF:FF:FF")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(request);
arpRequestSerialized = arprequestPacket.serialize();
arprequestPacketUnicast = new Ethernet()
.setSourceMACAddress("00:44:33:22:11:00")
.setDestinationMACAddress("00:11:22:33:44:55")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(request);
arpRequestUnicastSerialized = arprequestPacketUnicast.serialize();
packetInARPRequest =
((OFPacketIn) (new BasicFactory()).getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(arpRequestSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) arpRequestSerialized.length);
packetInARPRequestUnicast =
((OFPacketIn) (new BasicFactory()).getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(arpRequestSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) arpRequestSerialized.length);
ARP gratARP = new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REQUEST)
.setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
.setTargetHardwareAddress(Ethernet.toMACAddress("FF:FF:FF:FF:FF:FF"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"));
gratARPPacket = new Ethernet()
.setSourceMACAddress("00:44:33:22:11:00")
.setDestinationMACAddress("FF:FF:FF:FF:FF:FF")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(gratARP);
gratARPSerialized = gratARPPacket.serialize();
packetInGratARP =
((OFPacketIn) (new BasicFactory()).getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(gratARPSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) gratARPSerialized.length);
}
protected static OFPacketIn packetInARPReply;
protected static IPacket arpreplyPacket;
protected static byte[] arpReplySerialized;
static {
arpreplyPacket = new Ethernet()
// Note: Ethernet src mac address is specifically set to be different
// from the sender hardware address. This is to test ARP responses
// in case of VRRP scenarios.
.setSourceMACAddress("00:AA:BB:CC:DD:EE")
.setDestinationMACAddress("00:44:33:22:11:00")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(
new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REPLY)
.setSenderHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2"))
.setTargetHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1")));
arpReplySerialized = arpreplyPacket.serialize();
packetInARPReply =
((OFPacketIn) (new BasicFactory()).getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(arpReplySerialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) arpReplySerialized.length);
}
protected VNS defaultNetVirt;
protected VNS newNetVirt;
@Before
public void setUp() throws Exception {
super.setUp();
storageSource = new MemoryStorageSource();
mockDeviceManager = new MockDeviceManager();
virtualRouting = new VirtualRouting();
tagManager = new BetterDeviceManagerImpl();
netVirtManager = createNiceMock(INetVirtManagerService.class);
flowReconcileMgr = createNiceMock(IFlowReconcileService.class);
DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
RestApiServer ras = new RestApiServer();
MockThreadPoolService tp = new MockThreadPoolService();
topology = createMock(ITopologyService.class);
tunnelManager = EasyMock.createMock(ITunnelManagerService.class);
betterFlowCacheMgr = createNiceMock(IFlowCacheService.class);
topology.addListener(mockDeviceManager);
expectLastCall().times(1);
topology.addListener(tagManager);
expectLastCall().times(1);
expect(topology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes();
replay(topology);
fmc = new ModuleContext();
fmc.addService(IControllerService.class,
mockControllerProvider);
fmc.addService(IStorageSourceService.class, storageSource);
fmc.addService(IDeviceService.class, mockDeviceManager);
fmc.addService(ITagManagerService.class, tagManager);
fmc.addService(IVirtualRoutingService.class, virtualRouting);
fmc.addService(INetVirtManagerService.class, netVirtManager);
fmc.addService(IRestApiService.class, ras);
fmc.addService(IThreadPoolService.class, tp);
fmc.addService(ITopologyService.class, topology);
fmc.addService(ITunnelManagerService.class, tunnelManager);
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
fmc.addService(IEntityClassifierService.class, entityClassifier);
fmc.addService(IFlowCacheService.class, betterFlowCacheMgr);
storageSource.init(fmc);
mockDeviceManager.init(fmc);
tagManager.init(fmc);
virtualRouting.init(fmc);
ras.init(fmc);
mockControllerProvider.init(fmc);
tp.init(fmc);
entityClassifier.init(fmc);
netVirtManager.addNetVirtListener((INetVirtListener)EasyMock.anyObject());
expectLastCall().anyTimes();
replay(netVirtManager);
storageSource.startUp(fmc);
mockDeviceManager.startUp(fmc);
tagManager.startUp(fmc);
virtualRouting.startUp(fmc);
ras.startUp(fmc);
mockControllerProvider.startUp(fmc);
tp.startUp(fmc);
entityClassifier.startUp(fmc);
arpManager = virtualRouting.getArpManager();
defaultNetVirt = new VNS("default");
newNetVirt = new VNS("new");
}
/**
* Assert that the OFMessage is a unicast ARP message with
* with the correct source and destination details.
* @param outmessage
*/
private void assertUnicastArp(OFMessage outmessage) {
assertNotNull(outmessage);
assertTrue(outmessage instanceof OFPacketIn);
OFPacketIn po = (OFPacketIn)outmessage;
Ethernet eth = new Ethernet();
eth.deserialize(po.getPacketData(), 0, po.getPacketData().length);
assertEquals("00:11:22:33:44:55",
HexString.toHexString(eth.getDestinationMACAddress()));
assertEquals("00:44:33:22:11:00",
HexString.toHexString(eth.getSourceMACAddress()));
assertTrue(eth.getPayload() instanceof ARP);
ARP arp = (ARP) eth.getPayload();
assertEquals(ARP.PROTO_TYPE_IP, arp.getProtocolType());
assertEquals(ARP.OP_REQUEST, arp.getOpCode());
assertEquals("00:44:33:22:11:00",
HexString.toHexString(arp.getSenderHardwareAddress()));
assertEquals("ff:ff:ff:ff:ff:ff",
HexString.toHexString(arp.getTargetHardwareAddress()));
}
/**
* Tests ARP manager's setting of flood if it does not know
* the Device location of where the ARP request should go.
*/
@Test
public void testARPFloodIfNotFound() throws Exception {
ArpManager am = getArpManager();
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.FLOOD_IF_UNKNOWN);
VirtualRouting vr = getVirtualRouting();
am.ARP_CACHE_DEFAULT_TIMEOUT_MS = 50;
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
Capture<OFMessage> writeCapture =
new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
IControllerService bcp =
createMock(IControllerService.class);
MockControllerProvider bp = getMockControllerProvider();
am.setControllerProvider(bcp);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).
andReturn(true).anyTimes();
expect(bcp.getSwitches()).andReturn(switches).anyTimes();
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
am.setControllerProvider(bcp);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
// Learn the source device.
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice src = mockDeviceManager.learnEntity(mac, null, ip, 1L, 1);
reset(netVirtManager);
expect(netVirtManager.getInterfaces(src)).andReturn(srcIfaces).anyTimes();
replay(netVirtManager, mockSwitch, bcp);
ListenerContext bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
// The packet is sent along the regular forwarding logic for flooding,
// thus, nothing gets written to the switch.
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
verify(netVirtManager, mockSwitch, bcp);
// Make sure the switch hasn't seen any new packets
assertFalse(writeCapture.hasCaptured());
// We should be flooding the ARP request here because we do not yet
// know where the target Device is
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD,
result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Now, we learn the destination device.
reset(netVirtManager);
expect(netVirtManager.getInterfaces(src)).andReturn(srcIfaces).anyTimes();
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
IDevice dst = mockDeviceManager.learnEntity(mac, null, ip, 1L, 2);
expect(netVirtManager.getInterfaces(dst)).andReturn(srcIfaces).anyTimes();
// Here the packet should be reinjected as a unicast ARP message.
// as we have learned the destination.
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
expect(tunnelManager.isTunnelEndpoint((IDevice)EasyMock.anyObject())).andReturn(false).anyTimes();
reset(topology);
expect(topology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes();
expect(topology.inSameL2Domain(1L, 1L, true)).andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort(1L, (short)1, 1L, (short)2, true)).andReturn(new NodePortTuple(1, 1)).anyTimes();
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyBoolean())).andReturn(false).anyTimes();
replay(netVirtManager, topology, tunnelManager);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
verify(netVirtManager, topology, mockSwitch, bcp);
assertTrue(writeCapture.hasCaptured());
// Assert that the re-injected packet is a unicast packet.
OFMessage outmessage = writeCapture.getValue();
assertUnicastArp(outmessage);
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Now, dispatch the outmessage we got from the previous step, to
// ensure that the unicast ARP is handled correctly.
// We should see FORWARD_OR_FLOOD as the action, and no new packets
// injected on the switch.
writeCapture.reset();
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, outmessage, bc);
verify(netVirtManager, mockSwitch, bcp);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD,
result.getRoutingAction());
assertFalse(writeCapture.hasCaptured());
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// If we send a broadcast ARP request, it should be converted to unicast
// ARP, as we are still within the ARP cache timeout threshold.
writeCapture.reset();
Thread.sleep(1+am.ARP_CACHE_DEFAULT_TIMEOUT_MS/2);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertTrue(writeCapture.hasCaptured());
outmessage = writeCapture.getValue();
assertUnicastArp(outmessage);
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Once the timeout has elapsed, the packet should be flooded. Thus,
// no unicast conversion should take place.
writeCapture.reset();
Thread.sleep(1+am.ARP_CACHE_DEFAULT_TIMEOUT_MS/2);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD,
result.getRoutingAction());
assertFalse(writeCapture.hasCaptured());
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Now, we send an ARP response so that the arp cache is cleared.
// Note that the eth src mac and the sender hardware address are
// different, thus we are testing if the ARP is handled correctly
// in the VRRP scenarios.
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPReply, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPReply, bc);
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// The destination device should now be reset, and we should start
// converting broadcast ARP to unicast ARP again.
writeCapture.reset();
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertTrue(writeCapture.hasCaptured());
outmessage = writeCapture.getValue();
assertUnicastArp(outmessage);
}
/**
* This test verifies that when config is set to DROP_IF_UNKNOWN,
* the behavior is correct.
* @throws Exception
*/
@Test
public void testARPDropIfUnknown() throws Exception {
ArpManager am = getArpManager();
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.DROP_IF_UNKNOWN);
VirtualRouting vr = getVirtualRouting();
am.ARP_CACHE_DEFAULT_TIMEOUT_MS = 50;
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
Capture<OFMessage> writeCapture =
new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
IControllerService bcp =
createMock(IControllerService.class);
MockControllerProvider bp = getMockControllerProvider();
am.setControllerProvider(bcp);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).
andReturn(true).anyTimes();
expect(bcp.getSwitches()).andReturn(switches).anyTimes();
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
am.setControllerProvider(bcp);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice src = mockDeviceManager.learnEntity(mac, null, ip, 1L, 1);
reset(netVirtManager);
expect(netVirtManager.getInterfaces(src)).andReturn(srcIfaces).anyTimes();
replay(netVirtManager, mockSwitch, bcp);
ListenerContext bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
verify(netVirtManager, mockSwitch, bcp);
assertFalse(writeCapture.hasCaptured());
reset(netVirtManager);
expect(netVirtManager.getInterfaces(src)).andReturn(srcIfaces).anyTimes();
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
IDevice dst = mockDeviceManager.learnEntity(mac, null, ip, 1L, 2);
expect(netVirtManager.getInterfaces(dst)).andReturn(srcIfaces).anyTimes();
// We should be flooding the ARP request here because we do not yet
// know where the target Device is
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
// Here the packet should be reinjected
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
expect(tunnelManager.isTunnelEndpoint((IDevice)EasyMock.anyObject())).andReturn(false).anyTimes();
reset(topology);
expect(topology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes();
expect(topology.inSameL2Domain(1L, 1L, true)).andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort(1L, (short)1, 1L, (short)2, true)).andReturn(new NodePortTuple(1, 1)).anyTimes();
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyBoolean())).andReturn(false).anyTimes();
replay(netVirtManager, topology, tunnelManager);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
verify(netVirtManager, topology, mockSwitch, bcp);
assertTrue(writeCapture.hasCaptured());
OFMessage outmessage = writeCapture.getValue();
assertNotNull(outmessage);
if (outmessage != null) {
assertTrue(outmessage instanceof OFPacketIn);
OFPacketIn po = (OFPacketIn)outmessage;
Ethernet eth = new Ethernet();
eth.deserialize(po.getPacketData(), 0, po.getPacketData().length);
assertEquals("00:11:22:33:44:55",
HexString.toHexString(eth.getDestinationMACAddress()));
assertEquals("00:44:33:22:11:00",
HexString.toHexString(eth.getSourceMACAddress()));
assertTrue(eth.getPayload() instanceof ARP);
ARP arp = (ARP) eth.getPayload();
assertEquals(ARP.PROTO_TYPE_IP, arp.getProtocolType());
assertEquals(ARP.OP_REQUEST, arp.getOpCode());
assertEquals("00:44:33:22:11:00",
HexString.toHexString(arp.getSenderHardwareAddress()));
assertEquals("ff:ff:ff:ff:ff:ff",
HexString.toHexString(arp.getTargetHardwareAddress()));
}
writeCapture.reset();
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, outmessage, bc);
verify(netVirtManager, mockSwitch, bcp);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
// The action should be strictly FORWARD as flood is not allowed
// under DROP_IF_UNKNOWN.
assertEquals(RoutingAction.FORWARD,
result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
assertFalse(writeCapture.hasCaptured());
// Wait and send the message again.
Thread.sleep(1+am.ARP_CACHE_DEFAULT_TIMEOUT_MS/2);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
// Wait and send the message again. should be dropped.
Thread.sleep(1+am.ARP_CACHE_DEFAULT_TIMEOUT_MS/2);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
// Wait and send the message again, still should be dropped.
Thread.sleep(1+am.ARP_CACHE_DEFAULT_TIMEOUT_MS);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
/**
* Tests ARP manager's conversion to unicast
*/
@Test
public void testARPUnicast() throws Exception {
ArpManager am = getArpManager();
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
List<VNSInterface> dstIfaces = new ArrayList<VNSInterface>();
dstIfaces.add(new VNSInterface("defaultDstIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.FLOOD_IF_UNKNOWN);
VirtualRouting vr = getVirtualRouting();
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(11L).anyTimes();
Capture<OFMessage> writeCapture =
new Capture<OFMessage>(CaptureType.ALL);
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
IControllerService bcp =
createMock(IControllerService.class);
MockControllerProvider bp = getMockControllerProvider();
am.setControllerProvider(bcp);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).
andReturn(true).times(1);
expect(bcp.getSwitches()).andReturn(switches).anyTimes();
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
am.setControllerProvider(bcp);
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice src = mockDeviceManager.learnEntity(mac, null, ip, 11L, 1);
ListenerContext bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
mockDeviceManager.learnEntity(mac, null, ip, 11L, 2);
reset(netVirtManager);
expect(netVirtManager.getInterfaces((IDevice)EasyMock.anyObject()))
.andAnswer(new IAnswer<List<VNSInterface>>() {
@Override
public List<VNSInterface> answer() throws Throwable {
IDevice d = (IDevice)EasyMock.getCurrentArguments()[0];
long srcMac = HexString.toLong("00:44:33:22:11:00");
long dstMac = HexString.toLong("00:11:22:33:44:55");
if (d.getMACAddress() == srcMac) {
List<VNSInterface> srcIfaces =
new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface(
"defaultSrcIface1", defaultNetVirt, null, null));
return srcIfaces;
} else if (d.getMACAddress() == dstMac) {
List<VNSInterface> dstIfaces =
new ArrayList<VNSInterface>();
dstIfaces.add(new VNSInterface(
"defaultDstIface1", defaultNetVirt, null, null));
return dstIfaces;
} else {
return null;
}
}
}).times(3);
expect(tunnelManager.isTunnelEndpoint((IDevice)EasyMock.anyObject())).andReturn(false).anyTimes();
reset(topology);
expect(topology.inSameL2Domain(11L, 11L, true)).andReturn(true).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort(11L, (short)1, 11L, (short)2, true)).andReturn(new NodePortTuple(11, 1)).anyTimes();
expect(topology.isConsistent(11L, (short)1, 11L, (short)1, true)).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyBoolean())).andReturn(true).anyTimes();
replay(netVirtManager, tunnelManager, topology, mockSwitch, bcp);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_DST_IFACES, dstIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
// The original broadcast packet would be dropped.
assertEquals(RoutingAction.NONE, result.getRoutingAction());
verify(netVirtManager, mockSwitch, bcp, topology);
assertTrue(writeCapture.hasCaptured());
OFPacketIn pi = (OFPacketIn)writeCapture.getValue();
Ethernet eth = new Ethernet();
eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length);
// Make sure the destination MAC is not FF
assertEquals(mac, eth.getDestinationMAC().toLong());
// Re do the same test, except this time every switch port is
// treated as an internal port. Thus, conversion should always work.
reset(topology);
expect(topology.inSameL2Domain(11L, 11L, true)).andReturn(true).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort(11L, (short)1, 11L, (short)2, true)).andReturn(new NodePortTuple(11, 1)).anyTimes();
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort(), EasyMock.anyBoolean())).andReturn(false).anyTimes();
replay(topology);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_DST_IFACES, dstIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
// The original broadcast packet would be dropped.
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
verify(netVirtManager, mockSwitch, bcp, topology);
assertTrue(writeCapture.hasCaptured());
pi = (OFPacketIn)writeCapture.getValue();
eth = new Ethernet();
eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length);
// Make sure the destination MAC is not FF
assertEquals(mac, eth.getDestinationMAC().toLong());
}
/**
* Tests NO ARP unicast conversion for PI from non-AP switch port
*/
@Test
public void testARPSkipUnicastNonTrueAP() throws Exception {
ArpManager am = getArpManager();
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
List<VNSInterface> dstIfaces = new ArrayList<VNSInterface>();
dstIfaces.add(new VNSInterface("defaultDstIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.FLOOD_IF_UNKNOWN);
VirtualRouting vr = getVirtualRouting();
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(12L).anyTimes();
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
IControllerService bcp =
createMock(IControllerService.class);
MockControllerProvider bp = getMockControllerProvider();
am.setControllerProvider(bcp);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.getSwitches()).andReturn(switches).anyTimes();
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
am.setControllerProvider(bcp);
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice src = mockDeviceManager.learnEntity(mac, null, ip, 11L, 1);
ListenerContext bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
mockDeviceManager.learnEntity(mac, null, ip, 11L, 2);
reset(netVirtManager);
expect(netVirtManager.getInterfaces((IDevice)EasyMock.anyObject()))
.andAnswer(new IAnswer<List<VNSInterface>>() {
@Override
public List<VNSInterface> answer() throws Throwable {
IDevice d = (IDevice)EasyMock.getCurrentArguments()[0];
long srcMac = HexString.toLong("00:44:33:22:11:00");
long dstMac = HexString.toLong("00:11:22:33:44:55");
if (d.getMACAddress() == srcMac) {
List<VNSInterface> srcIfaces =
new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface(
"defaultSrcIface1", defaultNetVirt, null, null));
return srcIfaces;
} else if (d.getMACAddress() == dstMac) {
List<VNSInterface> dstIfaces =
new ArrayList<VNSInterface>();
dstIfaces.add(new VNSInterface(
"defaultDstIface1", defaultNetVirt, null, null));
return dstIfaces;
} else {
return null;
}
}
}).times(2);
expect(tunnelManager.isTunnelEndpoint((IDevice)EasyMock.anyObject())).andReturn(false).anyTimes();
// The packet-in switch port is not the one allowed for unicast
// transmission. So, ensure the test fails.
reset(topology);
expect(topology.isAttachmentPointPort(anyLong(), anyShort())).andReturn(true).anyTimes();
expect(topology.getL2DomainId(anyLong())).andReturn(1L).anyTimes();
expect(topology.inSameL2Domain(12L, 11L, true)).andReturn(true).anyTimes();
expect(topology.isConsistent(11L, (short)1, 12L, (short)1, true)).andReturn(true).anyTimes();
expect(topology.isConsistent(12L, (short)1, 11L, (short)2, true)).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(12L, (short)1, true)).andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort(12L, (short)1, 11L, (short)2, true)).andReturn(new NodePortTuple(12, 4)).anyTimes();
replay(netVirtManager, tunnelManager, topology, mockSwitch, bcp);
bc = new ListenerContext();
parseAndAnnotate(bc, packetInARPRequest, src, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_DST_IFACES, dstIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc,
IRoutingDecision.CONTEXT_DECISION);
verify(netVirtManager, mockSwitch, bcp, topology);
// The original broadcast packet would be dropped.
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
@Test
public void testARPReply() {
VirtualRouting vr = getVirtualRouting();
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice dst = mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
IDevice src = mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
IOFSwitch mockSwitch = createStrictMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
mockControllerProvider.setSwitches(switches);
MockControllerProvider bp = getMockControllerProvider();
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(mockSwitch);
ListenerContext bc = new ListenerContext();
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
parseAndAnnotate(bc, packetInARPReply, src, dst);
bp.dispatchMessage(mockSwitch, packetInARPReply, bc);
verify(mockSwitch);
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
/**
* Tests ARP manager's setting where it drops the ARP request
* if the device location of where the ARP should go is not
* known.
*/
@Test
public void testARPDropIfNotFound() throws Exception {
ArpManager am = getArpManager();
VirtualRouting vr = getVirtualRouting();
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice d = mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.DROP_IF_UNKNOWN);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
Capture<OFMessage> writeCapture =
new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
HashMap<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, mockSwitch);
mockControllerProvider.setSwitches(switches);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
MockControllerProvider bp = getMockControllerProvider();
IControllerService bcp =
createMock(IControllerService.class);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).
andReturn(true).anyTimes();
am.setControllerProvider(bcp);
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(mockSwitch, bcp);
ListenerContext bc =
parseAndAnnotate(packetInARPRequest, d, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
verify(mockSwitch, bcp);
assertFalse(writeCapture.hasCaptured());
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
/**
* Test ARP manager's 'disabled' setting.
* Flood all ARP requests like normal.
*/
@Test
public void testARPAlwaysFlood() throws Exception {
ArpManager am = getArpManager();
VirtualRouting vr = getVirtualRouting();
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice srcDevice = mockDeviceManager.learnEntity(mac, null, ip, null, null);
reset(netVirtManager);
expect(netVirtManager.getInterfaces(srcDevice)).andReturn(srcIfaces).times(2);
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
IDevice dstDevice = mockDeviceManager.learnEntity(mac, null, ip, null, null);
expect(netVirtManager.getInterfaces(dstDevice)).andReturn(srcIfaces).times(1);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
Capture<OFMessage> writeCapture =
new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
MockControllerProvider bp = getMockControllerProvider();
IControllerService bcp =
createMock(IControllerService.class);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).
andReturn(true).anyTimes();
am.setControllerProvider(bcp);
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(netVirtManager, mockSwitch, bcp);
ListenerContext bc = parseAndAnnotate(packetInARPRequest, srcDevice, dstDevice);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_DST_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
verify(netVirtManager, mockSwitch, bcp);
assertFalse(writeCapture.hasCaptured());
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
/**
* Test that ARPManager drops ARP requests to devices not in the same
* NetVirt as the source device.
*/
@Test
public void testARPDifferentNetVirt() throws Exception {
ArpManager am = getArpManager();
VirtualRouting vr = getVirtualRouting();
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
List<VNSInterface> dstIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("newDstIface1", newNetVirt, null, null));
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice srcDevice = mockDeviceManager.learnEntity(mac, null, ip, null, null);
reset(netVirtManager);
expect(netVirtManager.getInterfaces(srcDevice)).andReturn(srcIfaces).times(1);
mac = HexString.toLong("00:11:22:33:44:55");
ip = IPv4.toIPv4Address("192.168.1.2");
IDevice dstDevice = mockDeviceManager.learnEntity(mac, null, ip, 1L, 1);
expect(netVirtManager.getInterfaces(dstDevice)).andReturn(dstIfaces).times(1);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
Capture<OFMessage> writeCapture =
new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
expect(mockSwitch.getId()).andReturn(1L).times(1);
MockControllerProvider bp = getMockControllerProvider();
IControllerService bcp =
createMock(IControllerService.class);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).
andReturn(true).anyTimes();
am.setControllerProvider(bcp);
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(netVirtManager, mockSwitch, bcp);
ListenerContext bc = parseAndAnnotate(packetInARPRequest, srcDevice, dstDevice);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_DST_IFACES, dstIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
verify(netVirtManager, mockSwitch, bcp);
assertFalse(writeCapture.hasCaptured());
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
/**
* Test Gratuitous ARP processing.
*/
@Test
public void testGratARP() throws Exception {
ArpManager am = getArpManager();
MockDeviceManager dm = getMockDeviceManager();
reset(topology);
topology.addListener(dm);
expectLastCall().times(1);
replay(topology);
dm.startUp(null);
VirtualRouting vr = getVirtualRouting();
vr.setDeviceManager(dm);
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice d = mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.ALWAYS_FLOOD);
defaultNetVirt.setBroadcastMode(BroadcastMode.FORWARD_TO_KNOWN);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
Capture<OFMessage> writeCapture = new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
MockControllerProvider bp = getMockControllerProvider();
IControllerService bcp = createMock(IControllerService.class);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).andReturn(true).
anyTimes();
am.setControllerProvider(bcp);
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(mockSwitch, bcp);
ListenerContext bc = parseAndAnnotate(packetInGratARP, d, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInGratARP, bc);
verify(mockSwitch, bcp);
assertFalse(writeCapture.hasCaptured());
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.MULTICAST, result.getRoutingAction());
}
/**
* Test ARP on cluster without AP.
* @throws Exception
*/
@Test
public void testBroadcastARPonClusterWithoutAP() throws Exception {
ArpManager am = getArpManager();
MockDeviceManager dm = getMockDeviceManager();
reset(topology);
topology.addListener(dm);
expectLastCall().times(1);
replay(topology);
dm.startUp(null);
VirtualRouting vr = getVirtualRouting();
vr.setDeviceManager(dm);
long mac = HexString.toLong("00:44:33:22:11:00");
int ip = IPv4.toIPv4Address("192.168.1.1");
IDevice srcDev =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>();
srcIfaces.add(new VNSInterface("defaultSrcIface1", defaultNetVirt, null, null));
defaultNetVirt.setArpManagerMode(ARPMode.ALWAYS_FLOOD);
defaultNetVirt.setBroadcastMode(BroadcastMode.FORWARD_TO_KNOWN);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
Capture<OFMessage> writeCapture = new Capture<OFMessage>(CaptureType.ALL);
Capture<ListenerContext> contextCapture =
new Capture<ListenerContext>(CaptureType.ALL);
mockSwitch.write(capture(writeCapture), capture(contextCapture));
expectLastCall().anyTimes();
MockControllerProvider bp = getMockControllerProvider();
IControllerService bcp =
createMock(IControllerService.class);
expect(bcp.getOFMessageFactory()).
andReturn(bp.getOFMessageFactory()).anyTimes();
expect(bcp.injectOfMessage(eq(mockSwitch),
capture(writeCapture))).andReturn(true).
anyTimes();
am.setControllerProvider(bcp);
bp.clearListeners();
bp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(mockSwitch, bcp);
ListenerContext bc =
parseAndAnnotate(packetInARPRequest, srcDev, null);
INetVirtManagerService.bcStore.put(bc, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces);
bp.dispatchMessage(mockSwitch, packetInARPRequest, bc);
verify(mockSwitch, bcp);
assertFalse(writeCapture.hasCaptured());
IRoutingDecision result =
IRoutingDecision.rtStore.get(bc, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, result.getRoutingAction());
assertEquals(ArpManager.ARP_FLOWMOD_HARD_TIMEOUT,
result.getHardTimeout());
}
protected ArpManager getArpManager() {
return arpManager;
}
protected MockDeviceManager getMockDeviceManager() {
return mockDeviceManager;
}
protected VirtualRouting getVirtualRouting() {
return virtualRouting;
}
protected INetVirtManagerService getNetVirtManager() {
return netVirtManager;
}
protected IStorageSourceService getStorageSource() {
return storageSource;
}
}