[CORD-1887] Make DHCP relay works with dual homing
Change-Id: I479a292d6d6d4820798ed660cc51826c3b12ede3
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index ccdb407..235b4c5 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -44,8 +44,12 @@
import org.onosproject.dhcprelay.store.DhcpRelayStore;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.net.provider.ProviderId;
import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteStore;
import org.onosproject.net.ConnectPoint;
@@ -57,7 +61,6 @@
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.HostStore;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.OutboundPacket;
@@ -85,7 +88,7 @@
@Component
@Service
@Property(name = "version", value = "4")
-public class Dhcp4HandlerImpl implements DhcpHandler {
+public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider {
private static Logger log = LoggerFactory.getLogger(Dhcp4HandlerImpl.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -95,9 +98,6 @@
protected PacketService packetService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostStore hostStore;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RouteStore routeStore;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -106,6 +106,10 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostProviderRegistry providerRegistry;
+
+ protected HostProviderService providerService;
private InternalHostListener hostListener = new InternalHostListener();
private Ip4Address dhcpServerIp = null;
@@ -130,10 +134,16 @@
@Activate
protected void activate() {
hostService.addListener(hostListener);
+ providerService = providerRegistry.register(this);
}
@Deactivate
protected void deactivate() {
+ providerRegistry.unregister(this);
+ hostService.removeListener(hostListener);
+ this.dhcpConnectMac = null;
+ this.dhcpConnectVlan = null;
+
if (dhcpGatewayIp != null) {
hostService.stopMonitoringIp(dhcpGatewayIp);
}
@@ -337,11 +347,6 @@
checkNotNull(incomingPacketType, "Can't get message type from DHCP payload {}", dhcpPayload);
switch (incomingPacketType) {
case DHCPDISCOVER:
- // Try update host if it is directly connected.
- if (directlyConnected(dhcpPayload)) {
- updateHost(context, dhcpPayload);
- }
-
// Add the gateway IP as virtual interface IP for server to understand
// the lease to be assigned and forward the packet to dhcp server.
Ethernet ethernetPacketDiscover =
@@ -387,22 +392,6 @@
}
/**
- * Updates host to host store according to DHCP payload.
- *
- * @param context the packet context
- * @param dhcpPayload the DHCP payload
- */
- private void updateHost(PacketContext context, DHCP dhcpPayload) {
- ConnectPoint location = context.inPacket().receivedFrom();
- HostLocation hostLocation = new HostLocation(location, System.currentTimeMillis());
- MacAddress macAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress());
- VlanId vlanId = VlanId.vlanId(context.inPacket().parsed().getVlanID());
- HostId hostId = HostId.hostId(macAddress, vlanId);
- HostDescription desc = new DefaultHostDescription(macAddress, vlanId, hostLocation);
- hostStore.createOrUpdateHost(DhcpRelayManager.PROVIDER_ID, hostId, desc, false);
- }
-
- /**
* Checks if this app has been configured.
*
* @return true if all information we need have been initialized
@@ -847,11 +836,18 @@
if (directlyConnected(dhcpPayload)) {
// Add to host store if it connect to network directly
Set<IpAddress> ips = Sets.newHashSet(ip);
- HostDescription desc = new DefaultHostDescription(macAddress, vlanId,
- hostLocation, ips);
+ Host host = hostService.getHost(hostId);
- // Replace the ip when dhcp server give the host new ip address
- hostStore.createOrUpdateHost(DhcpRelayManager.PROVIDER_ID, hostId, desc, false);
+ Set<HostLocation> hostLocations = Sets.newHashSet(hostLocation);
+ if (host != null) {
+ // Dual homing support:
+ // if host exists, use old locations and new location
+ hostLocations.addAll(host.locations());
+ }
+ HostDescription desc = new DefaultHostDescription(macAddress, vlanId,
+ hostLocations, ips, false);
+ // Add IP address when dhcp server give the host new ip address
+ providerService.hostDetected(hostId, desc, false);
} else {
// Add to route store if it does not connect to network directly
// Get gateway host IP according to host mac address
@@ -1010,6 +1006,16 @@
packetService.emit(o);
}
+ @Override
+ public void triggerProbe(Host host) {
+ // Do nothing here
+ }
+
+ @Override
+ public ProviderId id() {
+ return DhcpRelayManager.PROVIDER_ID;
+ }
+
class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index 27d59d9..c247b90 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -48,7 +48,9 @@
import org.onlab.util.HexString;
import org.onosproject.dhcprelay.api.DhcpHandler;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
-import org.onosproject.net.host.HostStore;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.host.HostService;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
@@ -57,6 +59,7 @@
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.net.provider.ProviderId;
import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteStore;
import org.onosproject.dhcprelay.config.DhcpServerConfig;
@@ -88,7 +91,7 @@
@Component
@Service
@Property(name = "version", value = "6")
-public class Dhcp6HandlerImpl implements DhcpHandler {
+public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -98,9 +101,6 @@
protected PacketService packetService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostStore hostStore;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RouteStore routeStore;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -109,8 +109,11 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
- private InternalHostListener hostListener = new InternalHostListener();
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostProviderRegistry providerRegistry;
+ private InternalHostListener hostListener = new InternalHostListener();
+ protected HostProviderService providerService;
private Ip6Address dhcpServerIp = null;
// dhcp server may be connected directly to the SDN network or
// via an external gateway. When connected directly, the dhcpConnectPoint, dhcpConnectMac,
@@ -146,11 +149,13 @@
@Activate
protected void activate() {
+ providerService = providerRegistry.register(this);
hostService.addListener(hostListener);
}
@Deactivate
protected void deactivate() {
+ providerRegistry.unregister(this);
hostService.removeListener(hostListener);
this.dhcpConnectMac = null;
this.dhcpConnectVlan = null;
@@ -162,7 +167,6 @@
}
}
-
@Override
public void setDhcpServerIp(IpAddress dhcpServerIp) {
checkNotNull(dhcpServerIp, "DHCP server IP can't be null");
@@ -322,6 +326,16 @@
return this.dhcpServerConnectPoint != null && this.dhcpServerIp != null;
}
+ @Override
+ public ProviderId id() {
+ return DhcpRelayManager.PROVIDER_ID;
+ }
+
+ @Override
+ public void triggerProbe(Host host) {
+ // Do nothing here
+ }
+
// the new class the contains Ethernet packet and destination port, kind of like adding
// internal header to the packet
private class InternalPacket {
@@ -631,9 +645,8 @@
log.debug("client mac {} client vlan {}", HexString.toHexString(clientMac.toBytes(), ":"), vlanId);
-
// Remove host's ip of when dhcp release msg is received
- hostStore.removeIp(hostId, ip);
+ providerService.removeIpFromHost(hostId, ip);
} else {
log.debug("ipAddress not found. Do not add Host for directly connected.");
}
@@ -690,19 +703,30 @@
ip = extractIpAddress(embeddedDhcp6);
if (ip != null) {
Set<IpAddress> ips = Sets.newHashSet(ip);
+
+ // FIXME: we should use vlan id from original packet (solicit, request)
VlanId vlanId = clientInterfaces.iterator().next().vlan();
HostId hostId = HostId.hostId(clientMac, vlanId);
+ Host host = hostService.getHost(hostId);
HostLocation hostLocation = new HostLocation(clientInterfaces.iterator().next().connectPoint(),
- System.currentTimeMillis());
+ System.currentTimeMillis());
+ Set<HostLocation> hostLocations = Sets.newHashSet(hostLocation);
+
+ if (host != null) {
+ // Dual homing support:
+ // if host exists, use old locations and new location
+ hostLocations.addAll(host.locations());
+ }
HostDescription desc = new DefaultHostDescription(clientMac, vlanId,
- hostLocation, ips);
+ hostLocations, ips,
+ false);
log.debug("adding Host for directly connected.");
log.debug("client mac {} client vlan {} hostlocation {}",
HexString.toHexString(clientMac.toBytes(), ":"),
vlanId, hostLocation.toString());
// Replace the ip when dhcp server give the host new ip address
- hostStore.createOrUpdateHost(DhcpRelayManager.PROVIDER_ID, hostId, desc, true);
+ providerService.hostDetected(hostId, desc, false);
} else {
log.warn("ipAddress not found. Do not add Host for directly connected.");
}
@@ -935,7 +959,8 @@
// find destMac
MacAddress clientMac = null;
- Set<Host> clients = hostService.getHostsByIp(Ip6Address.valueOf(dhcp6Relay.getPeerAddress()));
+ Ip6Address peerAddress = Ip6Address.valueOf(dhcp6Relay.getPeerAddress());
+ Set<Host> clients = hostService.getHostsByIp(peerAddress);
if (clients.isEmpty()) {
log.warn("There's no host found for this address {}",
HexString.toHexString(dhcp6Relay.getPeerAddress(), ":"));
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index e66dbb6..97b19e7 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -115,8 +115,6 @@
public class DhcpRelayManager implements DhcpRelayService {
public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
public static final ProviderId PROVIDER_ID = new ProviderId("host", DHCP_RELAY_APP);
- public static final String HOST_LOCATION_PROVIDER =
- "org.onosproject.provider.host.impl.HostLocationProvider";
public static final String ROUTE_STORE_IMPL =
"org.onosproject.routeservice.store.RouteStoreImpl";
private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
@@ -243,9 +241,6 @@
requestDhcpPackets();
modified(context);
- // disable dhcp from host location provider
- compCfgService.preSetProperty(HOST_LOCATION_PROVIDER,
- "useDhcp", Boolean.FALSE.toString());
// Enable distribute route store
compCfgService.preSetProperty(ROUTE_STORE_IMPL,
"distributed", Boolean.TRUE.toString());
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
index a179e63..f45555d 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -76,6 +76,7 @@
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.host.HostProviderService;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceServiceAdapter;
import org.onosproject.net.packet.PacketPriority;
@@ -87,9 +88,7 @@
import org.onosproject.net.HostLocation;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.host.HostDescription;
-import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.HostStoreAdapter;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.InboundPacket;
@@ -98,7 +97,6 @@
import org.onosproject.net.packet.PacketContextAdapter;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketServiceAdapter;
-import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.StoreDelegate;
import org.osgi.service.component.ComponentContext;
import org.onlab.packet.DHCP6;
@@ -138,12 +136,28 @@
private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
+ private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
+ private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
+ private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
+ private static final Host EXISTS_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
+ CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
+ CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
private static final Interface CLIENT_INTERFACE = new Interface("C1",
CLIENT_CP,
INTERFACE_IPS,
CLIENT_IFACE_MAC,
CLIENT_VLAN);
+ // Dual homing test
+ private static final ConnectPoint CLIENT_DH_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/3");
+ private static final HostLocation CLIENT_DH_LOCATION = new HostLocation(CLIENT_DH_CP, 0);
+ private static final Interface CLIENT_DH_INTERFACE = new Interface("C1-DH",
+ CLIENT_DH_CP,
+ INTERFACE_IPS,
+ CLIENT_IFACE_MAC,
+ CLIENT_VLAN);
+
+
// DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
private static final VlanId CLIENT2_VLAN = VlanId.NONE;
@@ -208,7 +222,8 @@
private static final Set<Interface> INTERFACES = ImmutableSet.of(
CLIENT_INTERFACE,
CLIENT2_INTERFACE,
- SERVER_INTERFACE
+ SERVER_INTERFACE,
+ CLIENT_DH_INTERFACE
);
private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
@@ -216,9 +231,9 @@
private DhcpRelayManager manager;
private MockPacketService packetService;
- private MockHostStore mockHostStore;
private MockRouteStore mockRouteStore;
private MockDhcpRelayStore mockDhcpRelayStore;
+ private HostProviderService mockHostProviderService;
@Before
public void setup() {
@@ -254,20 +269,17 @@
expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
replay(manager.deviceService, device);
- mockHostStore = new MockHostStore();
mockRouteStore = new MockRouteStore();
mockDhcpRelayStore = new MockDhcpRelayStore();
manager.dhcpRelayStore = mockDhcpRelayStore;
manager.interfaceService = new MockInterfaceService();
manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
-
-
-
+ mockHostProviderService = createNiceMock(HostProviderService.class);
Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
+ v4Handler.providerService = mockHostProviderService;
v4Handler.dhcpRelayStore = mockDhcpRelayStore;
v4Handler.hostService = manager.hostService;
- v4Handler.hostStore = mockHostStore;
v4Handler.interfaceService = manager.interfaceService;
v4Handler.packetService = manager.packetService;
v4Handler.routeStore = mockRouteStore;
@@ -278,10 +290,10 @@
Dhcp6HandlerImpl v6Handler = new Dhcp6HandlerImpl();
v6Handler.dhcpRelayStore = mockDhcpRelayStore;
v6Handler.hostService = manager.hostService;
- v6Handler.hostStore = mockHostStore;
v6Handler.interfaceService = manager.interfaceService;
v6Handler.packetService = manager.packetService;
v6Handler.routeStore = mockRouteStore;
+ v6Handler.providerService = mockHostProviderService;
manager.v6Handler = v6Handler;
// properties
@@ -306,33 +318,36 @@
*/
@Test
public void relayDhcpWithoutAgentInfo() {
+ replay(mockHostProviderService);
// send request
packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
CLIENT_VLAN,
CLIENT_CP,
INTERFACE_IP.ipAddress().getIp4Address(),
false));
+ // won't trigger the host provider service
+ verify(mockHostProviderService);
+ reset(mockHostProviderService);
- Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(0, hosts.size());
assertEquals(0, mockRouteStore.routes.size());
+ HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
+ Capture<HostDescription> capturedHostDesc = newCapture();
+ mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
+ replay(mockHostProviderService);
// send ack
packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
false));
- hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(1, hosts.size());
+ verify(mockHostProviderService);
assertEquals(0, mockRouteStore.routes.size());
- Host host = hosts.iterator().next();
- assertEquals(CLIENT_MAC, host.mac());
- assertEquals(CLIENT_VLAN, host.vlan());
+ HostDescription host = capturedHostDesc.getValue();
+ assertEquals(false, host.configured());
assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
assertEquals(CLIENT_CP.port(), host.location().port());
- assertEquals(1, host.ipAddresses().size());
- assertEquals(IP_FOR_CLIENT, host.ipAddresses().iterator().next());
- assertEquals(HostId.hostId(CLIENT_MAC, CLIENT_VLAN), host.id());
+ assertEquals(1, host.ipAddress().size());
+ assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next());
}
/**
@@ -340,6 +355,7 @@
*/
@Test
public void relayDhcpWithAgentInfo() {
+ replay(mockHostProviderService);
// Assume outer dhcp relay agent exists in store already
// send request
packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
@@ -347,11 +363,8 @@
CLIENT2_CP,
INTERFACE_IP.ipAddress().getIp4Address(),
true));
-
- Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(0, hosts.size());
+ // No routes
assertEquals(0, mockRouteStore.routes.size());
-
// send ack
packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
CLIENT2_MAC,
@@ -359,8 +372,10 @@
INTERFACE_IP.ipAddress().getIp4Address(),
true));
- hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(0, hosts.size());
+ // won't trigger the host provider service
+ verify(mockHostProviderService);
+ reset(mockHostProviderService);
+
assertEquals(1, mockRouteStore.routes.size());
Route route = mockRouteStore.routes.get(0);
@@ -562,6 +577,7 @@
*/
@Test
public void relayDhcp6WithoutAgentInfo() {
+ replay(mockHostProviderService);
// send request
packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT_MAC,
VlanId.NONE,
@@ -569,27 +585,28 @@
INTERFACE_IP_V6.ipAddress().getIp6Address(),
0));
- Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(0, hosts.size());
+ verify(mockHostProviderService);
+ reset(mockHostProviderService);
assertEquals(0, mockRouteStore.routes.size());
+ Capture<HostDescription> capturedHostDesc = newCapture();
+ mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
+ capture(capturedHostDesc), eq(false));
+ replay(mockHostProviderService);
// send reply
packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT_CP, CLIENT_MAC,
CLIENT_VLAN,
INTERFACE_IP_V6.ipAddress().getIp6Address(),
0));
- hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(1, hosts.size());
+ verify(mockHostProviderService);
assertEquals(0, mockRouteStore.routes.size());
- Host host = hosts.iterator().next();
- assertEquals(CLIENT_MAC, host.mac());
+ HostDescription host = capturedHostDesc.getValue();
assertEquals(CLIENT_VLAN, host.vlan());
assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
assertEquals(CLIENT_CP.port(), host.location().port());
- assertEquals(1, host.ipAddresses().size());
- assertEquals(IP_FOR_CLIENT_V6, host.ipAddresses().iterator().next());
- assertEquals(HostId.hostId(CLIENT_MAC, CLIENT_VLAN), host.id());
+ assertEquals(1, host.ipAddress().size());
+ assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
}
/**
@@ -597,6 +614,7 @@
*/
@Test
public void relayDhcp6WithAgentInfo() {
+ replay(mockHostProviderService);
// Assume outer dhcp6 relay agent exists in store already
// send request
packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT2_MAC,
@@ -605,8 +623,6 @@
INTERFACE_IP_V6.ipAddress().getIp6Address(),
1));
- Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(0, hosts.size());
assertEquals(0, mockRouteStore.routes.size());
// send reply
@@ -616,8 +632,9 @@
INTERFACE_IP_V6.ipAddress().getIp6Address(),
1));
- hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
- assertEquals(0, hosts.size());
+ // won't trigger the host provider service
+ verify(mockHostProviderService);
+ reset(mockHostProviderService);
assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
Route route = mockRouteStore.routes.get(0);
@@ -625,6 +642,64 @@
assertEquals(IP_FOR_CLIENT_V6.toIpPrefix(), route.prefix());
assertEquals(Route.Source.STATIC, route.source());
}
+
+ @Test
+ public void testDhcp4DualHome() {
+ PacketContext packetContext =
+ new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
+ INTERFACE_IP.ipAddress().getIp4Address(),
+ false);
+ reset(manager.hostService);
+ expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
+ Capture<HostDescription> capturedHostDesc = newCapture();
+ mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
+ replay(mockHostProviderService, manager.hostService);
+ packetService.processPacket(packetContext);
+ verify(mockHostProviderService);
+
+ HostDescription hostDesc = capturedHostDesc.getValue();
+ Set<HostLocation> hostLocations = hostDesc.locations();
+ assertEquals(2, hostLocations.size());
+ assertTrue(hostLocations.contains(CLIENT_LOCATION));
+ assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
+ }
+
+ @Test
+ public void testDhcp6DualHome() {
+ PacketContext packetContext =
+ new TestDhcp6ReplyPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
+ INTERFACE_IP_V6.ipAddress().getIp6Address(),
+ 0);
+ reset(manager.hostService);
+ expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
+
+ // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
+ // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
+ HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
+ expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
+
+ // XXX: sometimes this will work, sometimes not
+ expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
+
+ Capture<HostDescription> capturedHostDesc = newCapture();
+
+ // XXX: also a hack here
+ mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
+ expectLastCall().anyTimes();
+
+ mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
+ expectLastCall().anyTimes();
+ replay(mockHostProviderService, manager.hostService);
+ packetService.processPacket(packetContext);
+ verify(mockHostProviderService);
+
+ HostDescription hostDesc = capturedHostDesc.getValue();
+ Set<HostLocation> hostLocations = hostDesc.locations();
+ assertEquals(2, hostLocations.size());
+ assertTrue(hostLocations.contains(CLIENT_LOCATION));
+ assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
+ }
+
private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
@Override
public boolean isValid() {
@@ -692,36 +767,6 @@
}
}
- private class MockHostStore extends HostStoreAdapter {
-
- private final Map<HostId, HostDescription> hosts = Maps.newHashMap();
-
- @Override
- public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
- HostDescription hostDescription,
- boolean replaceIps) {
- hosts.put(hostId, hostDescription);
-
- // not necessary to return host event in this test.
- return null;
- }
-
- public HostDescription hostDesc(HostId hostId) {
- return hosts.get(hostId);
- }
-
- @Override
- public Iterable<Host> getHosts() {
- return hosts.values().stream()
- .map(hd -> new DefaultHost(DhcpRelayManager.PROVIDER_ID,
- HostId.hostId(hd.hwAddress(), hd.vlan()),
- hd.hwAddress(),
- hd.vlan(), hd.locations(),
- hd.ipAddress(), false))
- .collect(Collectors.toList());
- }
- }
-
private class MockRouteStore extends RouteStoreAdapter {
private List<Route> routes = Lists.newArrayList();
@@ -1231,10 +1276,10 @@
byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
DHCP6 dhcp6 = new DHCP6();
buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
- INTERFACE_IP_V6.ipAddress().getIp6Address(),
- OUTER_RELAY_IP_V6,
- (byte) 0, interfaceId,
- dhcp6Payload);
+ INTERFACE_IP_V6.ipAddress().getIp6Address(),
+ CLIENT_LL_IP_V6,
+ (byte) 0, interfaceId,
+ dhcp6Payload);
DHCP6 dhcp6Parent = null;
DHCP6 dhcp6Child = dhcp6;
diff --git a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
index 90efcf4..a0d6e37 100644
--- a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
+++ b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
@@ -151,13 +151,11 @@
private boolean requestIpv6ND = false;
@Property(name = "useDhcp", boolValue = false,
- label = "Use DHCP for neighbor discovery by the " +
- "Host Location Provider; default is false")
+ label = "Use DHCP to update IP address of the host; default is false")
private boolean useDhcp = false;
@Property(name = "useDhcp6", boolValue = false,
- label = "Use DHCPv6 for neighbor discovery by the " +
- "Host Location Provider; default is false")
+ label = "Use DHCPv6 to update IP address of the host; default is false")
private boolean useDhcp6 = false;
@Property(name = "requestInterceptsEnabled", boolValue = true,
@@ -541,25 +539,18 @@
// IPv4: update location only
} else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
- DHCP dhcp = findDhcp(eth).orElse(null);
- if (dhcp != null) {
- if (useDhcp) {
- // learn host (server or client) MAC address
- createOrUpdateHost(hid, srcMac, vlan, hloc, null);
-
- // DHCP ACK: additionally update IP of DHCP client
- if (dhcp.getPacketType().equals(DHCP.MsgType.DHCPACK)) {
- MacAddress hostMac = MacAddress.valueOf(dhcp.getClientHardwareAddress());
- VlanId hostVlan = VlanId.vlanId(eth.getVlanID());
- HostId hostId = HostId.hostId(hostMac, hostVlan);
- updateHostIp(hostId, IpAddress.valueOf(dhcp.getYourIPAddress()));
- }
+ // Update host location
+ createOrUpdateHost(hid, srcMac, vlan, hloc, null);
+ if (useDhcp) {
+ DHCP dhcp = findDhcp(eth).orElse(null);
+ // DHCP ACK: additionally update IP of DHCP client
+ if (dhcp != null && dhcp.getPacketType().equals(DHCP.MsgType.DHCPACK)) {
+ MacAddress hostMac = MacAddress.valueOf(dhcp.getClientHardwareAddress());
+ VlanId hostVlan = VlanId.vlanId(eth.getVlanID());
+ HostId hostId = HostId.hostId(hostMac, hostVlan);
+ updateHostIp(hostId, IpAddress.valueOf(dhcp.getYourIPAddress()));
}
- } else {
- // learn host MAC address
- createOrUpdateHost(hid, srcMac, vlan, hloc, null);
}
- //
// NeighborAdvertisement and NeighborSolicitation: possible
// new hosts, update both location and IP.
//
@@ -605,8 +596,8 @@
}
}
- // multicast
- if (eth.isMulticast()) {
+ // multicast, exclude DHCPv6
+ if (eth.isMulticast() && dhcp6 == null) {
return;
}
diff --git a/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java b/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
index 5c924b5..77e2caa 100644
--- a/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
+++ b/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
@@ -439,18 +439,6 @@
}
/**
- * The host store should not updated when we disabled "useDhcp".
- */
- @Test
- public void receiveDhcpButNotEnabled() {
- TestUtils.setField(provider, "useDhcp", false);
- // DHCP Request
- testProcessor.process(new TestDhcpRequestPacketContext(DEV1, VLAN));
- assertThat("receiveDhcpButNotEnabled. No host description expected",
- providerService.descriptions.size(), is(0));
- }
-
- /**
* When receiving NeighborAdvertisement, updates location and IP.
*/
@Test