[CORD-458] Updates ARP handler

Changes:
- SR application uses NRM;
- Adds hooks for ND protocol;
- Updates ARP handler to better leverage on NRM;
- Reworks to take into account IPv4/IPv6 together;

Change-Id: Iab55b8c5ef7d973928d8ad47e2c2a482fb9c5c8a
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index 8975de1..246a3bb 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -18,19 +18,19 @@
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.HostId;
-import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.segmentrouting.config.DeviceConfiguration;
 import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
@@ -39,8 +39,10 @@
 
 import java.nio.ByteBuffer;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.incubator.net.neighbour.NeighbourMessageType.REQUEST;
 
 /**
  * Handler of ARP packets that responses or forwards ARP packets that
@@ -81,81 +83,71 @@
      * packet in.
      * We can deal with both cases.
      *
-     * @param pkt incoming packet
+     * @param pkt incoming ARP packet and context information
+     * @param hostService the host service
      */
-    public void processPacketIn(InboundPacket pkt) {
-        Ethernet ethernet = pkt.parsed();
-        ARP arp = (ARP) ethernet.getPayload();
-        ConnectPoint connectPoint = pkt.receivedFrom();
-        DeviceId deviceId = connectPoint.deviceId();
+    public void processPacketIn(NeighbourMessageContext pkt, HostService hostService) {
 
         SegmentRoutingAppConfig appConfig = srManager.cfgService
                 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
-        if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
+        if (appConfig != null && appConfig.suppressSubnet().contains(pkt.inPort())) {
             // Ignore ARP packets come from suppressed ports
             return;
         }
 
-        if (!validateArpSpa(connectPoint, arp)) {
+        if (!validateArpSpa(pkt)) {
             log.debug("Ignore ARP packet discovered on {} with unexpected src protocol address {}.",
-                    connectPoint, Ip4Address.valueOf(arp.getSenderProtocolAddress()));
+                    pkt.inPort(), pkt.sender().getIp4Address());
             return;
         }
 
-        if (arp.getOpCode() == ARP.OP_REQUEST) {
-            handleArpRequest(deviceId, connectPoint, ethernet);
+        if (pkt.type() == REQUEST) {
+            handleArpRequest(pkt, hostService);
         } else {
-            handleArpReply(deviceId, connectPoint, ethernet);
+            handleArpReply(pkt, hostService);
         }
     }
 
-    private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
-        ARP arpRequest = (ARP) payload.getPayload();
-        VlanId vlanId = VlanId.vlanId(payload.getVlanID());
-        HostId targetHostId = HostId.hostId(MacAddress.valueOf(
-                                            arpRequest.getTargetHardwareAddress()),
-                                            vlanId);
-
+    private void handleArpRequest(NeighbourMessageContext pkt, HostService hostService) {
         // ARP request for router. Send ARP reply.
-        if (isArpForRouter(deviceId, arpRequest)) {
-            Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
-            sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId);
+        if (isArpForRouter(pkt)) {
+            MacAddress targetMac = config.getRouterMacForAGatewayIp(pkt.target().getIp4Address());
+            sendArpResponse(pkt, targetMac, hostService);
         } else {
-            Host targetHost = srManager.hostService.getHost(targetHostId);
+            Set<Host> hosts = hostService.getHostsByIp(pkt.target());
+            if (hosts.size() > 1) {
+                log.warn("More than one host with the same ip {}", pkt.target());
+            }
+            Host targetHost = hosts.stream().findFirst().orElse(null);
             // ARP request for known hosts. Send proxy ARP reply on behalf of the target.
             if (targetHost != null) {
-                removeVlanAndForward(payload, targetHost.location());
+                pkt.forward(targetHost.location());
             // ARP request for unknown host in the subnet. Flood in the subnet.
             } else {
-                removeVlanAndFlood(payload, inPort);
+                flood(pkt);
             }
         }
     }
 
-    private void handleArpReply(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
-        ARP arpReply = (ARP) payload.getPayload();
-        VlanId vlanId = VlanId.vlanId(payload.getVlanID());
-        HostId targetHostId = HostId.hostId(MacAddress.valueOf(
-                                            arpReply.getTargetHardwareAddress()),
-                                            vlanId);
-
+    private void handleArpReply(NeighbourMessageContext pkt, HostService hostService) {
         // ARP reply for router. Process all pending IP packets.
-        if (isArpForRouter(deviceId, arpReply)) {
-            Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress());
-            srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
+        if (isArpForRouter(pkt)) {
+            Ip4Address hostIpAddress = pkt.sender().getIp4Address();
+            srManager.ipHandler.forwardPackets(pkt.inPort().deviceId(), hostIpAddress);
         } else {
-            Host targetHost = srManager.hostService.getHost(targetHostId);
+            HostId targetHostId = HostId.hostId(pkt.dstMac(), pkt.vlan());
+            Host targetHost = hostService.getHost(targetHostId);
             // ARP reply for known hosts. Forward to the host.
             if (targetHost != null) {
-                removeVlanAndForward(payload, targetHost.location());
+                pkt.forward(targetHost.location());
             // ARP reply for unknown host, Flood in the subnet.
             } else {
                 // Don't flood to non-edge ports
-                if (vlanId.equals(
+                if (pkt.vlan().equals(
                         VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET))) {
                     return;
                 }
-                removeVlanAndFlood(payload, inPort);
+                flood(pkt);
             }
         }
     }
@@ -164,26 +156,27 @@
      * Check if the source protocol address of an ARP packet belongs to the same
      * subnet configured on the port it is seen.
      *
-     * @param connectPoint connect point where the ARP packet is seen
-     * @param arpPacket ARP packet
+     * @param pkt ARP packet and context information
      * @return true if the source protocol address belongs to the configured subnet
      */
-    private boolean validateArpSpa(ConnectPoint connectPoint, ARP arpPacket) {
-        Ip4Address spa = Ip4Address.valueOf(arpPacket.getSenderProtocolAddress());
-        Ip4Prefix subnet = config.getPortSubnet(connectPoint.deviceId(), connectPoint.port());
-        return subnet != null && subnet.contains(spa);
+    private boolean validateArpSpa(NeighbourMessageContext pkt) {
+        Ip4Address spa = pkt.sender().getIp4Address();
+        Set<IpPrefix> subnet = config.getPortSubnets(pkt.inPort().deviceId(), pkt.inPort().port())
+                .stream()
+                .filter(ipPrefix -> ipPrefix.isIp4() && ipPrefix.contains(spa))
+                .collect(Collectors.toSet());
+        return !subnet.isEmpty();
     }
 
 
-    private boolean isArpForRouter(DeviceId deviceId, ARP arpMsg) {
-        Ip4Address targetProtocolAddress = Ip4Address.valueOf(
-                                               arpMsg.getTargetProtocolAddress());
-        Set<Ip4Address> gatewayIpAddresses = null;
+    private boolean isArpForRouter(NeighbourMessageContext pkt) {
+        Ip4Address targetProtocolAddress = pkt.target().getIp4Address();
+        Set<IpAddress> gatewayIpAddresses = null;
         try {
-            if (targetProtocolAddress.equals(config.getRouterIpv4(deviceId))) {
+            if (targetProtocolAddress.equals(config.getRouterIpv4(pkt.inPort().deviceId()))) {
                 return true;
             }
-            gatewayIpAddresses = config.getPortIPs(deviceId);
+            gatewayIpAddresses = config.getPortIPs(pkt.inPort().deviceId());
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
         }
@@ -207,7 +200,8 @@
 
         try {
             senderMacAddress = config.getDeviceMac(deviceId).toBytes();
-            senderIpAddress = config.getRouterIpv4(deviceId).toOctets();
+            senderIpAddress = config.getRouterIpAddressForASubnetHost(targetAddress.getIp4Address())
+                    .toOctets();
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting sendArpRequest.");
             return;
@@ -230,41 +224,18 @@
                 .setSourceMACAddress(senderMacAddress)
                 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
 
-        removeVlanAndFlood(eth, inPort);
+        flood(eth, inPort);
     }
 
-    private void sendArpResponse(ARP arpRequest, MacAddress targetMac, VlanId vlanId) {
-        ARP arpReply = new ARP();
-        arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
-                .setProtocolType(ARP.PROTO_TYPE_IP)
-                .setHardwareAddressLength(
-                        (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
-                .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
-                .setOpCode(ARP.OP_REPLY)
-                .setSenderHardwareAddress(targetMac.toBytes())
-                .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
-                .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
-                .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
-
-        Ethernet eth = new Ethernet();
-        eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
-                .setSourceMACAddress(targetMac.toBytes())
-                .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
-
-        MacAddress hostMac = MacAddress.valueOf(arpReply.getTargetHardwareAddress());
-        HostId dstId = HostId.hostId(hostMac, vlanId);
-        Host dst = srManager.hostService.getHost(dstId);
+    private void sendArpResponse(NeighbourMessageContext pkt, MacAddress targetMac, HostService hostService) {
+        HostId dstId = HostId.hostId(pkt.srcMac(), pkt.vlan());
+        Host dst = hostService.getHost(dstId);
         if (dst == null) {
-            log.warn("Cannot send ARP response to host {}", dstId);
+            log.warn("Cannot send ARP response to host {} - does not exist in the store",
+                     dstId);
             return;
         }
-
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder().
-                setOutput(dst.location().port()).build();
-        OutboundPacket packet = new DefaultOutboundPacket(dst.location().deviceId(),
-                treatment, ByteBuffer.wrap(eth.serialize()));
-
-        srManager.packetService.emit(packet);
+        pkt.reply(targetMac);
     }
 
     /**
@@ -273,27 +244,54 @@
      * @param packet packet to be flooded
      * @param inPort where the packet comes from
      */
-    private void removeVlanAndFlood(Ethernet packet, ConnectPoint inPort) {
+    private void flood(Ethernet packet, ConnectPoint inPort) {
         Ip4Address targetProtocolAddress = Ip4Address.valueOf(
                 ((ARP) packet.getPayload()).getTargetProtocolAddress()
         );
 
         try {
             srManager.deviceConfiguration
-                 .getSubnetPortsMap(inPort.deviceId()).forEach((subnet, ports) -> {
-                     if (subnet.contains(targetProtocolAddress)) {
+                    .getSubnetPortsMap(inPort.deviceId()).forEach((subnet, ports) -> {
+                if (subnet.contains(targetProtocolAddress)) {
+                    ports.stream()
+                            .filter(port -> port != inPort.port())
+                            .forEach(port -> {
+                                forward(packet, new ConnectPoint(inPort.deviceId(), port));
+                            });
+                }
+            });
+        } catch (DeviceConfigNotFoundException e) {
+            log.warn(e.getMessage()
+                             + " Cannot flood in subnet as device config not available"
+                             + " for device: " + inPort.deviceId());
+        }
+    }
+
+    /**
+     * Remove VLAN tag and flood to all ports in the same subnet.
+     *
+     * @param pkt arp packet to be flooded
+     */
+    private void flood(NeighbourMessageContext pkt) {
+        try {
+            srManager.deviceConfiguration
+                 .getSubnetPortsMap(pkt.inPort().deviceId()).forEach((subnet, ports) -> {
+                     if (subnet.contains(pkt.target())) {
                          ports.stream()
-                         .filter(port -> port != inPort.port())
+                         .filter(port -> port != pkt.inPort().port())
                          .forEach(port -> {
-                             removeVlanAndForward(packet,
-                                 new ConnectPoint(inPort.deviceId(), port));
+                             ConnectPoint outPoint = new ConnectPoint(
+                                     pkt.inPort().deviceId(),
+                                     port
+                             );
+                             pkt.forward(outPoint);
                          });
                      }
                  });
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage()
                     + " Cannot flood in subnet as device config not available"
-                    + " for device: " + inPort.deviceId());
+                    + " for device: " + pkt.inPort().deviceId());
         }
     }
 
@@ -312,9 +310,9 @@
      * @param packet packet to be forwarded
      * @param outPort where the packet should be forwarded
      */
-    private void removeVlanAndForward(Ethernet packet, ConnectPoint outPort) {
+    private void forward(Ethernet packet, ConnectPoint outPort) {
         packet.setEtherType(Ethernet.TYPE_ARP);
-        packet.setVlanID(Ethernet.VLAN_UNTAGGED);
+
         ByteBuffer buf = ByteBuffer.wrap(packet.serialize());
 
         TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java
index 6710330..618c0f0 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java
@@ -102,7 +102,7 @@
 
         // Do not proceed if agent port doesn't have subnet configured
         Ip4Prefix agentSubnet = srManager.deviceConfiguration
-                .getPortSubnet(agentLocation.deviceId(), agentLocation.port());
+                .getPortIPv4Subnet(agentLocation.deviceId(), agentLocation.port());
         if (agentSubnet == null) {
             log.warn("Agent port does not have subnet configuration. Abort.");
             return;
@@ -115,7 +115,7 @@
         accessAgentData.getOltMacInfo().forEach((connectPoint, macAddress) -> {
             // Do not proceed if olt port has subnet configured
             Ip4Prefix oltSubnet = srManager.deviceConfiguration
-                    .getPortSubnet(connectPoint.deviceId(), connectPoint.port());
+                    .getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
             if (oltSubnet != null) {
                 log.warn("OLT port has subnet configuration. Abort.");
                 return;
@@ -149,7 +149,7 @@
 
         // Do not proceed if olt port doesn't have subnet configured
         Ip4Prefix agentSubnet = srManager.deviceConfiguration
-                .getPortSubnet(agentLocation.deviceId(), agentLocation.port());
+                .getPortIPv4Subnet(agentLocation.deviceId(), agentLocation.port());
         if (agentSubnet == null) {
             log.warn("Agent port does not have subnet configuration. Abort.");
             return;
@@ -162,7 +162,7 @@
         accessAgentData.getOltMacInfo().forEach((connectPoint, macAddress) -> {
             // Do not proceed if agent port doesn't have subnet configured
             Ip4Prefix oltSubnet = srManager.deviceConfiguration
-                    .getPortSubnet(connectPoint.deviceId(), connectPoint.port());
+                    .getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
             if (oltSubnet == null) {
                 log.warn("OLT port does not have subnet configuration. Abort.");
                 return;
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index a689aec..4893684 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -21,7 +21,6 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.net.ConnectPoint;
@@ -505,7 +504,7 @@
      */
     private boolean populateEcmpRoutingRules(DeviceId destSw,
                                              EcmpShortestPathGraph ecmpSPG,
-                                             Set<Ip4Prefix> subnets) {
+                                             Set<IpPrefix> subnets) {
 
         HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
                 .getAllLearnedSwitchesAndVia();
@@ -543,7 +542,7 @@
     private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
                                                    DeviceId destSw,
                                                    Set<DeviceId> nextHops,
-                                                   Set<Ip4Prefix> subnets) {
+                                                   Set<IpPrefix> subnets) {
         boolean result;
 
         if (nextHops.isEmpty()) {
@@ -704,7 +703,7 @@
      * @param subnets subnet being added
      * @return true if succeed
      */
-    protected boolean populateSubnet(ConnectPoint cp, Set<Ip4Prefix> subnets) {
+    protected boolean populateSubnet(ConnectPoint cp, Set<IpPrefix> subnets) {
         statusLock.lock();
         try {
             EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(cp.deviceId());
@@ -724,7 +723,7 @@
      * @param subnets subnet being removed
      * @return true if succeed
      */
-    protected boolean revokeSubnet(Set<Ip4Prefix> subnets) {
+    protected boolean revokeSubnet(Set<IpPrefix> subnets) {
         statusLock.lock();
         try {
             return srManager.routingRulePopulator.revokeIpRuleForSubnet(subnets);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index 82a2829..c3022ff 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -257,7 +257,8 @@
             PortNumber outport) {
         // Get assigned VLAN for the subnets
         VlanId outvlan = null;
-        Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outport);
+        // FIXME L2 forwarding should consider also IPv6
+        Ip4Prefix subnet = srManager.deviceConfiguration.getPortIPv4Subnet(deviceId, outport);
         if (subnet == null) {
             outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
         } else {
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index dc217ee..80b233b 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -22,6 +22,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MPLS;
+import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -77,7 +78,7 @@
         DeviceId deviceId = connectPoint.deviceId();
         Ip4Address destinationAddress =
                 Ip4Address.valueOf(ipv4.getDestinationAddress());
-        Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
+        Set<IpAddress> gatewayIpAddresses = config.getPortIPs(deviceId);
         IpAddress routerIp;
         try {
             routerIp = config.getRouterIpv4(deviceId);
@@ -111,6 +112,19 @@
     }
 
     /**
+     * Process incoming ICMP packet.
+     * If it is an ICMP request to router or known host, then sends an ICMP response.
+     * If it is an ICMP packet to known host and forward the packet to the host.
+     * If it is an ICMP packet to unknown host in a subnet, then sends an ARP request
+     * to the subnet.
+     *
+     * @param pkt inbound packet
+     */
+    public void processPacketIn(NeighbourMessageContext pkt) {
+
+    }
+
+    /**
      * Sends an ICMP reply message.
      *
      * Note: we assume that packets sending from the edge switches to the hosts
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
index 36dc26b..f95addc 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/McastHandler.java
@@ -376,7 +376,7 @@
         }
 
         // Reuse unicast VLAN if the port has subnet configured
-        Ip4Prefix portSubnet = srManager.deviceConfiguration.getPortSubnet(deviceId, port);
+        Ip4Prefix portSubnet = srManager.deviceConfiguration.getPortIPv4Subnet(deviceId, port);
         VlanId unicastVlan = srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
         final VlanId finalVlanId = (unicastVlan != null) ? unicastVlan : assignedVlan;
 
@@ -764,7 +764,7 @@
         // Reuse unicast VLAN if the port has subnet configured
         if (cp != null) {
             Ip4Prefix portSubnet = srManager.deviceConfiguration
-                    .getPortSubnet(cp.deviceId(), cp.port());
+                    .getPortIPv4Subnet(cp.deviceId(), cp.port());
             VlanId unicastVlan = srManager.getSubnetAssignedVlanId(cp.deviceId(), portSubnet);
             if (unicastVlan != null) {
                 return unicastVlan;
@@ -791,7 +791,7 @@
             for (PortNumber port : ports) {
                 // Spine-facing port should have no subnet and no xconnect
                 if (srManager.deviceConfiguration != null &&
-                        srManager.deviceConfiguration.getPortSubnet(ingressDevice, port) == null &&
+                        srManager.deviceConfiguration.getPortSubnets(ingressDevice, port).isEmpty() &&
                         !srManager.xConnectHandler.hasXConnect(new ConnectPoint(ingressDevice, port))) {
                     return port;
                 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 2c2f1eb..757e408 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -203,7 +203,7 @@
         // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
         // for switch pipelines that need it, provide outgoing vlan as metadata
         VlanId outvlan = null;
-        Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outPort);
+        Ip4Prefix subnet = srManager.deviceConfiguration.getPortIPv4Subnet(deviceId, outPort);
         if (subnet == null) {
             outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
         } else {
@@ -234,7 +234,7 @@
      * @param nextHops next hop switch ID list
      * @return true if all rules are set successfully, false otherwise
      */
-    public boolean populateIpRuleForSubnet(DeviceId deviceId, Set<Ip4Prefix> subnets,
+    public boolean populateIpRuleForSubnet(DeviceId deviceId, Set<IpPrefix> subnets,
             DeviceId destSw, Set<DeviceId> nextHops) {
         for (IpPrefix subnet : subnets) {
             if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
@@ -250,7 +250,7 @@
      * @param subnets subnet being removed
      * @return true if all rules are removed successfully, false otherwise
      */
-    public boolean revokeIpRuleForSubnet(Set<Ip4Prefix> subnets) {
+    public boolean revokeIpRuleForSubnet(Set<IpPrefix> subnets) {
         for (IpPrefix subnet : subnets) {
             if (!revokeIpRuleForRouter(subnet)) {
                 return false;
@@ -597,7 +597,7 @@
                 suppressedPorts++;
             }
 
-            Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
+            Ip4Prefix portSubnet = config.getPortIPv4Subnet(deviceId, port.number());
             VlanId assignedVlan = (portSubnet == null || isSuppressed)
                     ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
                     : srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
@@ -785,7 +785,8 @@
     public void populateSubnetBroadcastRule(DeviceId deviceId) {
         config.getSubnets(deviceId).forEach(subnet -> {
             if (subnet.prefixLength() == 0 ||
-                    subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH) {
+                    subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
+                    subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
                 return;
             }
             int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet);
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 fea2824..b6a6219 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -24,6 +24,7 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
+import org.onlab.packet.IPv6;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.VlanId;
@@ -34,10 +35,12 @@
 import org.onosproject.event.Event;
 import org.onosproject.incubator.net.config.basics.McastConfig;
 import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.incubator.net.neighbour.NeighbourResolutionService;
 import org.onosproject.incubator.net.routing.RouteEvent;
 import org.onosproject.incubator.net.routing.RouteListener;
 import org.onosproject.incubator.net.routing.RouteService;
 import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
@@ -56,27 +59,27 @@
 import org.onosproject.net.flowobjective.FlowObjectiveService;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.link.LinkListener;
+import org.onosproject.net.link.LinkService;
 import org.onosproject.net.mcast.McastEvent;
 import org.onosproject.net.mcast.McastListener;
 import org.onosproject.net.mcast.MulticastRouteService;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.topology.TopologyService;
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
 import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
+import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
 import org.onosproject.segmentrouting.config.XConnectConfig;
 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
 import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.link.LinkEvent;
-import org.onosproject.net.link.LinkListener;
-import org.onosproject.net.link.LinkService;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketProcessor;
-import org.onosproject.net.packet.PacketService;
 import org.onosproject.segmentrouting.storekey.SubnetAssignedVidStoreKey;
 import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
@@ -102,6 +105,7 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkState;
 import static org.onlab.packet.Ethernet.TYPE_ARP;
@@ -120,6 +124,9 @@
     private ComponentConfigService compCfgService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private NeighbourResolutionService neighbourResolutionService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -179,7 +186,8 @@
     private McastHandler mcastHandler = null;
     HostHandler hostHandler = null;
     private CordConfigHandler cordConfigHandler = null;
-    RouteHandler routeHandler = null;
+    private RouteHandler routeHandler = null;
+    private SegmentRoutingNeighbourHandler neighbourHandler = null;
     private InternalEventHandler eventHandler = new InternalEventHandler();
     private final InternalHostListener hostListener = new InternalHostListener();
     private final InternalConfigListener cfgListener = new InternalConfigListener(this);
@@ -352,6 +360,7 @@
         hostHandler = new HostHandler(this);
         cordConfigHandler = new CordConfigHandler(this);
         routeHandler = new RouteHandler(this);
+        neighbourHandler = new SegmentRoutingNeighbourHandler(this);
 
         cfgService.addListener(cfgListener);
         cfgService.registerConfigFactory(deviceConfigFactory);
@@ -467,8 +476,8 @@
     }
 
     @Override
-    public Map<DeviceId, Set<Ip4Prefix>> getDeviceSubnetMap() {
-        Map<DeviceId, Set<Ip4Prefix>> deviceSubnetMap = Maps.newHashMap();
+    public Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap() {
+        Map<DeviceId, Set<IpPrefix>> deviceSubnetMap = Maps.newHashMap();
         deviceService.getAvailableDevices().forEach(device -> {
             deviceSubnetMap.put(device.id(), deviceConfiguration.getSubnets(device.id()));
         });
@@ -517,7 +526,7 @@
      *         the master for the device.
      */
     // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
-    public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
+    public VlanId getSubnetAssignedVlanId(DeviceId deviceId, IpPrefix subnet) {
         VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
                                                         deviceId, subnet));
         if (assignedVid != null) {
@@ -532,7 +541,12 @@
             return null;
         }
         // vlan assignment is expensive but done only once
-        Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
+        // FIXME for now we will do assignment considering only the ipv4 subnet.
+        Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId)
+                .stream()
+                .filter(IpPrefix::isIp4)
+                .map(IpPrefix::getIp4Prefix)
+                .collect(Collectors.toSet());
         Set<Short> assignedVlans = new HashSet<>();
         Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
         for (Ip4Prefix sub : configuredSubnets) {
@@ -646,7 +660,9 @@
             Ethernet ethernet = pkt.parsed();
             log.trace("Rcvd pktin: {}", ethernet);
             if (ethernet.getEtherType() == TYPE_ARP) {
-                arpHandler.processPacketIn(pkt);
+                log.warn("{} - we are still receiving ARP packets from {}",
+                         context.inPacket().receivedFrom());
+                log.debug("{}", ethernet);
             } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
                 IPv4 ipPacket = (IPv4) ethernet.getPayload();
                 // ipHandler.addToPacketBuffer(ipPacket);
@@ -657,6 +673,11 @@
                     //       is not necessary. Also it causes duplication of DHCP packets.
                     // ipHandler.processPacketIn(pkt);
                 }
+            } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV6) {
+                IPv6 ipv6Packet = (IPv6) ethernet.getPayload();
+                /*
+                 * TODO send to ICMPv6 handler and generalize the interaction with IP Handler
+                 */
             }
         }
     }
@@ -931,7 +952,7 @@
         // to switch ports, link-events should take care of any re-routing or
         // group editing necessary for port up/down. Here we only process edge ports
         // that are already configured.
-         Ip4Prefix configuredSubnet = deviceConfiguration.getPortSubnet(device.id(),
+         Ip4Prefix configuredSubnet = deviceConfiguration.getPortIPv4Subnet(device.id(),
                                                                         port.number());
         if (configuredSubnet == null) {
             log.debug("Not handling port updated event for unconfigured port "
@@ -962,6 +983,23 @@
         }
     }
 
+    /**
+     * Registers the given connect point with the NRS, this is necessary
+     * to receive the NDP and ARP packets from the NRS.
+     *
+     * @param portToRegister connect point to register
+     */
+    public void registerConnectPoint(ConnectPoint portToRegister) {
+        /*
+         * First we register the ARP handler.
+         */
+        this.neighbourResolutionService.registerNeighbourHandler(
+                portToRegister,
+                neighbourHandler,
+                appId
+        );
+    }
+
     private class InternalConfigListener implements NetworkConfigListener {
         SegmentRoutingManager srManager;
 
@@ -978,6 +1016,7 @@
          * Reads network config and initializes related data structure accordingly.
          */
         public void configureNetwork() {
+
             deviceConfiguration = new DeviceConfiguration(srManager);
 
             arpHandler = new ArpHandler(srManager);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
new file mode 100644
index 0000000..92a4371
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.segmentrouting;
+
+import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
+import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This handler deals with the ICMPv6 Echo protocol
+ * and ICMPv6 ND protocol.
+ */
+public class SegmentRoutingNeighbourHandler implements NeighbourMessageHandler {
+
+    private static Logger log = LoggerFactory.getLogger(SegmentRoutingNeighbourHandler.class);
+    private SegmentRoutingManager manager;
+
+    /**
+     * Create a segment routing neighbour handler.
+     *
+     * @param segmentRoutingManager the segment routing manager
+     */
+    public SegmentRoutingNeighbourHandler(SegmentRoutingManager segmentRoutingManager) {
+        this.manager = segmentRoutingManager;
+    }
+
+    /*
+     * We use this method to handle the NDP messages
+     */
+    @Override
+    public void handleMessage(NeighbourMessageContext context, HostService hostService) {
+        log.debug("Received a {} packet {}", context.protocol(), context.packet());
+        switch (context.protocol()) {
+            case ARP:
+                if (this.manager.arpHandler != null) {
+                    this.manager.arpHandler.processPacketIn(context, hostService);
+                }
+                break;
+            case NDP:
+                if (this.manager.icmpHandler != null) {
+                    this.manager.icmpHandler.processPacketIn(context);
+                }
+                break;
+            default:
+                log.warn("Unknown protocol", context.protocol());
+        }
+    }
+
+
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
index 7375b98..6f4b4e6 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -15,7 +15,7 @@
  */
 package org.onosproject.segmentrouting;
 
-import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onosproject.net.DeviceId;
 
 import java.util.List;
@@ -115,5 +115,5 @@
      *
      * @return device-subnet mapping
      */
-    Map<DeviceId, Set<Ip4Prefix>> getDeviceSubnetMap();
+    Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap();
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java
index 119d1e9..da3dd1c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java
@@ -17,7 +17,7 @@
 package org.onosproject.segmentrouting.cli;
 
 import org.apache.karaf.shell.commands.Command;
-import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.net.DeviceId;
 import org.onosproject.segmentrouting.SegmentRoutingService;
@@ -38,11 +38,11 @@
         printDeviceSubnetMap(srService.getDeviceSubnetMap());
     }
 
-    private void printDeviceSubnetMap(Map<DeviceId, Set<Ip4Prefix>> deviceSubnetMap) {
-        deviceSubnetMap.forEach(((deviceId, ip4Prefices) -> {
+    private void printDeviceSubnetMap(Map<DeviceId, Set<IpPrefix>> deviceSubnetMap) {
+        deviceSubnetMap.forEach(((deviceId, ipPrefices) -> {
             print("%s", deviceId);
-            ip4Prefices.forEach(ip4Prefix -> {
-                print("    %s", ip4Prefix);
+            ipPrefices.forEach(ipPrefix -> {
+                print("    %s", ipPrefix);
             });
         }));
     }
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 255f740..94f95f4 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
@@ -21,6 +21,7 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
@@ -37,6 +38,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -57,6 +59,7 @@
     private static final String ERROR_CONFIG = "Configuration error.";
     private static final String TOO_MANY_SUBNET = ERROR_CONFIG + " Too many subnets configured on {}";
     private static final String NO_SUBNET = "No subnet configured on {}";
+    private static final String MISCONFIGURED = "Subnets are not configured correctly for {}";
 
     private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
     private final List<Integer> allSegmentIds = new ArrayList<>();
@@ -71,12 +74,12 @@
         Ip6Address ipv6Loopback;
         MacAddress mac;
         boolean isEdge;
-        Map<PortNumber, Ip4Address> gatewayIps;
-        SetMultimap<PortNumber, Ip4Prefix> subnets;
+        SetMultimap<PortNumber, IpAddress> gatewayIps;
+        SetMultimap<PortNumber, IpPrefix> subnets;
         Map<Integer, Set<Integer>> adjacencySids;
 
         public SegmentRouterInfo() {
-            gatewayIps = new HashMap<>();
+            gatewayIps = HashMultimap.create();
             subnets = HashMultimap.create();
         }
     }
@@ -116,6 +119,7 @@
         // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
         Set<ConnectPoint> portSubjects = srManager.cfgService
                 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
+
         portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
             InterfaceConfig config =
                     srManager.cfgService.getConfig(subject, InterfaceConfig.class);
@@ -138,15 +142,27 @@
                     // Extract subnet information
                     List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
                     interfaceAddresses.forEach(interfaceAddress -> {
-                        // Do not add /0 and /32 to gateway IP list
+                        // Do not add /0, /32 and /128 to gateway IP list
                         int prefixLength = interfaceAddress.subnetAddress().prefixLength();
-                        if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
-                            info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
+                        IpPrefix ipPrefix = interfaceAddress.subnetAddress();
+                        if (ipPrefix.isIp4()) {
+                            if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
+                                info.gatewayIps.put(port, interfaceAddress.ipAddress());
+                            }
+                            info.subnets.put(port, interfaceAddress.subnetAddress());
+                        } else {
+                            if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
+                                info.gatewayIps.put(port, interfaceAddress.ipAddress());
+                            }
+                            info.subnets.put(port, interfaceAddress.subnetAddress());
                         }
-                        info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
                     });
                 }
             });
+            /*
+             * We register the connect point with the NRS.
+             */
+            srManager.registerConnectPoint(subject);
         });
     }
 
@@ -301,7 +317,7 @@
     }
 
     @Override
-    public Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
+    public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
             throws DeviceConfigNotFoundException {
         SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
         if (srinfo == null) {
@@ -309,14 +325,15 @@
             throw new DeviceConfigNotFoundException(message);
         }
         // Construct subnet-port mapping from port-subnet mapping
-        SetMultimap<PortNumber, Ip4Prefix> portSubnetMap = srinfo.subnets;
-        Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
+        SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
+        Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
 
         portSubnetMap.entries().forEach(entry -> {
             PortNumber port = entry.getKey();
-            Ip4Prefix subnet = entry.getValue();
+            IpPrefix subnet = entry.getValue();
 
-            if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH) {
+            if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
+                    subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
                 return;
             }
 
@@ -394,7 +411,7 @@
      * @param deviceId device identifier
      * @return immutable set of ip addresses configured on the ports or null if not found
      */
-    public Set<Ip4Address> getPortIPs(DeviceId deviceId) {
+    public Set<IpAddress> getPortIPs(DeviceId deviceId) {
         SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
         if (srinfo != null) {
             log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
@@ -410,10 +427,10 @@
      * @param deviceId device identifier
      * @return list of ip prefixes or null if not found
      */
-    public Set<Ip4Prefix> getSubnets(DeviceId deviceId) {
+    public Set<IpPrefix> getSubnets(DeviceId deviceId) {
         SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
         if (srinfo != null) {
-            ImmutableSet.Builder<Ip4Prefix> builder = ImmutableSet.builder();
+            ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
             return builder.addAll(srinfo.subnets.values()).build();
         }
         return null;
@@ -425,17 +442,17 @@
      *
      * @param deviceId Device ID
      * @param port Port number
-     * @return The subnet configured on given port or null if
+     * @return The subnets configured on given port or empty set if
      *         the port is unconfigured, misconfigured or suppressed.
      */
-    public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber port) {
+    public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
         ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
 
         if (isSuppressedPort(connectPoint)) {
-            return null;
+            return Collections.emptySet();
         }
 
-        Set<Ip4Prefix> subnets =
+        Set<IpPrefix> subnets =
                 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
                         .flatMap(intf -> intf.ipAddressesList().stream())
                         .map(InterfaceIpAddress::subnetAddress)
@@ -444,13 +461,69 @@
 
         if (subnets.isEmpty()) {
             log.info(NO_SUBNET, connectPoint);
-            return null;
-        } else if (subnets.size() > 1) {
+            return Collections.emptySet();
+        } else if (subnets.size() > 2) {
             log.warn(TOO_MANY_SUBNET, connectPoint);
-            return null;
-        } else {
-            return subnets.stream().findFirst().orElse(null);
+            return Collections.emptySet();
+        } else if (verifySubnets(subnets)) {
+            return subnets;
         }
+        log.warn(MISCONFIGURED, connectPoint);
+        return Collections.emptySet();
+    }
+
+    /**
+     * Returns the IPv4 subnet configured of given device and port.
+     *
+     * @param deviceId Device ID
+     * @param port Port number
+     * @return The IPv4 subnet configured on given port or null if
+     *         the port is unconfigured, misconfigured or suppressed.
+     */
+    public Ip4Prefix getPortIPv4Subnet(DeviceId deviceId, PortNumber port) {
+        return getPortSubnets(deviceId, port).stream()
+                .filter(IpPrefix::isIp4)
+                .map(IpPrefix::getIp4Prefix)
+                .findFirst().orElse(null);
+    }
+
+    /**
+     * Returns the IPv6 subnet configured of given device and port.
+     *
+     * @param deviceId Device ID
+     * @param port Port number
+     * @return The IPV6 subnet configured on given port or null if
+     *         the port is unconfigured, misconfigured or suppressed.
+     */
+    public Ip6Prefix getPortIPv6Subnet(DeviceId deviceId, PortNumber port) {
+        return getPortSubnets(deviceId, port).stream()
+                .filter(IpPrefix::isIp6)
+                .map(IpPrefix::getIp6Prefix)
+                .findFirst().orElse(null);
+    }
+
+    /**
+     * Utility to verify the configuration of a given port.
+     *
+     * @param subnets the subnets set to verify
+     * @return true if the configured subnets are ok. False otherwise.
+     */
+    private boolean verifySubnets(Set<IpPrefix> subnets) {
+        Set<Ip4Prefix> ip4Prefices = subnets.stream()
+                .filter(IpPrefix::isIp4)
+                .map(IpPrefix::getIp4Prefix)
+                .collect(Collectors.toSet());
+        if (ip4Prefices.size() > 1) {
+            return false;
+        }
+        Set<Ip6Prefix> ip6Prefices = subnets.stream()
+                .filter(IpPrefix::isIp6)
+                .map(IpPrefix::getIp6Prefix)
+                .collect(Collectors.toSet());
+        if (ip6Prefices.size() > 1) {
+            return false;
+        }
+        return !(ip4Prefices.isEmpty() && ip6Prefices.isEmpty());
     }
 
     /**
@@ -510,7 +583,7 @@
      * @param gatewayIpAddress router gateway ip address
      * @return router mac address or null if not found
      */
-    public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
+    public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
                 deviceConfigMap.entrySet()) {
             if (entry.getValue().gatewayIps.
@@ -534,14 +607,14 @@
      * false if no subnet is defined under the router or if the host is not
      * within the subnet defined in the router
      */
-    public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) {
+    public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
 
-        Set<Ip4Prefix> subnets = getSubnets(deviceId);
+        Set<IpPrefix> subnets = getSubnets(deviceId);
         if (subnets == null) {
             return false;
         }
 
-        for (Ip4Prefix subnet: subnets) {
+        for (IpPrefix subnet: subnets) {
             // Exclude /0 since it is a special case used for default route
             if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
                 return true;
@@ -561,8 +634,10 @@
      *         there is no subnet configuration on given connect point.
      */
     public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
-        Ip4Prefix portSubnet = getPortSubnet(connectPoint.deviceId(), connectPoint.port());
-        return portSubnet != null && portSubnet.contains(ip);
+        Ip4Prefix ipv4Subnet = getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
+        Ip6Prefix ipv6Subnet = getPortIPv6Subnet(connectPoint.deviceId(), connectPoint.port());
+        return (ipv4Subnet != null && ipv4Subnet.contains(ip)) ||
+                (ipv6Subnet != null && ipv6Subnet.contains(ip));
     }
 
     /**
@@ -596,34 +671,34 @@
      * Add subnet to specific connect point.
      *
      * @param cp connect point
-     * @param ip4Prefix subnet being added to the device
+     * @param ipPrefix subnet being added to the device
      */
-    public void addSubnet(ConnectPoint cp, Ip4Prefix ip4Prefix) {
+    public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
         checkNotNull(cp);
-        checkNotNull(ip4Prefix);
+        checkNotNull(ipPrefix);
         SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
         if (srinfo == null) {
             log.warn("Device {} is not configured. Abort.", cp.deviceId());
             return;
         }
-        srinfo.subnets.put(cp.port(), ip4Prefix);
+        srinfo.subnets.put(cp.port(), ipPrefix);
     }
 
     /**
      * Remove subnet from specific connect point.
      *
      * @param cp connect point
-     * @param ip4Prefix subnet being removed to the device
+     * @param ipPrefix subnet being removed to the device
      */
-    public void removeSubnet(ConnectPoint cp, Ip4Prefix ip4Prefix) {
+    public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
         checkNotNull(cp);
-        checkNotNull(ip4Prefix);
+        checkNotNull(ipPrefix);
         SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
         if (srinfo == null) {
             log.warn("Device {} is not configured. Abort.", cp.deviceId());
             return;
         }
-        srinfo.subnets.remove(cp.port(), ip4Prefix);
+        srinfo.subnets.remove(cp.port(), ipPrefix);
     }
 
     private boolean isSuppressedPort(ConnectPoint connectPoint) {
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
index 565dbe1..e4e71db 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
@@ -15,8 +15,8 @@
  */
 package org.onosproject.segmentrouting.config;
 
-import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
@@ -111,6 +111,6 @@
      * @throws DeviceConfigNotFoundException if the device configuration is not found
      * @return a map that contains all subnet-to-ports mapping of given device
      */
-    Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
+    Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
             throws DeviceConfigNotFoundException;
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 529a99c..d943710 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -713,7 +713,7 @@
      * all configured subnets.
      */
     public void createGroupsFromSubnetConfig() {
-        Map<Ip4Prefix, List<PortNumber>> subnetPortMap;
+        Map<IpPrefix, List<PortNumber>> subnetPortMap;
         try {
             subnetPortMap = this.deviceConfig.getSubnetPortsMap(this.deviceId);
         } catch (DeviceConfigNotFoundException e) {
@@ -722,7 +722,11 @@
             return;
         }
         // Construct a broadcast group for each subnet
-        subnetPortMap.forEach((subnet, ports) -> createBcastGroupFromSubnet(subnet, ports));
+        subnetPortMap.forEach((subnet, ports) -> {
+            if (subnet.isIp4()) {
+                createBcastGroupFromSubnet(subnet.getIp4Prefix(), ports);
+            }
+        });
     }
 
     /**
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/storekey/SubnetAssignedVidStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/storekey/SubnetAssignedVidStoreKey.java
index 8c6dce2..917122f 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/storekey/SubnetAssignedVidStoreKey.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/storekey/SubnetAssignedVidStoreKey.java
@@ -15,17 +15,17 @@
  */
 package org.onosproject.segmentrouting.storekey;
 
-import java.util.Objects;
-
-import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onosproject.net.DeviceId;
 
+import java.util.Objects;
+
 /**
  * Key of assigned VLAN ID store.
  */
 public class SubnetAssignedVidStoreKey {
     private final DeviceId deviceId;
-    private final Ip4Prefix subnet;
+    private final IpPrefix subnet;
 
     /**
      * Constructs the key of per subnet VLAN ID store.
@@ -33,7 +33,7 @@
      * @param deviceId device ID of the VLAN cross-connection
      * @param subnet subnet information
      */
-    public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) {
+    public SubnetAssignedVidStoreKey(DeviceId deviceId, IpPrefix subnet) {
         this.deviceId = deviceId;
         this.subnet = subnet;
     }
@@ -52,7 +52,7 @@
      *
      * @return the subnet
      */
-    public Ip4Prefix subnet() {
+    public IpPrefix subnet() {
         return subnet;
     }