Use DHCP ACK to learn the DHCP client
This feature can be turn on/off via component config.
In addition, ARP interception can also be turned on/off now.
Change-Id: Ia3310fa3fb06821051fbf3363e51096d00781dbf
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 d91d437..1119eda 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
@@ -23,12 +23,17 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ARP;
+import org.onlab.packet.DHCP;
+import org.onlab.packet.DHCPPacketType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP6;
import org.onlab.packet.IPacket;
+import org.onlab.packet.IPv4;
import org.onlab.packet.IPv6;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.UDP;
import org.onlab.packet.VlanId;
import org.onlab.packet.ipv6.IExtensionHeader;
import org.onlab.packet.ndp.NeighborAdvertisement;
@@ -120,10 +125,20 @@
label = "Enable host removal on port/device down events")
private boolean hostRemovalEnabled = true;
- @Property(name = "ipv6NeighborDiscovery", boolValue = false,
+ @Property(name = "useArp", boolValue = true,
+ label = "Enable using ARP for neighbor discovery by the " +
+ "Host Location Provider; default is true")
+ private boolean useArp = true;
+
+ @Property(name = "useIpv6ND", boolValue = false,
label = "Enable using IPv6 Neighbor Discovery by the " +
"Host Location Provider; default is false")
- private boolean ipv6NeighborDiscovery = false;
+ private boolean useIpv6ND = false;
+
+ @Property(name = "useDhcp", boolValue = false,
+ label = "Enable using DHCP for neighbor discovery by the " +
+ "Host Location Provider; default is false")
+ private boolean useDhcp = false;
@Property(name = "requestInterceptsEnabled", boolValue = true,
label = "Enable requesting packet intercepts")
@@ -184,26 +199,52 @@
* Request packet intercepts.
*/
private void requestIntercepts() {
- TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
- selector.matchEthType(Ethernet.TYPE_ARP);
- packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
-
- // IPv6 Neighbor Solicitation packet.
- selector.matchEthType(Ethernet.TYPE_IPV6);
- selector.matchIPProtocol(IPv6.PROTOCOL_ICMP6);
- selector.matchIcmpv6Type(ICMP6.NEIGHBOR_SOLICITATION);
- if (ipv6NeighborDiscovery) {
- packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
+ // Use ARP
+ TrafficSelector arpSelector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_ARP)
+ .build();
+ if (useArp) {
+ packetService.requestPackets(arpSelector, PacketPriority.CONTROL, appId);
} else {
- packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
+ packetService.cancelPackets(arpSelector, PacketPriority.CONTROL, appId);
}
- // IPv6 Neighbor Advertisement packet.
- selector.matchIcmpv6Type(ICMP6.NEIGHBOR_ADVERTISEMENT);
- if (ipv6NeighborDiscovery) {
- packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
+ // Use IPv6 Neighbor Discovery
+ TrafficSelector ipv6NsSelector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6)
+ .matchIPProtocol(IPv6.PROTOCOL_ICMP6)
+ .matchIcmpv6Type(ICMP6.NEIGHBOR_SOLICITATION)
+ .build();
+ TrafficSelector ipv6NaSelector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6)
+ .matchIPProtocol(IPv6.PROTOCOL_ICMP6)
+ .matchIcmpv6Type(ICMP6.NEIGHBOR_ADVERTISEMENT)
+ .build();
+ if (useIpv6ND) {
+ packetService.requestPackets(ipv6NsSelector, PacketPriority.CONTROL, appId);
+ packetService.requestPackets(ipv6NaSelector, PacketPriority.CONTROL, appId);
} else {
- packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
+ packetService.cancelPackets(ipv6NsSelector, PacketPriority.CONTROL, appId);
+ packetService.cancelPackets(ipv6NaSelector, PacketPriority.CONTROL, appId);
+ }
+
+ // Use DHCP
+ TrafficSelector dhcpServerSelector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .build();
+ TrafficSelector dhcpClientSelector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
+ .build();
+ if (useDhcp) {
+ packetService.requestPackets(dhcpServerSelector, PacketPriority.CONTROL, appId);
+ packetService.requestPackets(dhcpClientSelector, PacketPriority.CONTROL, appId);
+ } else {
+ packetService.cancelPackets(dhcpServerSelector, PacketPriority.CONTROL, appId);
+ packetService.cancelPackets(dhcpClientSelector, PacketPriority.CONTROL, appId);
}
}
@@ -245,14 +286,34 @@
hostRemovalEnabled ? "enabled" : "disabled");
}
- flag = Tools.isPropertyEnabled(properties, "ipv6NeighborDiscovery");
+ flag = Tools.isPropertyEnabled(properties, "useArp");
+ if (flag == null) {
+ log.info("Using ARP is not configured, " +
+ "using current value of {}", useArp);
+ } else {
+ useArp = flag;
+ log.info("Configured. Using ARP is {}",
+ useArp ? "enabled" : "disabled");
+ }
+
+ flag = Tools.isPropertyEnabled(properties, "useIpv6ND");
if (flag == null) {
log.info("Using IPv6 Neighbor Discovery is not configured, " +
- "using current value of {}", ipv6NeighborDiscovery);
+ "using current value of {}", useIpv6ND);
} else {
- ipv6NeighborDiscovery = flag;
+ useIpv6ND = flag;
log.info("Configured. Using IPv6 Neighbor Discovery is {}",
- ipv6NeighborDiscovery ? "enabled" : "disabled");
+ useIpv6ND ? "enabled" : "disabled");
+ }
+
+ flag = Tools.isPropertyEnabled(properties, "useDhcp");
+ if (flag == null) {
+ log.info("Using DHCP is not configured, " +
+ "using current value of {}", useDhcp);
+ } else {
+ useDhcp = flag;
+ log.info("Configured. Using DHCP is {}",
+ useDhcp ? "enabled" : "disabled");
}
flag = Tools.isPropertyEnabled(properties, "requestInterceptsEnabled");
@@ -332,7 +393,7 @@
private class InternalHostProvider implements PacketProcessor {
/**
- * Update host location only.
+ * Updates host location only.
*
* @param hid host ID
* @param mac source Mac address
@@ -350,7 +411,7 @@
}
/**
- * Update host location and IP address.
+ * Updates host location and IP address.
*
* @param hid host ID
* @param mac source Mac address
@@ -371,6 +432,28 @@
}
}
+ /**
+ * Updates host IP address for an existing host.
+ *
+ * @param hid host ID
+ * @param ip IP address
+ */
+ private void updateIp(HostId hid, IpAddress ip) {
+ Host host = hostService.getHost(hid);
+ if (host == null) {
+ log.debug("Fail to update IP for {}. Host does not exist");
+ return;
+ }
+
+ HostDescription desc =
+ new DefaultHostDescription(hid.mac(), hid.vlanId(), host.location(), ip);
+ try {
+ providerService.hostDetected(hid, desc, false);
+ } catch (IllegalStateException e) {
+ log.debug("Host {} suppressed", hid);
+ }
+ }
+
@Override
public void process(PacketContext context) {
if (context == null) {
@@ -412,7 +495,28 @@
updateLocationIP(hid, srcMac, vlan, hloc, ip);
// IPv4: update location only
+ // DHCP ACK: additionally update IP of DHCP client
} else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
+ IPacket pkt = eth.getPayload();
+ if (pkt != null && pkt instanceof IPv4) {
+ pkt = pkt.getPayload();
+ if (pkt != null && pkt instanceof UDP) {
+ pkt = pkt.getPayload();
+ if (pkt != null && pkt instanceof DHCP) {
+ DHCP dhcp = (DHCP) pkt;
+ if (dhcp.getOptions().stream()
+ .anyMatch(dhcpOption -> dhcpOption.getCode() ==
+ DHCP.DHCPOptionCode.OptionCode_MessageType.getValue() &&
+ dhcpOption.getLength() == 1 &&
+ dhcpOption.getData()[0] == DHCPPacketType.DHCPACK.getValue())) {
+ MacAddress hostMac = MacAddress.valueOf(dhcp.getClientHardwareAddress());
+ VlanId hostVlan = VlanId.vlanId(eth.getVlanID());
+ HostId hostId = HostId.hostId(hostMac, hostVlan);
+ updateIp(hostId, IpAddress.valueOf(dhcp.getYourIPAddress()));
+ }
+ }
+ }
+ }
updateLocation(hid, srcMac, vlan, hloc);
//