/*
* 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 static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketIn.OFPacketInReason;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFType;
import org.openflow.util.HexString;
import org.sdnplatform.core.ListenerContext;
import org.sdnplatform.core.IControllerService;
import org.sdnplatform.core.IOFMessageListener;
import org.sdnplatform.core.IOFSwitch;
import org.sdnplatform.core.IListener.Command;
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.linkdiscovery.ILinkDiscoveryService;
import org.sdnplatform.linkdiscovery.internal.LinkDiscoveryManager;
import org.sdnplatform.netvirt.core.VNSInterface;
import org.sdnplatform.netvirt.core.VNS.DHCPMode;
import org.sdnplatform.netvirt.manager.INetVirtManagerService;
import org.sdnplatform.netvirt.manager.internal.NetVirtManagerImpl;
import org.sdnplatform.netvirt.virtualrouting.IVirtualRoutingService;
import org.sdnplatform.netvirt.virtualrouting.internal.DhcpManager;
import org.sdnplatform.netvirt.virtualrouting.internal.VirtualRouting;
import org.sdnplatform.packet.DHCP;
import org.sdnplatform.packet.DHCPOption;
import org.sdnplatform.packet.Ethernet;
import org.sdnplatform.packet.IPacket;
import org.sdnplatform.packet.IPv4;
import org.sdnplatform.packet.UDP;
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.tunnelmanager.ITunnelManagerService;
public class DhcpManagerTest extends PlatformTestCase {
private NetVirtManagerImpl netVirtManager;
private MockDeviceManager mockDeviceManager;
private MemoryStorageSource storageSource;
private VirtualRouting virtualRouting;
private DhcpManager dhcpManager;
private BetterDeviceManagerImpl tagManager;
private LinkDiscoveryManager linkDiscovery;
private ModuleContext fmc;
private ITopologyService topology;
private IFlowReconcileService flowReconcileMgr;
private IFlowCacheService betterFlowCacheMgr;
private ITunnelManagerService tunnelManager;
// DHCP Discovery Request/Reply
protected OFPacketIn packetInDHCPDiscoveryRequest;
protected OFPacketIn packetInDHCPDiscoveryRequestUnicast;
protected OFPacketIn packetInDHCPDiscoveryReply;
protected OFPacketIn packetInDHCPDiscoveryRoqueReply;
protected OFPacketIn packetInDHCPDiscoveryBroadcastReply;
// DHCP Discovery Request/ACK
protected OFPacketIn packetInDHCPRequestRequest;
protected OFPacketIn packetInDHCPRequestAck;
// Static MAC and IP assignments
protected String hostMac = "00:0b:82:01:fc:42";
protected String hostIp = "192.168.0.10";
protected String altHostMac = "00:0b:82:01:fc:43";
protected String altHostIp = "192.168.0.11";
protected String dhcpMac = "00:08:74:ad:f1:9b";
protected String roqueDhcpMac = "00:08:74:ad:f1:9a";
protected String dhcpIp = "192.168.0.1";
protected String roqueDhcpIp = "192.168.0.3";
protected String hostSubnetMask = "255.255.255.0";
protected String broadcastMac = "ff:ff:ff:ff:ff:ff";
protected String broadcastIp = "255.255.255.255";
public class MessageCapture implements IOFMessageListener {
protected List<IOFSwitch> switches;
protected List<OFMessage> messages;
protected List<ListenerContext> contexts;
public MessageCapture() {
switches = new ArrayList<IOFSwitch>();
messages = new ArrayList<OFMessage>();
contexts = new ArrayList<ListenerContext>();
}
public void assertOneMessageAndReset() {
assertEquals(1, switches.size());
assertEquals(1, messages.size());
assertEquals(1, contexts.size());
reset();
}
public void reset() {
switches.clear();
messages.clear();
contexts.clear();
}
@Override
public String getName() {
return this.getClass().getName();
}
@Override
public boolean isCallbackOrderingPrereq(OFType type, String name) {
return false;
}
@Override
public boolean isCallbackOrderingPostreq(OFType type, String name) {
// We want to be the first listener.
if (!name.equals(getName()))
return true;
return false;
}
@Override
public Command
receive(IOFSwitch sw, OFMessage msg, ListenerContext cntx) {
switches.add(sw);
messages.add(msg);
contexts.add(cntx);
return Command.CONTINUE;
}
// Getters
public List<IOFSwitch> getSwitches() {
return switches;
}
public List<OFMessage> getMessages() {
return messages;
}
public List<ListenerContext> getContexts() {
return contexts;
}
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
storageSource = new MemoryStorageSource();
mockDeviceManager = new MockDeviceManager();
virtualRouting = new VirtualRouting();
tagManager = new BetterDeviceManagerImpl();
netVirtManager = new NetVirtManagerImpl();
tunnelManager = createMock(ITunnelManagerService.class);
topology = createNiceMock(ITopologyService.class);
RestApiServer ras = new RestApiServer();
MockThreadPoolService tp = new MockThreadPoolService();
linkDiscovery = new LinkDiscoveryManager();
flowReconcileMgr = createNiceMock(IFlowReconcileService.class);
DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
betterFlowCacheMgr = createNiceMock(IFlowCacheService.class);
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(ILinkDiscoveryService.class, linkDiscovery);
fmc.addService(IRestApiService.class, ras);
fmc.addService(IThreadPoolService.class, tp);
fmc.addService(ITopologyService.class, topology);
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
fmc.addService(IEntityClassifierService.class, entityClassifier);
fmc.addService(IFlowCacheService.class, betterFlowCacheMgr);
fmc.addService(ITunnelManagerService.class, tunnelManager);
replay(topology);
storageSource.init(fmc);
linkDiscovery.init(fmc);
mockDeviceManager.init(fmc);
tagManager.init(fmc);
virtualRouting.init(fmc);
netVirtManager.init(fmc);
ras.init(fmc);
mockControllerProvider.init(fmc);
tp.init(fmc);
entityClassifier.init(fmc);
storageSource.startUp(fmc);
linkDiscovery.startUp(fmc);
mockDeviceManager.startUp(fmc);
tagManager.startUp(fmc);
virtualRouting.startUp(fmc);
netVirtManager.startUp(fmc);
ras.startUp(fmc);
mockControllerProvider.startUp(fmc);
tp.startUp(fmc);
entityClassifier.startUp(fmc);
dhcpManager = virtualRouting.getDhcpManager();
initDiscoveryRequestPacket();
initDiscoveryRequestPacketUnicast();
initDiscoveryReplyPacket();
initDiscoveryRoqueReplyPacket();
initDiscoveryBroadcastReplyPacket();
initRequestRequestPacket();
initRequestAckPacket();
resetToNice(topology);
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes();
expect(tunnelManager.isTunnelEndpoint(anyObject(IDevice.class)))
.andReturn(false).anyTimes();
replay(tunnelManager);
}
/** Test cases when there's no NetVirt or no source device in the context
* (which really shouldn't happen)
*/
@Test
public void testNoNetVirtNoDevice() {
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
DhcpManager dhcpManager = new DhcpManager();
dhcpManager.init();
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
replay(mockSwitch);
// no source device
ListenerContext cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest,
null, null);
assertEquals(Command.STOP,
dhcpManager.receive(mockSwitch,
packetInDHCPDiscoveryRequest, cntx));
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
// no NetVirt
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest, host, null);
assertEquals(Command.STOP,
dhcpManager.receive(mockSwitch,
packetInDHCPDiscoveryRequest, cntx));
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
}
/**
* Test that we correctly punt on non DHCP packets or when the source
* device is missing
*
*/
@Test
public void testNonDhcpPacket() {
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
DhcpManager dhcpManager = new DhcpManager();
dhcpManager.init();
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
replay(mockSwitch, topology);
// a UDP packet (with DHCP payload but wrong port)
OFPacketIn packetIn = newNonDhcpPacket(true, true);
ListenerContext cntx = parseAndAnnotate(packetIn, host, null);
assertEquals(Command.CONTINUE,
dhcpManager.receive(mockSwitch, packetIn, cntx));
IRoutingDecision res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertNull(res);
// An non-UDP packet
packetIn = newNonDhcpPacket(true, false);
cntx = parseAndAnnotate(packetIn, host, null);
assertEquals(Command.CONTINUE,
dhcpManager.receive(mockSwitch, packetIn, cntx));
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertNull(res);
// An non-UDP packet
packetIn = newNonDhcpPacket(false, false);
cntx = parseAndAnnotate(packetIn, host, null);
assertEquals(Command.CONTINUE,
dhcpManager.receive(mockSwitch, packetIn, cntx));
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertNull(res);
}
/**
* Tests the ALWAYS_FLOOD (disabled) DHCP Manager setting.
* We should just flood the packet.
* @throws IOException
*/
@Test
public void testDhcpManagerAlwaysFlood() throws IOException {
NetVirtManagerImpl netVirtManager = getNetVirtManager();
VirtualRouting vr = getVirtualRouting();
DhcpManager dhcpManager = getDhcpManager();
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.ALWAYS_FLOOD);
}
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
replay(mockSwitch, topology);
MockControllerProvider flp = getMockControllerProvider();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, vr);
flp.addOFMessageListener(OFType.PACKET_IN, dhcpManager);
ListenerContext cntx =
parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
cntx = parseAndAnnotate(packetInDHCPRequestRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPRequestRequest, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
cntx = parseAndAnnotate(packetInDHCPRequestAck);
flp.dispatchMessage(mockSwitch, packetInDHCPRequestAck, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
verify(mockSwitch);
}
/**
* Tests that we have snooped a DHCP server and unicast
* other DHCP requests.
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testFloodIfUnknown() throws IOException, InterruptedException {
NetVirtManagerImpl netVirtManager = getNetVirtManager();
VirtualRouting vr = getVirtualRouting();
// Set timeout to low value
vr.dhcpManager.UNICAST_CONV_TIMEOUT = 30;
vr.dhcpManager.init();
// Learn devices
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(altHostMac);
ip = IPv4.toIPv4Address(altHostIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
// Configure DHCP mode
// All hosts are in the default NetVirt so its fine if we just set the
// mode once.
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.FLOOD_IF_UNKNOWN);
break;
}
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
MockControllerProvider flp = getMockControllerProvider();
flp.clearListeners();
MessageCapture msgCapture = new MessageCapture();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, vr);
replay(mockSwitch, topology);
// Send first request. Nothing snooped yet so we expect a flood.
ListenerContext cntx =
parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
msgCapture.assertOneMessageAndReset();
// Send the reply. Now we will snoop the server
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
msgCapture.assertOneMessageAndReset();
reset(mockSwitch, topology);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
replay(mockSwitch, topology);
// The DHCP server should have been learned by now
// Next request should be converted to unicast
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
// Note that the unicast packet is reinjected. We therefore expect
// a routing decision of NONE and we check that unicast packet
// was indeed injected (by checking the captured calls to our
// OFMessageListener)
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
// Expect two captures messaged. First is the original broadcast, second
// is the reinjected unicast.
assertEquals(2, msgCapture.getMessages().size());
ListenerContext injectedContext = msgCapture.getContexts().get(1);
Ethernet injectedEth = IControllerService.bcStore.
get(injectedContext, IControllerService.CONTEXT_PI_PAYLOAD);
OFPacketIn injectedMessage = (OFPacketIn)msgCapture.getMessages().get(1);
assertEquals(dhcpMac,
HexString.toHexString(
injectedEth.getDestinationMACAddress()));
assertArrayEquals(injectedMessage.getPacketData(),
injectedEth.serialize());
msgCapture.reset();
// We are within the unicast timeout so we should convert again
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
assertEquals(2, msgCapture.getMessages().size());
msgCapture.reset();
// Should be back to broadcast since no reply to last request
Thread.sleep(35);
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
Ethernet eth =
IControllerService.bcStore.
get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
assertEquals(broadcastMac,
HexString.toHexString(eth.getDestinationMACAddress()));
assertEquals(1, msgCapture.getMessages().size());
msgCapture.reset();
// Send the reply again. To refresh the server state and remove pending
// request state
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
msgCapture.assertOneMessageAndReset();
// Send a packet from a different client host and verify that it's
// converted to unicast
OFPacketIn altHostPacketnDHCPDiscoverRequest =
newDiscoveryRequest(altHostMac, broadcastMac);
msgCapture.reset();
cntx = parseAndAnnotate(altHostPacketnDHCPDiscoverRequest);
flp.dispatchMessage(mockSwitch, altHostPacketnDHCPDiscoverRequest, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
assertEquals(2, msgCapture.getMessages().size());
injectedContext = msgCapture.getContexts().get(1);
injectedEth = IControllerService.bcStore.
get(injectedContext, IControllerService.CONTEXT_PI_PAYLOAD);
injectedMessage = (OFPacketIn)msgCapture.getMessages().get(1);
assertEquals(dhcpMac, HexString.toHexString(
injectedEth.getDestinationMACAddress()));
assertArrayEquals(injectedMessage.getPacketData(),
injectedEth.serialize());
msgCapture.reset();
// wait for timeout to expire.
Thread.sleep(35);
// Now send a request from the first host. This host does not have
// a pending request but the server has an unanswered pending request.
// Thus we should flood.
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
eth = IControllerService.bcStore.
get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
assertEquals(broadcastMac,
HexString.toHexString(eth.getDestinationMACAddress()));
assertEquals(1, msgCapture.getMessages().size());
msgCapture.reset();
verify(mockSwitch);
}
/**
* Tests handling of the reinjected unicast packet
* @throws IOException
*/
@Test
public void testDhcpManagerUnicast() throws IOException {
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host = mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
// Do not learn about the destination (DHCP server) at this stage
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
MockControllerProvider flp = getMockControllerProvider();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, getVirtualRouting());
replay(mockSwitch, topology);
//-----------------
// TEST with unknown destination device
//-----------------
// No dest device and flood if unknown ==> flood
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.FLOOD_IF_UNKNOWN);
}
ListenerContext cntx =
parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
// Always Flood ==> flood packet.
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.ALWAYS_FLOOD);
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
// static ==> ignore packet
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
verify(mockSwitch, topology);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
//-----------------
// TEST with known destination device.
//-----------------
// flood if unknown ==> forward
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.FLOOD_IF_UNKNOWN);
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
// Always Flood ==> still forward packet as is
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.ALWAYS_FLOOD);
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
// static with correct DHCP-server ==> forward packet
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
// static with in-correct DHCP-server ==> forward packet (because it's
// an request we will allow it. Could also drop it. )
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(roqueDhcpIp));
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequestUnicast);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequestUnicast, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
verify(mockSwitch, topology);
}
/**
* Tests static DHCP configuration. We should convert
* all broadcast requests to unicast.
* @throws IOException
*/
@Test
public void testDhcpManagerStatic() throws IOException {
NetVirtManagerImpl netVirtManager = getNetVirtManager();
VirtualRouting vr = getVirtualRouting();
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
expect(mockSwitch.hasAttribute("isCoreSwitch")).andReturn(false);
replay(mockSwitch, topology);
MockControllerProvider flp = getMockControllerProvider();
MessageCapture msgCapture = new MessageCapture();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, vr);
// send request
ListenerContext cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
assertEquals(2, msgCapture.getMessages().size());
ListenerContext injectedContext = msgCapture.getContexts().get(1);
Ethernet injectedEth = IControllerService.bcStore.
get(injectedContext, IControllerService.CONTEXT_PI_PAYLOAD);
OFPacketIn injectedMessage = (OFPacketIn)msgCapture.getMessages().get(1);
assertEquals(dhcpMac,
HexString.toHexString(
injectedEth.getDestinationMACAddress()));
assertArrayEquals(injectedMessage.getPacketData(),
injectedEth.serialize());
msgCapture.reset();
// send reply
Ethernet eth =
IControllerService.bcStore
.get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
assertEquals(dhcpMac,
HexString.toHexString(eth.getDestinationMACAddress()));
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
assertEquals(1, msgCapture.getMessages().size());
msgCapture.reset();
}
/**
* Tests static DHCP configuration when we can't find the server.
* Request should be simply ignored
* @throws IOException
*/
@Test
public void testDhcpManagerStaticNoServer() throws IOException {
NetVirtManagerImpl netVirtManager = getNetVirtManager();
VirtualRouting vr = getVirtualRouting();
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(dhcpMac);
// do not learn server's IP
mockDeviceManager.learnEntity(mac, null, null, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
expect(mockSwitch.hasAttribute("isCoreSwitch")).andReturn(false);
replay(mockSwitch, topology);
MockControllerProvider flp = getMockControllerProvider();
MessageCapture msgCapture = new MessageCapture();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, vr);
// send request
ListenerContext cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
assertEquals(1, msgCapture.getMessages().size());
assertSame(cntx, msgCapture.getContexts().get(0));
Ethernet eth = IControllerService.bcStore.
get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
assertEquals(broadcastMac,
HexString.toHexString(eth.getDestinationMACAddress()));
}
/**
* Tests static DHCP configuration. A DHCP reply from an un-authorized server
* should be dropped.
* @throws IOException
*/
@Test
public void testDhcpManagerStaticNegative() throws IOException {
NetVirtManagerImpl netVirtManager = getNetVirtManager();
VirtualRouting vr = getVirtualRouting();
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
expect(mockSwitch.hasAttribute("isCoreSwitch")).andReturn(false);
replay(mockSwitch, topology);
MockControllerProvider flp = getMockControllerProvider();
MessageCapture msgCapture = new MessageCapture();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, vr);
// send request
ListenerContext cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
assertEquals(2, msgCapture.getMessages().size());
ListenerContext injectedContext = msgCapture.getContexts().get(1);
Ethernet injectedEth = IControllerService.bcStore.
get(injectedContext, IControllerService.CONTEXT_PI_PAYLOAD);
OFPacketIn injectedMessage = (OFPacketIn)msgCapture.getMessages().get(1);
assertEquals(dhcpMac,
HexString.toHexString(
injectedEth.getDestinationMACAddress()));
assertArrayEquals(injectedMessage.getPacketData(),
injectedEth.serialize());
msgCapture.reset();
Ethernet eth =
IControllerService.bcStore
.get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
assertEquals(dhcpMac,
HexString.toHexString(eth.getDestinationMACAddress()));
// send reply
cntx = parseAndAnnotate(packetInDHCPDiscoveryRoqueReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRoqueReply, cntx);
res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.DROP, res.getRoutingAction());
assertEquals(1, msgCapture.getMessages().size());
msgCapture.reset();
}
/**
* Test all DHCP modes with a broadcast reply packet.
* @throws IOException
*/
@Test
public void testDhcpManagerBroadcastReplies() throws IOException {
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host = mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
mockDeviceManager.learnEntity(mac, null, ip, null, null);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
MockControllerProvider flp = getMockControllerProvider();
MessageCapture msgCapture = new MessageCapture();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, getVirtualRouting());
replay(mockSwitch, topology);
// FLOOD-IF-UNKNOWN
// We expect the packet to be flooded. We might be able to convert
// to unicast though. Need to take a closer look at the DHCP protocol
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.FLOOD_IF_UNKNOWN);
}
ListenerContext cntx =
parseAndAnnotate(packetInDHCPDiscoveryBroadcastReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryBroadcastReply,
cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
msgCapture.assertOneMessageAndReset();
// Always Flood ==> flood packet.
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.ALWAYS_FLOOD);
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryBroadcastReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryBroadcastReply,
cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
msgCapture.assertOneMessageAndReset();
// static
// This is very tricky. We currently flood. We could potentially
// convert to unicast but we need to take a closer look at the
// packet. But ultimately the problem is that the server decided
// to flood although it (presumably) knew about the client.
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryBroadcastReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryBroadcastReply,
cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
msgCapture.assertOneMessageAndReset();
}
/**
* Test all DHCP modes with a unicast reply packet with an unknown
* destination (client host)
* @throws IOException
*/
@Test
public void testDhcpManagerUnicastNoDeviceReply() throws IOException {
long mac = HexString.toLong(dhcpMac);
int ip = IPv4.toIPv4Address(dhcpIp);
IDevice dhcpDevice =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
List<VNSInterface> ifaces = netVirtManager.getInterfaces(dhcpDevice);
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
MockControllerProvider flp = getMockControllerProvider();
MessageCapture msgCapture = new MessageCapture();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, getVirtualRouting());
replay(mockSwitch, topology);
// FLOOD-IF-UNKNOWN ==> Flood
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.FLOOD_IF_UNKNOWN);
}
ListenerContext cntx =
parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply,
cntx);
IRoutingDecision res =
IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
msgCapture.assertOneMessageAndReset();
// Always Flood ==> flood packet.
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.ALWAYS_FLOOD);
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply,
cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
msgCapture.assertOneMessageAndReset();
// static ==> ignore (no drop flow)
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.STATIC);
iface.getParentVNS().setDhcpIp(IPv4.toIPv4Address(dhcpIp));
}
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply,
cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
msgCapture.assertOneMessageAndReset();
}
/** Heloer for callDeviceListener
*/
enum DeviceListenerToCall {
DEVICE_ADDED,
DEVICE_REOMOVED
}
/**
* Helper function that acutally calls an IDeviceListener method
* @param listenerToCall
* @param device
*/
public void callDeviceListener(DeviceListenerToCall listenerToCall,
IDevice device) {
VirtualRouting vr = getVirtualRouting();
switch(listenerToCall) {
case DEVICE_ADDED:
vr.dhcpManager.deviceListener.deviceAdded(device);
break;
case DEVICE_REOMOVED:
vr.dhcpManager.deviceListener.deviceRemoved(device);
break;
default:
break;
}
}
/**
* Tests handling IDeviceListener events. Caller can specify the
* listener function to be called
* @throws IOException
* @throws InterruptedException
*/
public void doDeviceListenerTest(DeviceListenerToCall listenerToCall)
throws IOException, InterruptedException {
NetVirtManagerImpl netVirtManager = getNetVirtManager();
VirtualRouting vr = getVirtualRouting();
int timeout = 30; // ms
int sleepTime = timeout + 6; // ms
// Set timeout to low value
vr.dhcpManager.UNICAST_CONV_TIMEOUT = timeout;
vr.dhcpManager.init();
// Learn devices
long mac = HexString.toLong(hostMac);
int ip = IPv4.toIPv4Address(hostIp);
IDevice host =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(altHostMac);
ip = IPv4.toIPv4Address(altHostIp);
IDevice altDevice =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
mac = HexString.toLong(dhcpMac);
ip = IPv4.toIPv4Address(dhcpIp);
IDevice dhpcServerDevice =
mockDeviceManager.learnEntity(mac, null, ip, null, null);
// Configure DHCP mode
// All hosts are in the default NetVirt so its fine if we just set the
// mode once.
List<VNSInterface> ifaces = netVirtManager.getInterfaces(host);
for (VNSInterface iface : ifaces) {
iface.getParentVNS().setDhcpManagerMode(DHCPMode.FLOOD_IF_UNKNOWN);
break;
}
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(1L).anyTimes();
MockControllerProvider flp = getMockControllerProvider();
MessageCapture msgCapture = new MessageCapture();
flp.clearListeners();
flp.addOFMessageListener(OFType.PACKET_IN, msgCapture);
flp.addOFMessageListener(OFType.PACKET_IN, mockDeviceManager);
flp.addOFMessageListener(OFType.PACKET_IN, netVirtManager);
flp.addOFMessageListener(OFType.PACKET_IN, vr);
OFPacketIn altHostPacketnDHCPDiscoverRequest =
newDiscoveryRequest(altHostMac, broadcastMac);
replay(mockSwitch, topology);
// Send first request. Nothing snooped yet so we expect a flood.
ListenerContext cntx;
IRoutingDecision res;
// Send a reply. Now we will snoop the server
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
msgCapture.assertOneMessageAndReset();
//--
// The DHCP server should have been learned by now
// Send a request from altHost. Should be converted
//--
cntx = parseAndAnnotate(altHostPacketnDHCPDiscoverRequest);
flp.dispatchMessage(mockSwitch, altHostPacketnDHCPDiscoverRequest,
cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
// Expect two captured messages. First is the original broadcast, second
// is the reinjected unicast.
assertEquals(2, msgCapture.getMessages().size());
ListenerContext injectedContext = msgCapture.getContexts().get(1);
Ethernet injectedEth = IControllerService.bcStore.
get(injectedContext, IControllerService.CONTEXT_PI_PAYLOAD);
OFPacketIn injectedMessage = (OFPacketIn)msgCapture.getMessages().get(1);
assertEquals(dhcpMac,
HexString.toHexString(
injectedEth.getDestinationMACAddress()));
assertArrayEquals(injectedMessage.getPacketData(),
injectedEth.serialize());
msgCapture.reset();
//--
// Wait for the timeout seconds. Send a request to the original
// device to keep the server alive. But the altHost should still be
// timed out
//--
Thread.sleep(sleepTime);
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
msgCapture.assertOneMessageAndReset();
//--
// check that we convert to unicast for orig host (just a safety check)
//--
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
// Expect two captures messaged. First is the original broadcast, second
// is the reinjected unicast.
assertEquals(2, msgCapture.getMessages().size());
msgCapture.reset();
//--
// check that alt host is still timed out (i.e., it floods):
//--
cntx = parseAndAnnotate(altHostPacketnDHCPDiscoverRequest);
flp.dispatchMessage(mockSwitch, altHostPacketnDHCPDiscoverRequest,
cntx);
Ethernet eth =
IControllerService.bcStore.
get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
assertEquals(broadcastMac,
HexString.toHexString(eth.getDestinationMACAddress()));
assertEquals(1, msgCapture.getMessages().size());
msgCapture.reset();
//--
// Send Device Update for altHost. We should now clear the pending
// device state
//--
callDeviceListener(listenerToCall, altDevice);
//
// check we convert to unicast for alt host
//
cntx = parseAndAnnotate(altHostPacketnDHCPDiscoverRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
// Expect two captured messages. First is the original broadcast, second
// is the reinjected unicast.
assertEquals(2, msgCapture.getMessages().size());
injectedMessage = (OFPacketIn)msgCapture.getMessages().get(1);
assertEquals(dhcpMac,
HexString.toHexString(
injectedEth.getDestinationMACAddress()));
msgCapture.reset();
//////////////////////////////////////////////
// TEST DHCP SERVER DEVICE HANDLING
// ///////////////////////////////////////////
//
// Send a reply. Now we will snoop the server
//
cntx = parseAndAnnotate(packetInDHCPDiscoveryReply);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryReply, cntx);
res = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD, res.getRoutingAction());
assertEquals(true, res.getWildcards() != 0);
msgCapture.assertOneMessageAndReset();
//
//
// Check that we convert to unicast
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.NONE, res.getRoutingAction());
// Expect two captures messaged. First is the original broadcast, second
// is the reinjected unicast.
assertEquals(2, msgCapture.getMessages().size());
msgCapture.reset();
// Remvoe the DHCPServer device by calling an IOFDeviceListener
// A request from the same client should be flooded again
callDeviceListener(listenerToCall, dhpcServerDevice);
//
// Send request. We expect it to be flooded since we just removed
// the server
//
cntx = parseAndAnnotate(packetInDHCPDiscoveryRequest);
flp.dispatchMessage(mockSwitch, packetInDHCPDiscoveryRequest, cntx);
eth = IControllerService.bcStore.
get(cntx, IControllerService.CONTEXT_PI_PAYLOAD);
res = IRoutingDecision.rtStore.get(cntx,
IRoutingDecision.CONTEXT_DECISION);
assertEquals(RoutingAction.FORWARD_OR_FLOOD, res.getRoutingAction());
assertEquals(Integer.valueOf(0), res.getWildcards());
assertEquals(broadcastMac,
HexString.toHexString(eth.getDestinationMACAddress()));
assertEquals(1, msgCapture.getMessages().size());
msgCapture.reset();
verify(mockSwitch);
}
@Test
public void testDeviceAddedHandling()
throws IOException, InterruptedException {
doDeviceListenerTest(DeviceListenerToCall.DEVICE_ADDED);
}
@Test
public void testDeviceRemovedHandling()
throws IOException, InterruptedException {
doDeviceListenerTest(DeviceListenerToCall.DEVICE_REOMOVED);
}
protected DhcpManager getDhcpManager() {
return dhcpManager;
}
protected MockDeviceManager getMockDeviceManager() {
return mockDeviceManager;
}
protected IStorageSourceService getStorageSource() {
return storageSource;
}
protected NetVirtManagerImpl getNetVirtManager() {
return netVirtManager;
}
protected VirtualRouting getVirtualRouting() {
return virtualRouting;
}
protected void initDiscoveryRequestPacket() {
this.packetInDHCPDiscoveryRequest = newDiscoveryRequest(hostMac,
broadcastMac);
}
protected void initDiscoveryRequestPacketUnicast() {
this.packetInDHCPDiscoveryRequestUnicast = newDiscoveryRequest(hostMac,
dhcpMac);
}
protected void initDiscoveryReplyPacket() {
int srcIp = IPv4.toIPv4Address(dhcpIp);
int dstIp = IPv4.toIPv4Address(hostIp);
this.packetInDHCPDiscoveryReply =
newDiscoveryReply(dhcpMac, hostMac, srcIp, dstIp);
}
protected void initDiscoveryRoqueReplyPacket() {
int srcIp = IPv4.toIPv4Address(roqueDhcpIp);
int dstIp = IPv4.toIPv4Address(hostIp);
this.packetInDHCPDiscoveryRoqueReply =
newDiscoveryReply(roqueDhcpMac, hostMac, srcIp, dstIp);
}
protected void initDiscoveryBroadcastReplyPacket() {
int srcIp = IPv4.toIPv4Address(dhcpIp);
int dstIp = IPv4.toIPv4Address(broadcastIp);
this.packetInDHCPDiscoveryBroadcastReply =
newDiscoveryReply(dhcpMac, broadcastMac, srcIp, dstIp);
}
protected OFPacketIn newDiscoveryRequest(String srcMac, String dstMac) {
List<DHCPOption> optionList = new ArrayList<DHCPOption>();
byte[] requestValue = new byte[4];
requestValue[0] = requestValue[1] = requestValue[2] = requestValue[3] = 0;
DHCPOption requestOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.
getValue())
.setLength((byte)4)
.setData(requestValue);
byte[] msgTypeValue = new byte[1];
msgTypeValue[0] = 1; // DHCP request
DHCPOption msgTypeOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.
getValue())
.setLength((byte)1)
.setData(msgTypeValue);
byte[] reqParamValue = new byte[4];
reqParamValue[0] = 1; // subnet mask
reqParamValue[1] = 3; // Router
reqParamValue[2] = 6; // Domain Name Server
reqParamValue[3] = 42; // NTP Server
DHCPOption reqParamOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedParameters.
getValue())
.setLength((byte)4)
.setData(reqParamValue);
byte[] clientIdValue = new byte[7];
clientIdValue[0] = 1; // Ethernet
System.arraycopy(Ethernet.toMACAddress(srcMac), 0,
clientIdValue, 1, 6);
DHCPOption clientIdOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_ClientID.
getValue())
.setLength((byte)7)
.setData(clientIdValue);
DHCPOption endOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_END.
getValue())
.setLength((byte)0)
.setData(null);
optionList.add(requestOption);
optionList.add(msgTypeOption);
optionList.add(reqParamOption);
optionList.add(clientIdOption);
optionList.add(endOption);
IPacket requestPacket = new Ethernet()
.setSourceMACAddress(srcMac)
.setDestinationMACAddress(dstMac)
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setVersion((byte)4)
.setDiffServ((byte)0)
.setIdentification((short)100)
.setFlags((byte)0)
.setFragmentOffset((short)0)
.setTtl((byte)250)
.setProtocol(IPv4.PROTOCOL_UDP)
.setChecksum((short)0)
.setSourceAddress(0)
.setDestinationAddress(broadcastIp)
.setPayload(
new UDP()
.setSourcePort(UDP.DHCP_CLIENT_PORT)
.setDestinationPort(UDP.DHCP_SERVER_PORT)
.setChecksum((short)0)
.setPayload(
new DHCP()
.setOpCode(DHCP.OPCODE_REQUEST)
.setHardwareType(DHCP.HWTYPE_ETHERNET)
.setHardwareAddressLength((byte)6)
.setHops((byte)0)
.setTransactionId(0x00003d1d)
.setSeconds((short)0)
.setFlags((short)0)
.setClientIPAddress(0)
.setYourIPAddress(0)
.setServerIPAddress(0)
.setGatewayIPAddress(0)
.setClientHardwareAddress(Ethernet.
toMACAddress(srcMac))
.setOptions(optionList))));
byte[] serializedPacket = requestPacket.serialize();
return (((OFPacketIn) mockControllerProvider.getOFMessageFactory()
.getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(serializedPacket)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short)serializedPacket.length));
}
protected OFPacketIn newDiscoveryReply(String srcMac, String dstMac,
int srcIp, int dstIp) {
List<DHCPOption> optionList = new ArrayList<DHCPOption>();
byte[] subnetMaskValue = IPv4.toIPv4AddressBytes(hostSubnetMask);
DHCPOption subnetMaskOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.
getValue())
.setLength((byte)4)
.setData(subnetMaskValue);
byte[] leaseTimeValue = new byte[4];
leaseTimeValue[0] = leaseTimeValue[1] = 0;
leaseTimeValue[2] = 0x0e;
leaseTimeValue[3] = 0x10; // 1 Hour
DHCPOption leaseTimeOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime
.getValue())
.setLength((byte)4)
.setData(leaseTimeValue);
byte[] msgTypeValue = new byte[1];
msgTypeValue[0] = 2; // DHCP offer
DHCPOption msgTypeOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType
.getValue())
.setLength((byte)1)
.setData(msgTypeValue);
byte[] dhcpServerIdValue = IPv4.toIPv4AddressBytes(dhcpIp);
DHCPOption dhcpServerIdOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp
.getValue())
.setLength((byte)4)
.setData(dhcpServerIdValue);
byte[] renewalTimeValue = new byte[4];
renewalTimeValue[0] = renewalTimeValue[1] = 0;
renewalTimeValue[2] = 0x07;
renewalTimeValue[3] = 0x08;
DHCPOption renewalTimeOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime
.getValue())
.setLength((byte)4)
.setData(renewalTimeValue);
byte[] rebindingTimeValue = new byte[4];
rebindingTimeValue[0] = rebindingTimeValue[1] = 0;
rebindingTimeValue[2] = 0x0c;
rebindingTimeValue[3] = 0x4e;
DHCPOption rebindingTimeOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime
.getValue())
.setLength((byte)4)
.setData(rebindingTimeValue);
DHCPOption endOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue())
.setLength((byte)0)
.setData(null);
optionList.add(subnetMaskOption);
optionList.add(leaseTimeOption);
optionList.add(msgTypeOption);
optionList.add(dhcpServerIdOption);
optionList.add(renewalTimeOption);
optionList.add(rebindingTimeOption);
optionList.add(endOption);
IPacket replyPacket = new Ethernet()
.setSourceMACAddress(srcMac)
.setDestinationMACAddress(dstMac)
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setVersion((byte)4)
.setDiffServ((byte)0)
.setIdentification((short)200)
.setFlags((byte)0)
.setFragmentOffset((short)0)
.setTtl((byte)128)
.setProtocol(IPv4.PROTOCOL_UDP)
.setChecksum((short)0)
.setSourceAddress(srcIp)
.setDestinationAddress(dstIp)
.setPayload(
new UDP()
.setSourcePort(UDP.DHCP_SERVER_PORT)
.setDestinationPort(UDP.DHCP_CLIENT_PORT)
.setChecksum((short)0)
.setPayload(
new DHCP()
.setOpCode(DHCP.OPCODE_REPLY)
.setHardwareType(DHCP.HWTYPE_ETHERNET)
.setHardwareAddressLength((byte)6)
.setHops((byte)0)
.setTransactionId(0x00003d1d)
.setSeconds((short)0)
.setFlags((short)0)
.setClientIPAddress(0)
.setYourIPAddress(IPv4.toIPv4Address(hostIp))
.setServerIPAddress(srcIp)
.setGatewayIPAddress(0)
.setClientHardwareAddress(Ethernet.
toMACAddress(hostMac))
.setOptions(optionList))));
byte[] serializedPacket = replyPacket.serialize();
return (((OFPacketIn) mockControllerProvider.getOFMessageFactory()
.getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short)1)
.setPacketData(serializedPacket)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short)serializedPacket.length));
}
protected void initRequestRequestPacket() {
List<DHCPOption> optionList = new ArrayList<DHCPOption>();
byte[] requestValue = IPv4.toIPv4AddressBytes(hostIp);
DHCPOption requestOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP
.getValue())
.setLength((byte)4)
.setData(requestValue);
byte[] msgTypeValue = new byte[1];
msgTypeValue[0] = 1; // DHCP request
DHCPOption msgTypeOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType
.getValue())
.setLength((byte)1)
.setData(msgTypeValue);
byte[] dhcpServerIdValue = IPv4.toIPv4AddressBytes(dhcpIp);
DHCPOption dhcpServerIdOption =
new DHCPOption()
.setCode(DHCP.DHCPOptionCode.OptionCode_DHCPServerIp
.getValue())
.setLength((byte)4)
.setData(dhcpServerIdValue);
byte[] reqParamValue = new byte[4];
reqParamValue[0] = 1; // subnet mask
reqParamValue[1] = 3; // Router
reqParamValue[2] = 6; // Domain Name Server
reqParamValue[3] = 42; // NTP Server
DHCPOption reqParamOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode
.OptionCode_RequestedParameters
.getValue())
.setLength((byte)4)
.setData(reqParamValue);
byte[] clientIdValue = new byte[7];
clientIdValue[0] = 1; // Ethernet
System.arraycopy(Ethernet.toMACAddress(hostMac), 0, clientIdValue, 1, 6);
DHCPOption clientIdOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode
.OptionCode_ClientID.getValue())
.setLength((byte)7)
.setData(clientIdValue);
DHCPOption endOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode
.OptionCode_END.getValue())
.setLength((byte)0)
.setData(null);
optionList.add(requestOption);
optionList.add(msgTypeOption);
optionList.add(reqParamOption);
optionList.add(dhcpServerIdOption);
optionList.add(clientIdOption);
optionList.add(endOption);
IPacket dhcpRequestRequestPacket = new Ethernet()
.setSourceMACAddress(hostMac)
.setDestinationMACAddress(broadcastMac)
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setVersion((byte)4)
.setDiffServ((byte)0)
.setIdentification((short)101)
.setFlags((byte)0)
.setFragmentOffset((short)0)
.setTtl((byte)250)
.setProtocol(IPv4.PROTOCOL_UDP)
.setChecksum((short)0)
.setSourceAddress(0)
.setDestinationAddress(broadcastIp)
.setPayload(
new UDP()
.setSourcePort(UDP.DHCP_CLIENT_PORT)
.setDestinationPort(UDP.DHCP_SERVER_PORT)
.setChecksum((short)0)
.setPayload(
new DHCP()
.setOpCode(DHCP.OPCODE_REQUEST)
.setHardwareType(DHCP.HWTYPE_ETHERNET)
.setHardwareAddressLength((byte)6)
.setHops((byte)0)
.setTransactionId(0x00003d1d)
.setSeconds((short)0)
.setFlags((short)0)
.setClientIPAddress(0)
.setYourIPAddress(0)
.setServerIPAddress(0)
.setGatewayIPAddress(0)
.setClientHardwareAddress(Ethernet.
toMACAddress(hostMac))
.setOptions(optionList))));
byte[] serializedPacket = dhcpRequestRequestPacket.serialize();
this.packetInDHCPRequestRequest =
((OFPacketIn) mockControllerProvider.getOFMessageFactory()
.getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short)1)
.setPacketData(serializedPacket)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short)serializedPacket.length);
}
protected void initRequestAckPacket() {
List<DHCPOption> optionList = new ArrayList<DHCPOption>();
byte[] subnetMaskValue = IPv4.toIPv4AddressBytes(hostSubnetMask);
DHCPOption subnetMaskOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_SubnetMask.getValue())
.setLength((byte)4)
.setData(subnetMaskValue);
byte[] leaseTimeValue = new byte[4];
leaseTimeValue[0] = leaseTimeValue[1] = 0;
leaseTimeValue[2] = 0x0e;
leaseTimeValue[3] = 0x10; // 1 Hour
DHCPOption leaseTimeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_LeaseTime.getValue())
.setLength((byte)4)
.setData(leaseTimeValue);
byte[] msgTypeValue = new byte[1];
msgTypeValue[0] = 5; // DHCP ACK
DHCPOption msgTypeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_MessageType.getValue())
.setLength((byte)1)
.setData(msgTypeValue);
byte[] dhcpServerIdValue = IPv4.toIPv4AddressBytes(dhcpIp);
DHCPOption dhcpServerIdOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_DHCPServerIp.getValue())
.setLength((byte)4)
.setData(dhcpServerIdValue);
byte[] renewalTimeValue = new byte[4];
renewalTimeValue[0] = renewalTimeValue[1] = 0;
renewalTimeValue[2] = 0x07;
renewalTimeValue[3] = 0x08;
DHCPOption renewalTimeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_RenewalTime.getValue())
.setLength((byte)4)
.setData(renewalTimeValue);
byte[] rebindingTimeValue = new byte[4];
rebindingTimeValue[0] = rebindingTimeValue[1] = 0;
rebindingTimeValue[2] = 0x0c;
rebindingTimeValue[3] = 0x4e;
DHCPOption rebindingTimeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OPtionCode_RebindingTime.
getValue())
.setLength((byte)4)
.setData(rebindingTimeValue);
DHCPOption endOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_END.getValue())
.setLength((byte)0)
.setData(null);
optionList.add(subnetMaskOption);
optionList.add(leaseTimeOption);
optionList.add(msgTypeOption);
optionList.add(dhcpServerIdOption);
optionList.add(renewalTimeOption);
optionList.add(rebindingTimeOption);
optionList.add(endOption);
IPacket dhcpRequestAckPacket = new Ethernet()
.setSourceMACAddress(dhcpMac)
.setDestinationMACAddress(hostMac)
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setVersion((byte)4)
.setDiffServ((byte)0)
.setIdentification((short)201)
.setFlags((byte)0)
.setFragmentOffset((short)0)
.setTtl((byte)128)
.setProtocol(IPv4.PROTOCOL_UDP)
.setChecksum((short)0)
.setSourceAddress(dhcpIp)
.setDestinationAddress(hostIp)
.setPayload(
new UDP()
.setSourcePort(UDP.DHCP_SERVER_PORT)
.setDestinationPort(UDP.DHCP_CLIENT_PORT)
.setChecksum((short)0)
.setPayload(
new DHCP()
.setOpCode(DHCP.OPCODE_REPLY)
.setHardwareType(DHCP.HWTYPE_ETHERNET)
.setHardwareAddressLength((byte)6)
.setHops((byte)0)
.setTransactionId(0x00003d1d)
.setSeconds((short)0)
.setFlags((short)0)
.setClientIPAddress(0)
.setYourIPAddress(IPv4.toIPv4Address(hostIp))
.setServerIPAddress(0)
.setGatewayIPAddress(0)
.setClientHardwareAddress(Ethernet.
toMACAddress(hostMac))
.setOptions(optionList))));
byte[] serializedPacket = dhcpRequestAckPacket.serialize();
this.packetInDHCPRequestAck =
((OFPacketIn) mockControllerProvider.getOFMessageFactory()
.getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short)1)
.setPacketData(serializedPacket)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short)serializedPacket.length);
}
/* return a non DHCP packet.
* We'll change Ethertype, IP protocol, and/or UDP ports to make the
* packet non-DHCP
*/
protected OFPacketIn newNonDhcpPacket(boolean makeIpPacket,
boolean makeUDPPacket) {
List<DHCPOption> optionList = new ArrayList<DHCPOption>();
byte[] subnetMaskValue = IPv4.toIPv4AddressBytes(hostSubnetMask);
DHCPOption subnetMaskOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_SubnetMask.getValue())
.setLength((byte)4)
.setData(subnetMaskValue);
byte[] leaseTimeValue = new byte[4];
leaseTimeValue[0] = leaseTimeValue[1] = 0;
leaseTimeValue[2] = 0x0e;
leaseTimeValue[3] = 0x10; // 1 Hour
DHCPOption leaseTimeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_LeaseTime.getValue())
.setLength((byte)4)
.setData(leaseTimeValue);
byte[] msgTypeValue = new byte[1];
msgTypeValue[0] = 5; // DHCP ACK
DHCPOption msgTypeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_MessageType.getValue())
.setLength((byte)1)
.setData(msgTypeValue);
byte[] dhcpServerIdValue = IPv4.toIPv4AddressBytes(dhcpIp);
DHCPOption dhcpServerIdOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_DHCPServerIp.getValue())
.setLength((byte)4)
.setData(dhcpServerIdValue);
byte[] renewalTimeValue = new byte[4];
renewalTimeValue[0] = renewalTimeValue[1] = 0;
renewalTimeValue[2] = 0x07;
renewalTimeValue[3] = 0x08;
DHCPOption renewalTimeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_RenewalTime.getValue())
.setLength((byte)4)
.setData(renewalTimeValue);
byte[] rebindingTimeValue = new byte[4];
rebindingTimeValue[0] = rebindingTimeValue[1] = 0;
rebindingTimeValue[2] = 0x0c;
rebindingTimeValue[3] = 0x4e;
DHCPOption rebindingTimeOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OPtionCode_RebindingTime.
getValue())
.setLength((byte)4)
.setData(rebindingTimeValue);
DHCPOption endOption = new DHCPOption()
.setCode(DHCP.DHCPOptionCode.
OptionCode_END.getValue())
.setLength((byte)0)
.setData(null);
optionList.add(subnetMaskOption);
optionList.add(leaseTimeOption);
optionList.add(msgTypeOption);
optionList.add(dhcpServerIdOption);
optionList.add(renewalTimeOption);
optionList.add(rebindingTimeOption);
optionList.add(endOption);
Ethernet eth = new Ethernet()
.setSourceMACAddress(dhcpMac)
.setDestinationMACAddress(hostMac)
.setEtherType((short)0);
IPv4 ipv4 = new IPv4()
.setVersion((byte)4)
.setDiffServ((byte)0)
.setIdentification((short)201)
.setFlags((byte)0)
.setFragmentOffset((short)0)
.setTtl((byte)128)
.setProtocol((byte)0)
.setChecksum((short)0)
.setSourceAddress(dhcpIp)
.setDestinationAddress(hostIp);
UDP udp = (UDP)new UDP()
.setSourcePort((short)2000)
.setDestinationPort((short)3000)
.setChecksum((short)0)
.setPayload(
new DHCP()
.setOpCode(DHCP.OPCODE_REPLY)
.setHardwareType(DHCP.HWTYPE_ETHERNET)
.setHardwareAddressLength((byte)6)
.setHops((byte)0)
.setTransactionId(0x00003d1d)
.setSeconds((short)0)
.setFlags((short)0)
.setClientIPAddress(0)
.setYourIPAddress(IPv4.toIPv4Address(hostIp))
.setServerIPAddress(0)
.setGatewayIPAddress(0)
.setClientHardwareAddress(Ethernet.
toMACAddress(hostMac))
.setOptions(optionList));
if (makeUDPPacket) {
ipv4.setPayload(udp);
ipv4.setProtocol(IPv4.PROTOCOL_UDP);
}
if (makeIpPacket) {
eth.setPayload(ipv4);
eth.setEtherType(Ethernet.TYPE_IPv4);
}
byte[] packetSerialized = eth.serialize();
OFPacketIn pi =
((OFPacketIn) mockControllerProvider.getOFMessageFactory()
.getMessage(OFType.PACKET_IN))
.setBufferId(OFPacketOut.BUFFER_ID_NONE)
.setInPort((short)1)
.setPacketData(packetSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) packetSerialized.length);
pi.setLength((short)(OFPacketIn.MINIMUM_LENGTH +
packetSerialized.length));
return pi;
}
}