[CORD-783] Greedy learning of IPv6 hosts

- Opportunistic learning of IPv6 link local addresses

Change-Id: Ic94a8239c1ae81fc83453d1a29dfc8bd9803b531
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index fc9304a..a78f093 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -353,6 +353,9 @@
                                       "requestInterceptsEnabled", "false");
         compCfgService.preSetProperty("org.onosproject.dhcprelay.DhcpRelay",
                                       "arpEnabled", "false");
+        compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
+                                      "greedyLearningIpv6", "true");
+
 
         processor = new InternalPacketProcessor();
         linkListener = new InternalLinkListener();
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index a18d4ad..3f5d643 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -23,6 +23,7 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -60,6 +61,8 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
+import static org.onlab.packet.IPv6.getLinkLocalAddress;
+import static org.onosproject.net.link.ProbedLinkProvider.DEFAULT_MAC;
 import static org.onosproject.security.AppGuard.checkPermission;
 import static org.slf4j.LoggerFactory.getLogger;
 import static org.onosproject.security.AppPermission.Type.*;
@@ -104,7 +107,6 @@
 
     @Property(name = "allowDuplicateIps", boolValue = true,
             label = "Enable removal of duplicate ip address")
-
     private boolean allowDuplicateIps = true;
 
     @Property(name = "monitorHosts", boolValue = false,
@@ -115,6 +117,10 @@
             label = "Set the probe Rate in milli seconds")
     private long probeRate = 30000;
 
+    @Property(name = "greedyLearningIpv6", boolValue = false,
+            label = "Enable/Disable greedy learning of IPv6 link local address")
+    private boolean greedyLearningIpv6 = false;
+
     private HostMonitor monitor;
 
 
@@ -197,6 +203,16 @@
                      allowDuplicateIps ? "disabled" : "enabled");
         }
 
+        flag = Tools.isPropertyEnabled(properties, "greedyLearningIpv6");
+        if (flag == null) {
+            log.info("greedy learning is not enabled " +
+                             "using current value of {}", greedyLearningIpv6);
+        } else {
+            greedyLearningIpv6 = flag;
+            log.info("Configured. greedyLearningIpv6 {}",
+                     greedyLearningIpv6 ? "enabled" : "disabled");
+        }
+
     }
 
     /**
@@ -330,6 +346,43 @@
                     monitor.addMonitoringFor(ip);
                 });
             }
+
+            // Greedy learning of IPv6 host. We have to disable the greedy
+            // learning of configured hosts. Validate hosts each time will
+            // overwrite the learnt information with the configured informations.
+            if (greedyLearningIpv6) {
+                // Auto-generation of the IPv6 link local address
+                // using the mac address
+                Ip6Address targetIp6Address = Ip6Address.valueOf(
+                        getLinkLocalAddress(hostId.mac().toBytes())
+                );
+                // If we already know this guy we don't need to do other
+                if (!hostDescription.ipAddress().contains(targetIp6Address)) {
+                    Host host = store.getHost(hostId);
+                    // Configured host, skip it.
+                    if (host != null && host.configured()) {
+                        return;
+                    }
+                    // Host does not exist in the store or the target is not known
+                    if ((host == null || !host.ipAddresses().contains(targetIp6Address))) {
+                        // We generate ONOS ip from the ONOS default mac
+                        // We could use the mac generated for the link
+                        // discovery but maybe does not worth
+                        MacAddress onosMacAddress = MacAddress.valueOf(DEFAULT_MAC);
+                        Ip6Address onosIp6Address = Ip6Address.valueOf(
+                                getLinkLocalAddress(onosMacAddress.toBytes())
+                        );
+                        // We send a probe using the monitoring service
+                        monitor.sendProbe(
+                                hostDescription.location(),
+                                targetIp6Address,
+                                onosIp6Address,
+                                onosMacAddress,
+                                hostId.vlanId()
+                        );
+                    }
+                }
+            }
         }
 
         // When a new IP is detected, remove that IP on other hosts if it exists
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
index 7375105..2e4a435 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
@@ -206,21 +206,20 @@
         }
     }
 
-    private void sendProbe(ConnectPoint connectPoint,
-                           IpAddress targetIp,
-                           IpAddress sourceIp, MacAddress sourceMac,
-                           VlanId vlan) {
+    public void sendProbe(ConnectPoint connectPoint,
+                          IpAddress targetIp,
+                          IpAddress sourceIp,
+                          MacAddress sourceMac,
+                          VlanId vlan) {
         Ethernet probePacket;
 
         if (targetIp.isIp4()) {
             // IPv4: Use ARP
             probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan);
         } else {
-            /*
-             * IPv6: Use Neighbor Discovery. According to the NDP protocol,
-             * we should use the solicitation node address as IPv6 destination
-             * and the multicast mac address as Ethernet destination.
-             */
+             // IPv6: Use Neighbor Discovery. According to the NDP protocol,
+             // we should use the solicitation node address as IPv6 destination
+             // and the multicast mac address as Ethernet destination.
             byte[] destIp = IPv6.getSolicitNodeAddress(targetIp.toOctets());
             probePacket = NeighborSolicitation.buildNdpSolicit(
                     targetIp.toOctets(),