Trace IPv6 hosts

ONOS-511: Implement NeighborSolicitation

Change-Id: I9aaf35d499cfc7885c74f9c4bf281210ef9f3969

ONOS-507: Trace NeighborSolicitation/NeighborAdvertisement/IPv6 packets in HostLocationProvider
	* Complete Javadoc of IPv6, ICMP6, NeighborAdvertisement and NeighborSolicitation
		- The Javadoc for serialize() is removed since the one in its superclass just works fine.
	* Change 'diffServ' in IPv6 to 'trafficClass' to meet the field name in RFC.
		- The setter method, getter method and unit test are also updated accordingly.
	* Add IpAddress.isZero() to determine if this address is zero.
		- The unit test is also updated accordingly.
	* Fix misuse of IpAddress.valueOf(int) in HostLocationProvider

Change-Id: Id0d873aeb1bc61bf26d4964e7aab4bb06ccd0a38
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 f2a5b6c..b8a93bb 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
@@ -46,6 +46,10 @@
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.IPacket;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.NeighborAdvertisement;
+import org.onlab.packet.NeighborSolicitation;
 import org.onlab.packet.VlanId;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
@@ -155,22 +159,43 @@
 
             HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
 
-            // Potentially a new or moved host
+            // ARP: possible new hosts, update both location and IP
             if (eth.getEtherType() == Ethernet.TYPE_ARP) {
                 ARP arp = (ARP) eth.getPayload();
-                IpAddress ip =
-                        IpAddress.valueOf(IpAddress.Version.INET,
-                                          arp.getSenderProtocolAddress());
+                IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET, arp.getSenderProtocolAddress());
                 HostDescription hdescr =
                         new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
                 providerService.hostDetected(hid, hdescr);
 
+            // IPv4: update location only
             } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
-                //Do not learn new ip from ip packet.
                 HostDescription hdescr =
                         new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
                 providerService.hostDetected(hid, hdescr);
 
+            // NeighborAdvertisement and NeighborSolicitation: possible new hosts, update both location and IP
+            // IPv6: update location only
+            } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
+                IpAddress ip = null;
+                IPv6 ipv6 = (IPv6) eth.getPayload();
+
+                IPacket iPkt = ipv6;
+                while (iPkt != null) {
+                    if (iPkt instanceof NeighborAdvertisement || iPkt instanceof NeighborSolicitation) {
+                        IpAddress sourceAddress =
+                                IpAddress.valueOf(IpAddress.Version.INET6, ipv6.getSourceAddress());
+                        // Ignore DAD packets, in which source address is all zeros.
+                        if (!sourceAddress.isZero()) {
+                            ip = sourceAddress;
+                            break;
+                        }
+                    }
+                    iPkt = iPkt.getPayload();
+                }
+                HostDescription hdescr = (ip == null) ?
+                        new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc) :
+                        new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
+                providerService.hostDetected(hid, hdescr);
             }
         }
     }