CORD-2870: Bypass DHCP leasequery without learning routes.

  Changes:
    * Add configuration flag to disable old leasequery routing/learning flow
    * Route leasequery (v4 and v6) responses to an originator
    * Fix NPE and BufferOverflow exceptions in Dhcp6LeaseQueryOption
    * Make Dhcp4/Dhcp6HandlerUtil classes static
    * Fix codestyle issues

Change-Id: Ic9e527d73a226e7f1f544dab9fb98398b85c5460
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index e60cad8..73ddc5f 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -20,11 +20,12 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Deactivate;
 import com.google.common.collect.Sets;
 import com.google.common.collect.ImmutableSet;
+import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
@@ -54,6 +55,8 @@
 import org.onlab.packet.dhcp.Dhcp6Duid;
 import org.onlab.packet.DHCP6.MsgType;
 import org.onlab.util.HexString;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.dhcprelay.api.DhcpHandler;
@@ -83,7 +86,6 @@
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.host.DefaultHostDescription;
 import org.onosproject.net.host.HostDescription;
-import org.onosproject.net.host.InterfaceIpAddress;
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.intf.Interface;
@@ -101,17 +103,18 @@
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketService;
+import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.dhcprelay.Dhcp6HandlerUtil.InternalPacket;
 import java.nio.ByteBuffer;
-import java.util.List;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Dictionary;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
-import java.util.ArrayList;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -132,6 +135,7 @@
     public static final ProviderId PROVIDER_ID = new ProviderId("dhcp6", DHCP_V6_RELAY_APP);
     private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
     private String gCount = "global";
+    private static final String LQ_ROUTE_PROPERTY_NAME = "learnRouteFromLeasequery";
     private static final TrafficSelector CLIENT_SERVER_SELECTOR = DefaultTrafficSelector.builder()
             .matchEthType(Ethernet.TYPE_IPV6)
             .matchIPProtocol(IPv6.PROTOCOL_UDP)
@@ -194,12 +198,18 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected FlowObjectiveService flowObjectiveService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
+    @Property(name = Dhcp6HandlerImpl.LQ_ROUTE_PROPERTY_NAME, boolValue = false,
+            label = "Enable learning routing information from LQ")
+    private Boolean learnRouteFromLeasequery = Boolean.TRUE;
+
     protected HostProviderService providerService;
     protected ApplicationId appId;
     protected Multimap<DeviceId, VlanId> ignoredVlans = Multimaps.synchronizedMultimap(HashMultimap.create());
     private InternalHostListener hostListener = new InternalHostListener();
     private Boolean dhcpFpmEnabled = false;
-    private Dhcp6HandlerUtil dhcp6HandlerUtil = new Dhcp6HandlerUtil();
     private List<DhcpServerInfo> defaultServerInfoList = new CopyOnWriteArrayList<>();
     private List<DhcpServerInfo> indirectServerInfoList = new CopyOnWriteArrayList<>();
 
@@ -236,7 +246,9 @@
                             DHCP6.MsgType.LEASEQUERY_REPLY.value());
 
     @Activate
-    protected void activate() {
+    protected void activate(ComponentContext context) {
+        cfgService.registerProperties(getClass());
+        modified(context);
         appId = coreService.registerApplication(DHCP_V6_RELAY_APP);
         providerService = providerRegistry.register(this);
         hostService.addListener(hostListener);
@@ -244,6 +256,7 @@
 
     @Deactivate
     protected void deactivate() {
+        cfgService.unregisterProperties(getClass(), false);
         providerRegistry.unregister(this);
         hostService.removeListener(hostListener);
         defaultServerInfoList.forEach(this::stopMonitoringIps);
@@ -252,6 +265,18 @@
         indirectServerInfoList.clear();
     }
 
+    @Modified
+    protected void modified(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+        Boolean flag;
+        flag = Tools.isPropertyEnabled(properties, Dhcp6HandlerImpl.LQ_ROUTE_PROPERTY_NAME);
+        if (flag != null) {
+            learnRouteFromLeasequery = flag;
+            log.info("Learning routes from DHCP leasequery is {}",
+                    learnRouteFromLeasequery ? "enabled" : "disabled");
+        }
+    }
+
     private void stopMonitoringIps(DhcpServerInfo serverInfo) {
         serverInfo.getDhcpGatewayIp6().ifPresent(gatewayIp -> {
             hostService.stopMonitoringIp(gatewayIp);
@@ -307,7 +332,7 @@
 
     public DhcpRecord getDhcpRelayRecordFor(Ip6Address clientAddress) {
 
-        Collection<DhcpRecord>  records = dhcpRelayStore.getDhcpRecords();
+        Collection<DhcpRecord> records = dhcpRelayStore.getDhcpRecords();
         DhcpRecord dr = null;
         for (DhcpRecord e:records) {
             if (e.ip6Address().isPresent()) {
@@ -478,7 +503,7 @@
         ConnectPoint inPort = context.inPacket().receivedFrom();
 
         if (inPort == null) {
-            log.warn("incomming ConnectPoint is null");
+            log.warn("incoming ConnectPoint is null");
         }
         Set<Interface> receivingInterfaces = interfaceService.getInterfacesByPort(inPort);
         //ignore the packets if dhcp client interface is not configured on onos.
@@ -488,20 +513,21 @@
         }
 
         if (msgTypeVal == DHCP6.MsgType.LEASEQUERY.value()) {
-            List<InternalPacket> ethernetClientPacket =
-                    processLQ6PacketFromClient(context, receivedPacket, receivingInterfaces, dhcp6Payload);
-            for (InternalPacket internalPacket : ethernetClientPacket) {
+            List<InternalPacket> ethernetClientPackets =
+                    learnRouteFromLeasequery ?
+                        processLQ6PacketFromClient(context, receivedPacket, receivingInterfaces, dhcp6Payload) :
+                        processDhcp6ForwardOnly(context, receivedPacket, receivingInterfaces, dhcp6Payload);
+            for (InternalPacket internalPacket : ethernetClientPackets) {
                 forwardPacket(internalPacket);
             }
-        } else if (msgTypeVal == DHCP6.MsgType.LEASEQUERY_REPLY.value()) {
-
+        } else if (msgTypeVal == DHCP6.MsgType.LEASEQUERY_REPLY.value() && learnRouteFromLeasequery) {
             IPv6 clientIpv6 = (IPv6) receivedPacket.getPayload();
             UDP clientUdp = (UDP) clientIpv6.getPayload();
             DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
-            Interface serverInterface = dhcp6HandlerUtil.directlyConnected(clientDhcp6) ?
+            Interface serverInterface = Dhcp6HandlerUtil.directlyConnected(clientDhcp6) ?
                     getServerInterface() : getIndirectServerInterface();
             InternalPacket ethernetPacketReply =
-                    dhcp6HandlerUtil.processLQ6PacketFromServer(
+                    Dhcp6HandlerUtil.processLQ6PacketFromServer(
                             defaultServerInfoList, indirectServerInfoList,
                             serverInterface, interfaceService,
                             hostService,
@@ -510,24 +536,21 @@
                 forwardPacket(ethernetPacketReply);
             }
             handleLeaseQuery6ReplyMsg(context, dhcp6Payload);
-        } else {
-            if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) {
-
-                List<InternalPacket> ethernetClientPacket =
-                        processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
-                for (InternalPacket internalPacket : ethernetClientPacket) {
-                    forwardPacket(internalPacket);
-                }
-            } else if (MSG_TYPE_FROM_SERVER.contains(msgTypeVal)) {
-                log.debug("calling processDhcp6PacketFromServer with RELAY_REPL {}", msgTypeVal);
-                InternalPacket ethernetPacketReply =
-                        processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
-                if (ethernetPacketReply != null) {
-                    forwardPacket(ethernetPacketReply);
-                }
-            } else {
-                log.warn("Not so fast, packet type {} not supported yet", msgTypeVal);
+        } else if (MSG_TYPE_FROM_CLIENT.contains(msgTypeVal)) {
+            List<InternalPacket> ethernetClientPacket =
+                    processDhcp6PacketFromClient(context, receivedPacket, receivingInterfaces);
+            for (InternalPacket internalPacket : ethernetClientPacket) {
+                forwardPacket(internalPacket);
             }
+        } else if (MSG_TYPE_FROM_SERVER.contains(msgTypeVal)) {
+            log.debug("calling processDhcp6PacketFromServer with RELAY_REPL {}, {}", receivedPacket, dhcp6Payload);
+            InternalPacket ethernetPacketReply =
+                    processDhcp6PacketFromServer(context, receivedPacket, receivingInterfaces);
+            if (ethernetPacketReply != null) {
+                forwardPacket(ethernetPacketReply);
+            }
+        } else {
+            log.warn("Not so fast, packet type {} not supported yet", msgTypeVal);
         }
     }
 
@@ -553,16 +576,21 @@
     //forward the packet to ConnectPoint where the DHCP server is attached.
     private void forwardPacket(InternalPacket packet) {
         //send Packetout to dhcp server connectpoint.
-        if (packet.destLocation != null) {
+        if (packet.getDestLocation() != null) {
             TrafficTreatment t = DefaultTrafficTreatment.builder()
-                    .setOutput(packet.destLocation.port()).build();
+                    .setOutput(packet.getDestLocation().port()).build();
             OutboundPacket o = new DefaultOutboundPacket(
-                    packet.destLocation.deviceId(), t, ByteBuffer.wrap(packet.packet.serialize()));
-            if (log.isTraceEnabled()) {
-                log.trace("Relaying packet to destination {}", packet.destLocation);
-            }
+                    packet.getDestLocation().deviceId(), t, ByteBuffer.wrap(packet.getPacket().serialize()));
             packetService.emit(o);
-        } // if
+            if (log.isTraceEnabled()) {
+                IPv6 ip6 = (IPv6) packet.getPacket().getPayload();
+                UDP udp = (UDP) ip6.getPayload();
+                DHCP6 dhcp6  = (DHCP6) udp.getPayload();
+                log.trace("Relaying packet to destination {} eth: {} dhcp: {}",
+                        packet.getDestLocation(), packet.getPacket(), dhcp6);
+            }
+
+        }
     }
 
     /**
@@ -683,7 +711,7 @@
                     .findFirst()
                     .orElse(null);
         } else {
-            DHCP6 leafDhcp = dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Payload);
+            DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Payload);
             clientIdOption = leafDhcp.getOptions()
                     .stream()
                     .filter(opt -> opt instanceof Dhcp6ClientIdOption)
@@ -740,7 +768,7 @@
             record = record.clone();
         }
 
-        Boolean isMsgRelease = dhcp6HandlerUtil.isDhcp6Release(dhcp6Packet);
+        Boolean isMsgRelease = Dhcp6HandlerUtil.isDhcp6Release(dhcp6Packet);
         IpAddressInfo ipInfo;
         PdPrefixInfo pdInfo = null;
         if (directConnFlag) {
@@ -767,7 +795,7 @@
                 return;
             }
 
-            DHCP6 leafDhcp = dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Packet);
+            DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(dhcp6Packet);
             ipInfo = extractIpAddress(leafDhcp);
             if (ipInfo == null) {
                 log.debug("ip is null");
@@ -822,7 +850,7 @@
         }
 
         if (record != null) {
-            record.getV6Counters().incrementCounter(dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
+            record.getV6Counters().incrementCounter(Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
             record.addLocation(new HostLocation(location, System.currentTimeMillis()));
             record.ip6Status(DHCP6.MsgType.getType(leafMsgType));
             record.setDirectlyConnected(directConnFlag);
@@ -837,7 +865,7 @@
         try {
             recordSemaphore.acquire();
             try {
-                dhcpRelayCountersStore.incrementCounter(gCount, dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
+                dhcpRelayCountersStore.incrementCounter(gCount, Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
             } finally {
                 // calling release() after a successful acquire()
                 recordSemaphore.release();
@@ -856,13 +884,12 @@
      * @param embeddedDhcp6 the dhcp6 payload within relay
      * @param srcMac client gw/host macAddress
      * @param clientInterface client interface
-     * @param dhcpServerIp6Address DHCP server IP
      */
     private void addHostOrRoute(boolean directConnFlag, ConnectPoint location, DHCP6 dhcp6Relay,
                                 DHCP6 embeddedDhcp6, MacAddress srcMac, Interface clientInterface) {
         log.debug("addHostOrRoute entered.");
         VlanId vlanId = clientInterface.vlan();
-        Boolean isMsgReply = dhcp6HandlerUtil.isDhcp6Reply(dhcp6Relay);
+        Boolean isMsgReply = Dhcp6HandlerUtil.isDhcp6Reply(dhcp6Relay);
         MacAddress leafClientMac;
         Byte leafMsgType;
 
@@ -931,7 +958,7 @@
                 return;
             }
 
-            DHCP6 leafDhcp = dhcp6HandlerUtil.getDhcp6Leaf(embeddedDhcp6);
+            DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(embeddedDhcp6);
             ipInfo = extractIpAddress(leafDhcp);
             if (ipInfo == null) {
                 log.debug("ip is null");
@@ -988,7 +1015,7 @@
             }
         }
 
-        record.getV6Counters().incrementCounter(dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
+        record.getV6Counters().incrementCounter(Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
         record.ip6Status(DHCP6.MsgType.getType(leafMsgType));
         record.setDirectlyConnected(directConnFlag);
         record.updateLastSeen();
@@ -997,7 +1024,7 @@
         try {
             recordSemaphore.acquire();
             try {
-                dhcpRelayCountersStore.incrementCounter(gCount, dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
+                dhcpRelayCountersStore.incrementCounter(gCount, Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
             } finally {
                 // calling release() after a successful acquire()
                 recordSemaphore.release();
@@ -1007,6 +1034,28 @@
         }
     }
 
+    private List<InternalPacket> processDhcp6ForwardOnly(PacketContext context,
+                                                         Ethernet clientPacket,
+                                                         Set<Interface> clientInterfaces,
+                                                         DHCP6 dhcpPacket) {
+        ConnectPoint inPort = context.inPacket().receivedFrom();
+        log.trace("Got DHCPv6 on port {}", inPort);
+        boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(dhcpPacket);
+
+        List<InternalPacket> internalPackets = new ArrayList<>();
+        List<DhcpServerInfo> serverInfoList = findValidServerInfo(directConnFlag);
+
+        for (DhcpServerInfo dhcpServer : serverInfoList) {
+            Ethernet newPacket = Dhcp6HandlerUtil.buildDhcp6PacketFromClient(context,
+                    clientPacket, clientInterfaces, dhcpServer, getServerInterface(dhcpServer));
+            log.trace("Built packet for server {} : {}", dhcpServer, newPacket);
+            internalPackets.add(InternalPacket.internalPacket(newPacket,
+                    dhcpServer.getDhcpServerConnectPoint().get()));
+        }
+
+        return internalPackets;
+    }
+
     private List<InternalPacket> processLQ6PacketFromClient(PacketContext context,
                                                               Ethernet clientPacket,
                                                               Set<Interface> clientInterfaces,
@@ -1048,27 +1097,18 @@
         MacAddress potentialNH = packet.getSourceMAC();
         VlanId vlanId = VlanId.vlanId(packet.getVlanID());
         setPotentialNextHopForIp6InRelayStore(clientAddress, vlanId, potentialNH);
-
         // 3. route this LQ6 to all relevant servers
         IPv6 clientIpv6 = (IPv6) clientPacket.getPayload();
         UDP clientUdp = (UDP) clientIpv6.getPayload();
         DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
 
-        boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(clientDhcp6);
-
-        ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
-        VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
-        Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
-                .stream().filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
-                .findFirst()
-                .orElse(null);
-
+        boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(clientDhcp6);
         List<InternalPacket> internalPackets = new ArrayList<>();
         List<DhcpServerInfo> serverInfoList = findValidServerInfo(directConnFlag);
         List<DhcpServerInfo> copyServerInfoList = new ArrayList<DhcpServerInfo>(serverInfoList);
 
         for (DhcpServerInfo serverInfo : copyServerInfoList) {
-            if (!dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) {
+            if (!Dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) {
                 log.warn("Can't get server connect point, ignore");
                 continue;
             }
@@ -1077,14 +1117,11 @@
                 log.warn("Can't get server interface with host info resolved, ignore");
                 continue;
             }
-
             Interface serverInterface = getServerInterface(newServerInfo);
             if (serverInterface == null) {
                 log.warn("Can't get server interface, ignore");
                 continue;
             }
-
-
             Ethernet etherRouted = (Ethernet) clientPacket.clone();
             MacAddress macFacingServer = serverInterface.mac();
             if (macFacingServer == null) {
@@ -1094,7 +1131,7 @@
             etherRouted.setSourceMACAddress(macFacingServer);
             etherRouted.setDestinationMACAddress(newServerInfo.getDhcpConnectMac().get());
             InternalPacket internalPacket =
-                    new Dhcp6HandlerUtil().new InternalPacket(etherRouted,
+                    InternalPacket.internalPacket(etherRouted,
                               serverInfo.getDhcpServerConnectPoint().get());
             internalPackets.add(internalPacket);
             log.debug("Sending LQ to DHCP server {}", newServerInfo.getDhcpServerIp6());
@@ -1115,8 +1152,7 @@
                                                               Ethernet clientPacket,
                                                               Set<Interface> clientInterfaces) {
         ConnectPoint receivedFrom = context.inPacket().receivedFrom();
-        DeviceId receivedFromDevice = receivedFrom.deviceId();
-        Ip6Address relayAgentIp = dhcp6HandlerUtil.getRelayAgentIPv6Address(clientInterfaces);
+        Ip6Address relayAgentIp = Dhcp6HandlerUtil.getRelayAgentIPv6Address(clientInterfaces);
         MacAddress relayAgentMac = clientInterfaces.iterator().next().mac();
         if (relayAgentIp == null || relayAgentMac == null) {
             log.warn("Missing DHCP relay agent interface Ipv6 addr config for "
@@ -1130,12 +1166,12 @@
         UDP clientUdp = (UDP) clientIpv6.getPayload();
         DHCP6 clientDhcp6 = (DHCP6) clientUdp.getPayload();
 
-        boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(clientDhcp6);
+        boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(clientDhcp6);
 
         ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
         VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
         Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
-                .stream().filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
+                .stream().filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
                 .findFirst()
                 .orElse(null);
 
@@ -1144,7 +1180,7 @@
         List<DhcpServerInfo> copyServerInfoList = new ArrayList<DhcpServerInfo>(serverInfoList);
 
         for (DhcpServerInfo serverInfo : copyServerInfoList) {
-            if (!dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) {
+            if (!Dhcp6HandlerUtil.checkDhcpServerConnPt(directConnFlag, serverInfo)) {
                 log.warn("Can't get server connect point, ignore");
                 continue;
             }
@@ -1160,12 +1196,12 @@
                 continue;
             }
 
-            Ethernet etherReply = dhcp6HandlerUtil.buildDhcp6PacketFromClient(context, clientPacket,
+            Ethernet etherReply = Dhcp6HandlerUtil.buildDhcp6PacketFromClient(context, clientPacket,
                                                               clientInterfaces, newServerInfo, serverInterface);
             removeHostOrRoute(directConnFlag, clientConnectionPoint, clientDhcp6, clientPacket,
                     clientIpv6, clientInterface);
 
-            InternalPacket internalPacket = new Dhcp6HandlerUtil().new InternalPacket(etherReply,
+            InternalPacket internalPacket = InternalPacket.internalPacket(etherReply,
                     serverInfo.getDhcpServerConnectPoint().get());
             internalPackets.add(internalPacket);
         }
@@ -1189,7 +1225,7 @@
         IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
         UDP udpPacket = (UDP) ipv6Packet.getPayload();
         DHCP6 dhcp6Relay = (DHCP6) udpPacket.getPayload();
-        Boolean directConnFlag = dhcp6HandlerUtil.directlyConnected(dhcp6Relay);
+        Boolean directConnFlag = Dhcp6HandlerUtil.directlyConnected(dhcp6Relay);
 
         DHCP6 embeddedDhcp6 = dhcp6Relay.getOptions().stream()
                 .filter(opt -> opt instanceof Dhcp6RelayOption)
@@ -1205,7 +1241,7 @@
             dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_SERVER_INFO);
             return null;
         } else {
-            if (dhcp6HandlerUtil.isServerIpEmpty(foundServerInfo)) {
+            if (Dhcp6HandlerUtil.isServerIpEmpty(foundServerInfo)) {
                 log.warn("Cannot find server info's ipaddress");
                 dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_SERVER_IP6ADDR);
                 return null;
@@ -1228,7 +1264,7 @@
         ConnectPoint clientConnectionPoint = ConnectPoint.deviceConnectPoint(clientConnectionPointStr);
         VlanId vlanIdInUse = VlanId.vlanId(interfaceIdOption.getVlanId());
         Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
-                .stream().filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
+                .stream().filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, vlanIdInUse))
                 .findFirst().orElse(null);
         if (clientInterface == null) {
             log.warn("Cannot get client interface for from packet, abort... vlan {}", vlanIdInUse.toString());
@@ -1274,30 +1310,23 @@
         } else {
             udpPacket.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
         }
-        // add host or route
-        addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6,
-                       clientMac, clientInterface);
 
 
+        boolean hostOrRouteAllowed = learnRouteFromLeasequery ||
+                    Dhcp6HandlerUtil.getDhcp6LeafMessageType(dhcp6Relay) != MsgType.LEASEQUERY_REPLY;
+        log.debug("Can add host or route: {}", hostOrRouteAllowed);
+
+        if (hostOrRouteAllowed) {
+            // add host or route
+            addHostOrRoute(directConnFlag, clientConnectionPoint, dhcp6Relay, embeddedDhcp6,
+                    clientMac, clientInterface);
+        }
+
         udpPacket.setPayload(embeddedDhcp6);
         udpPacket.resetChecksum();
         ipv6Packet.setPayload(udpPacket);
         etherReply.setPayload(ipv6Packet);
-        return new Dhcp6HandlerUtil().new InternalPacket(etherReply, clientConnectionPoint);
-    }
-
-    // Returns the first v6 interface ip out of a set of interfaces or null.
-    // Checks all interfaces, and ignores v6 interface ips
-    private Ip6Address getRelayAgentIPv6Address(Set<Interface> intfs) {
-        for (Interface intf : intfs) {
-            for (InterfaceIpAddress ip : intf.ipAddressesList()) {
-                Ip6Address relayAgentIp = ip.ipAddress().getIp6Address();
-                if (relayAgentIp != null) {
-                    return relayAgentIp;
-                }
-            }
-        }
-        return null;
+        return InternalPacket.internalPacket(etherReply, clientConnectionPoint);
     }
 
     @Override
@@ -1476,23 +1505,6 @@
         }
     }
 
-    /**
-     * Returns the first interface ip from interface.
-     *
-     * @param iface interface of one connect point
-     * @return the first interface IP; null if not exists an IP address in
-     *         these interfaces
-     */
-    private Ip6Address getFirstIpFromInterface(Interface iface) {
-        checkNotNull(iface, "Interface can't be null");
-        return iface.ipAddressesList().stream()
-                .map(InterfaceIpAddress::ipAddress)
-                .filter(IpAddress::isIp6)
-                .map(IpAddress::getIp6Address)
-                .findFirst()
-                .orElse(null);
-    }
-
    /**
      * Gets Interface facing to the server for default host.
      *
@@ -1516,7 +1528,7 @@
         }
         return interfaceService.getInterfacesByPort(dhcpServerConnectPoint)
                 .stream()
-                .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan))
+                .filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan))
                 .findFirst()
                 .orElse(null);
     }
@@ -1546,7 +1558,7 @@
         }
         return interfaceService.getInterfacesByPort(indirectDhcpServerConnectPoint)
                 .stream()
-                .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, indirectDhcpConnectVlan))
+                .filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, indirectDhcpConnectVlan))
                 .findFirst()
                 .orElse(null);
     }
@@ -1615,7 +1627,7 @@
         if (dhcpServerConnectPoint != null && dhcpConnectVlan != null) {
         serverInterface = interfaceService.getInterfacesByPort(dhcpServerConnectPoint)
                     .stream()
-                    .filter(iface -> dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan))
+                    .filter(iface -> Dhcp6HandlerUtil.interfaceContainsVlan(iface, dhcpConnectVlan))
                     .findFirst()
                     .orElse(null);
         } else {