Pavlin Radoslavov

Added IPv6 support to HostMonitor

This fixes ONOS-635

Change-Id: I49cb135af38d54298ba950d5ce1cc110a6f3184d
...@@ -19,9 +19,14 @@ import org.jboss.netty.util.Timeout; ...@@ -19,9 +19,14 @@ import org.jboss.netty.util.Timeout;
19 import org.jboss.netty.util.TimerTask; 19 import org.jboss.netty.util.TimerTask;
20 import org.onlab.packet.ARP; 20 import org.onlab.packet.ARP;
21 import org.onlab.packet.Ethernet; 21 import org.onlab.packet.Ethernet;
22 +import org.onlab.packet.ICMP6;
22 import org.onlab.packet.IpAddress; 23 import org.onlab.packet.IpAddress;
24 +import org.onlab.packet.Ip4Address;
25 +import org.onlab.packet.IPv6;
23 import org.onlab.packet.MacAddress; 26 import org.onlab.packet.MacAddress;
24 import org.onlab.packet.VlanId; 27 import org.onlab.packet.VlanId;
28 +import org.onlab.packet.ndp.NeighborDiscoveryOptions;
29 +import org.onlab.packet.ndp.NeighborSolicitation;
25 import org.onlab.util.Timer; 30 import org.onlab.util.Timer;
26 import org.onosproject.net.ConnectPoint; 31 import org.onosproject.net.ConnectPoint;
27 import org.onosproject.net.Device; 32 import org.onosproject.net.Device;
...@@ -149,7 +154,7 @@ public class HostMonitor implements TimerTask { ...@@ -149,7 +154,7 @@ public class HostMonitor implements TimerTask {
149 Set<Host> hosts = hostManager.getHostsByIp(ip); 154 Set<Host> hosts = hostManager.getHostsByIp(ip);
150 155
151 if (hosts.isEmpty()) { 156 if (hosts.isEmpty()) {
152 - sendArpRequest(ip); 157 + sendArpNdpRequest(ip);
153 } else { 158 } else {
154 for (Host host : hosts) { 159 for (Host host : hosts) {
155 HostProvider provider = hostProviders.get(host.providerId()); 160 HostProvider provider = hostProviders.get(host.providerId());
...@@ -166,12 +171,13 @@ public class HostMonitor implements TimerTask { ...@@ -166,12 +171,13 @@ public class HostMonitor implements TimerTask {
166 } 171 }
167 172
168 /** 173 /**
169 - * Sends an ARP request for the given IP address. 174 + * Sends an ARP or Neighbor Discovery Protocol request for the given IP
175 + * address.
170 * 176 *
171 - * @param targetIp IP address to ARP for 177 + * @param targetIp IP address to send the request for
172 */ 178 */
173 - private void sendArpRequest(IpAddress targetIp) { 179 + private void sendArpNdpRequest(IpAddress targetIp) {
174 - // Find ports with an IP address in the target's subnet and sent ARP 180 + // Find ports with an IP address in the target's subnet and sent ARP/ND
175 // probes out those ports. 181 // probes out those ports.
176 for (Device device : deviceService.getDevices()) { 182 for (Device device : deviceService.getDevices()) {
177 for (Port port : deviceService.getPorts(device.id())) { 183 for (Port port : deviceService.getPorts(device.id())) {
...@@ -182,9 +188,10 @@ public class HostMonitor implements TimerTask { ...@@ -182,9 +188,10 @@ public class HostMonitor implements TimerTask {
182 for (PortAddresses portAddresses : portAddressSet) { 188 for (PortAddresses portAddresses : portAddressSet) {
183 for (InterfaceIpAddress ia : portAddresses.ipAddresses()) { 189 for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
184 if (ia.subnetAddress().contains(targetIp)) { 190 if (ia.subnetAddress().contains(targetIp)) {
185 - sendProbe(device.id(), port, targetIp, 191 + sendArpNdpProbe(device.id(), port, targetIp,
186 - ia.ipAddress(), portAddresses.mac(), 192 + ia.ipAddress(),
187 - portAddresses.vlan()); 193 + portAddresses.mac(),
194 + portAddresses.vlan());
188 } 195 }
189 } 196 }
190 } 197 }
...@@ -192,26 +199,38 @@ public class HostMonitor implements TimerTask { ...@@ -192,26 +199,38 @@ public class HostMonitor implements TimerTask {
192 } 199 }
193 } 200 }
194 201
195 - private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp, 202 + private void sendArpNdpProbe(DeviceId deviceId, Port port,
196 - IpAddress sourceIp, MacAddress sourceMac, VlanId vlan) { 203 + IpAddress targetIp,
197 - Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan); 204 + IpAddress sourceIp, MacAddress sourceMac,
205 + VlanId vlan) {
206 + Ethernet probePacket = null;
207 +
208 + if (targetIp.version() == Ip4Address.VERSION) {
209 + // IPv4: Use ARP
210 + probePacket = buildArpRequest(targetIp, sourceIp, sourceMac,
211 + vlan);
212 + } else {
213 + // IPv6: Use Neighbor Discovery
214 + probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac,
215 + vlan);
216 + }
198 217
199 List<Instruction> instructions = new ArrayList<>(); 218 List<Instruction> instructions = new ArrayList<>();
200 instructions.add(Instructions.createOutput(port.number())); 219 instructions.add(Instructions.createOutput(port.number()));
201 220
202 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 221 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
203 - .setOutput(port.number()) 222 + .setOutput(port.number())
204 - .build(); 223 + .build();
205 224
206 OutboundPacket outboundPacket = 225 OutboundPacket outboundPacket =
207 - new DefaultOutboundPacket(deviceId, treatment, 226 + new DefaultOutboundPacket(deviceId, treatment,
208 - ByteBuffer.wrap(arpPacket.serialize())); 227 + ByteBuffer.wrap(probePacket.serialize()));
209 228
210 packetService.emit(outboundPacket); 229 packetService.emit(outboundPacket);
211 } 230 }
212 231
213 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp, 232 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
214 - MacAddress sourceMac, VlanId vlan) { 233 + MacAddress sourceMac, VlanId vlan) {
215 234
216 ARP arp = new ARP(); 235 ARP arp = new ARP();
217 arp.setHardwareType(ARP.HW_TYPE_ETHERNET) 236 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
...@@ -237,4 +256,44 @@ public class HostMonitor implements TimerTask { ...@@ -237,4 +256,44 @@ public class HostMonitor implements TimerTask {
237 256
238 return ethernet; 257 return ethernet;
239 } 258 }
259 +
260 + private Ethernet buildNdpRequest(IpAddress targetIp, IpAddress sourceIp,
261 + MacAddress sourceMac, VlanId vlan) {
262 +
263 + // Create the Ethernet packet
264 + Ethernet ethernet = new Ethernet();
265 + ethernet.setEtherType(Ethernet.TYPE_IPV6)
266 + .setDestinationMACAddress(MacAddress.BROADCAST)
267 + .setSourceMACAddress(sourceMac);
268 + if (!vlan.equals(VlanId.NONE)) {
269 + ethernet.setVlanID(vlan.toShort());
270 + }
271 +
272 + //
273 + // Create the IPv6 packet
274 + //
275 + // TODO: The destination IP address should be the
276 + // solicited-node multicast address
277 + IPv6 ipv6 = new IPv6();
278 + ipv6.setSourceAddress(sourceIp.toOctets());
279 + ipv6.setDestinationAddress(targetIp.toOctets());
280 + ipv6.setHopLimit((byte) 255);
281 +
282 + // Create the ICMPv6 packet
283 + ICMP6 icmp6 = new ICMP6();
284 + icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION);
285 + icmp6.setIcmpCode((byte) 0);
286 +
287 + // Create the Neighbor Solication packet
288 + NeighborSolicitation ns = new NeighborSolicitation();
289 + ns.setTargetAddress(targetIp.toOctets());
290 + ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS,
291 + sourceMac.toBytes());
292 +
293 + icmp6.setPayload(ns);
294 + ipv6.setPayload(icmp6);
295 + ethernet.setPayload(ipv6);
296 +
297 + return ethernet;
298 + }
240 } 299 }
......