CORD-1888 Use DAD to probe if interface MAC is not configured

Change-Id: I67bfdbc355e331903b4b7310e4fa9a79f962aa5c
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
index 11a8425..18169bb 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
@@ -15,6 +15,9 @@
  */
 package org.onosproject.segmentrouting.config;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.SetMultimap;
@@ -136,6 +139,7 @@
                 ConnectPoint connectPoint = networkInterface.connectPoint();
                 DeviceId dpid = connectPoint.deviceId();
                 PortNumber port = connectPoint.port();
+                MacAddress mac = networkInterface.mac();
                 SegmentRouterInfo info = deviceConfigMap.get(dpid);
 
                 // skip if there is no corresponding device for this ConenctPoint
@@ -158,6 +162,16 @@
                             info.subnets.put(port, interfaceAddress.subnetAddress());
                         }
                     });
+
+                    // Override interface mac with router mac
+                    if (!mac.equals(info.mac)) {
+                        ArrayNode array = (ArrayNode) config.node();
+                        for (JsonNode intfNode : array) {
+                            ObjectNode objNode = (ObjectNode) intfNode;
+                            objNode.put(InterfaceConfig.MAC, info.mac.toString());
+                        }
+                        srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
+                    }
                 }
             });
             // We register the connect point with the NRS.
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 f6c5856..66159f7 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
@@ -29,6 +29,7 @@
 import org.onlab.packet.VlanId;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.net.intf.Interface;
 import org.onosproject.net.intf.InterfaceService;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.edge.EdgePortService;
@@ -63,7 +64,6 @@
 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.onosproject.security.AppPermission.Type.HOST_EVENT;
 import static org.onosproject.security.AppPermission.Type.HOST_READ;
@@ -349,7 +349,7 @@
 
             // 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.
+            // overwrite the learnt information with the configured information.
             if (greedyLearningIpv6) {
                 // Auto-generation of the IPv6 link local address
                 // using the mac address
@@ -365,19 +365,18 @@
                     }
                     // 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())
-                        );
+                        // Use DAD to probe if interface MAC is not specified
+                        MacAddress probeMac = interfaceService.getInterfacesByPort(hostDescription.location())
+                                .stream().map(Interface::mac).findFirst().orElse(MacAddress.ONOS);
+                        Ip6Address probeIp = !probeMac.equals(MacAddress.ONOS) ?
+                                Ip6Address.valueOf(getLinkLocalAddress(probeMac.toBytes())) :
+                                Ip6Address.ZERO;
                         // We send a probe using the monitoring service
                         monitor.sendProbe(
                                 hostDescription.location(),
                                 targetIp6Address,
-                                onosIp6Address,
-                                onosMacAddress,
+                                probeIp,
+                                probeMac,
                                 hostId.vlanId()
                         );
                     }
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 950bedd..3d9861c 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
@@ -18,6 +18,8 @@
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv6;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -194,28 +196,26 @@
             intf.ipAddressesList().stream()
                     .filter(ia -> ia.subnetAddress().contains(targetIp))
                     .forEach(ia -> {
-                        log.debug("Sending probe for target:{} out of intf:{} vlan:{}",
-                                targetIp, intf.connectPoint(), intf.vlan());
-                        sendProbe(intf.connectPoint(), targetIp, ia.ipAddress(),
-                                intf.mac(), intf.vlan());
+                        MacAddress probeMac = intf.mac();
+                        IpAddress probeIp = !probeMac.equals(MacAddress.ONOS) ?
+                                ia.ipAddress() :
+                                (ia.ipAddress().isIp4() ? Ip4Address.ZERO : Ip6Address.ZERO);
+                        sendProbe(intf.connectPoint(), targetIp, probeIp, probeMac, intf.vlan());
+
                         // account for use-cases where tagged-vlan config is used
                         if (!intf.vlanTagged().isEmpty()) {
                             intf.vlanTagged().forEach(tag -> {
-                                log.debug("Sending probe for target:{} out of intf:{} vlan:{}",
-                                        targetIp, intf.connectPoint(), tag);
-                                sendProbe(intf.connectPoint(), targetIp, ia.ipAddress(),
-                                        intf.mac(), tag);
+                                sendProbe(intf.connectPoint(), targetIp, probeIp, probeMac, tag);
                             });
                         }
                     });
         });
     }
 
-    public 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) {
+        log.debug("Sending probe for target:{} out of intf:{} vlan:{}", targetIp, connectPoint, vlan);
+
         Ethernet probePacket;
 
         if (targetIp.isIp4()) {