[CORD-630] IPv6 filtering rules

Changes:
- Udpates TMAC table in order to handle IPv6 protocol;
- Updates ACL table in order to handle ICMPv6 traffic and traffic for the router;
- Udpates UNICAST table in order to handle the traffic towards the other routers;
- Updates the router ip in the netcfg in order to handle IPv6 address;
- Substitutes IpAddress and IpPrefix in many parts;
- Updates cpqd and ofdpa drivers to handle the above cases;
- Fixes the interaction with NRM when neighbordiscovery is activated;
- Introduces the IPv6 loopback and IPv6 node sid;

Change-Id: I0a3003be6f2f4b581cabe224c47a0cfbf51e8f9c
diff --git a/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index 4529389..8975de1 100644
--- a/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -180,7 +180,7 @@
                                                arpMsg.getTargetProtocolAddress());
         Set<Ip4Address> gatewayIpAddresses = null;
         try {
-            if (targetProtocolAddress.equals(config.getRouterIp(deviceId))) {
+            if (targetProtocolAddress.equals(config.getRouterIpv4(deviceId))) {
                 return true;
             }
             gatewayIpAddresses = config.getPortIPs(deviceId);
@@ -207,7 +207,7 @@
 
         try {
             senderMacAddress = config.getDeviceMac(deviceId).toBytes();
-            senderIpAddress = config.getRouterIp(deviceId).toOctets();
+            senderIpAddress = config.getRouterIpv4(deviceId).toOctets();
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting sendArpRequest.");
             return;
diff --git a/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 5396f54..a689aec 100644
--- a/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -22,6 +22,7 @@
 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;
 import org.onosproject.net.Device;
@@ -32,9 +33,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static org.onlab.util.Tools.groupedThreads;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -45,8 +43,10 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newScheduledThreadPool;
+import static org.onlab.util.Tools.groupedThreads;
 
 /**
  * Default routing handler that is responsible for route computing and
@@ -335,7 +335,7 @@
                         log.trace("TargetSwitch {} --> RootSwitch {}", targetSw, rootSw);
                         for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
                             log.trace(" Via:");
-                            via.forEach(e -> { log.trace("  {}", e); });
+                            via.forEach(e -> log.trace("  {}", e));
                         }
                     }
                     Set<ArrayList<DeviceId>> subLinks =
@@ -553,12 +553,14 @@
         // rule for both subnet and router IP.
         boolean targetIsEdge;
         boolean destIsEdge;
-        Ip4Address destRouterIp;
+        Ip4Address destRouterIpv4;
+        Ip6Address destRouterIpv6;
 
         try {
             targetIsEdge = config.isEdgeDevice(targetSw);
             destIsEdge = config.isEdgeDevice(destSw);
-            destRouterIp = config.getRouterIp(destSw);
+            destRouterIpv4 = config.getRouterIpv4(destSw);
+            destRouterIpv6 = config.getRouterIpv6(destSw);
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting populateEcmpRoutingRulePartial.");
             return false;
@@ -574,33 +576,61 @@
                 return false;
             }
 
-            Ip4Address routerIp = destRouterIp;
-            IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
+            IpPrefix routerIpPrefix = destRouterIpv4.toIpPrefix();
             log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
                       targetSw, destSw, routerIpPrefix);
             result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
             if (!result) {
                 return false;
             }
+            /*
+             * If present we deal with IPv6 loopback.
+             */
+            if (destRouterIpv6 != null) {
+                routerIpPrefix = destRouterIpv6.toIpPrefix();
+                log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for v6 router IP {}",
+                          targetSw, destSw, routerIpPrefix);
+                result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
+                if (!result) {
+                    return false;
+                }
+            }
 
         } else if (targetIsEdge) {
             // If the target switch is an edge router, then set IP rules for the router IP.
-            Ip4Address routerIp = destRouterIp;
-            IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
+            IpPrefix routerIpPrefix = destRouterIpv4.toIpPrefix();
             log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
                       targetSw, destSw, routerIpPrefix);
             result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
             if (!result) {
                 return false;
             }
+            if (destRouterIpv6 != null) {
+                routerIpPrefix = destRouterIpv6.toIpPrefix();
+                log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for v6 router IP {}",
+                          targetSw, destSw, routerIpPrefix);
+                result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops);
+                if (!result) {
+                    return false;
+                }
+            }
         }
         // Populates MPLS rules to all routers
         log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
                 targetSw, destSw);
-        result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops);
+        result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops, destRouterIpv4);
         if (!result) {
             return false;
         }
+        /*
+         * If present we will populate the MPLS rules for the IPv6 sid.
+         */
+        if (destRouterIpv6 != null) {
+            result = rulePopulator.populateMplsRule(targetSw, destSw, nextHops, destRouterIpv6);
+            if (!result) {
+                return false;
+            }
+        }
         return true;
     }
 
diff --git a/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index 220d3f2..dc217ee 100644
--- a/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -19,6 +19,7 @@
 import org.onlab.packet.ICMP;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MPLS;
 import org.onosproject.net.ConnectPoint;
@@ -77,9 +78,9 @@
         Ip4Address destinationAddress =
                 Ip4Address.valueOf(ipv4.getDestinationAddress());
         Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
-        Ip4Address routerIp;
+        IpAddress routerIp;
         try {
-            routerIp = config.getRouterIp(deviceId);
+            routerIp = config.getRouterIpv4(deviceId);
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting processPacketIn.");
             return;
@@ -91,7 +92,7 @@
         if (((ICMP) ipv4.getPayload()).getIcmpType() == ICMP.TYPE_ECHO_REQUEST &&
                 (destinationAddress.equals(routerIpAddress) ||
                         gatewayIpAddresses.contains(destinationAddress))) {
-            sendICMPResponse(ethernet, connectPoint);
+            sendIcmpResponse(ethernet, connectPoint);
 
         // ICMP for any known host
         } else if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
@@ -117,7 +118,7 @@
      * @param icmpRequest the original ICMP request
      * @param outport the output port where the ICMP reply should be sent to
      */
-    private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) {
+    private void sendIcmpResponse(Ethernet icmpRequest, ConnectPoint outport) {
         // Note: We assume that packets arrive at the edge switches have
         // untagged VLAN.
         Ethernet icmpReplyEth = new Ethernet();
@@ -145,7 +146,7 @@
 
         Ip4Address destIpAddress = Ip4Address.valueOf(icmpReplyIpv4.getDestinationAddress());
         Ip4Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress);
-        int destSid = config.getSegmentId(destRouterAddress);
+        int destSid = config.getIPv4SegmentId(destRouterAddress);
         if (destSid < 0) {
             log.warn("Cannot find the Segment ID for {}", destAddress);
             return;
@@ -160,7 +161,7 @@
         IPv4 ipPacket = (IPv4) payload.getPayload();
         Ip4Address destIpAddress = Ip4Address.valueOf(ipPacket.getDestinationAddress());
 
-        if (destSid == -1 || config.getSegmentId(payload.getDestinationMAC()) == destSid ||
+        if (destSid == -1 || config.getIPv4SegmentId(payload.getDestinationMAC()) == destSid ||
                 config.inSameSubnet(outport.deviceId(), destIpAddress)) {
             TrafficTreatment treatment = DefaultTrafficTreatment.builder().
                     setOutput(outport.port()).build();
diff --git a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index b691f80..2c2f1eb 100644
--- a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -19,6 +19,8 @@
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
@@ -262,7 +264,7 @@
      * is reachable via destination device.
      *
      * @param deviceId target device ID to set the rules
-     * @param ipPrefix the IP address of the destination router
+     * @param ipPrefix the destination IP prefix
      * @param destSw device ID of the destination router
      * @param nextHops next hop switch ID list
      * @return true if all rules are set successfully, false otherwise
@@ -272,15 +274,17 @@
                                            Set<DeviceId> nextHops) {
         int segmentId;
         try {
-            segmentId = config.getSegmentId(destSw);
+            if (ipPrefix.isIp4()) {
+                segmentId = config.getIPv4SegmentId(destSw);
+            } else {
+                segmentId = config.getIPv6SegmentId(destSw);
+            }
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting populateIpRuleForRouter.");
             return false;
         }
 
-        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
-        sbuilder.matchIPDst(ipPrefix);
-        sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+        TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(ipPrefix);
         TrafficSelector selector = sbuilder.build();
 
         TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
@@ -379,13 +383,18 @@
      * @param targetSwId target device ID of the switch to set the rules
      * @param destSwId destination switch device ID
      * @param nextHops next hops switch ID list
+     * @param routerIp the router Ip
      * @return true if all rules are set successfully, false otherwise
      */
     public boolean populateMplsRule(DeviceId targetSwId, DeviceId destSwId,
-                                    Set<DeviceId> nextHops) {
+                                    Set<DeviceId> nextHops, IpAddress routerIp) {
         int segmentId;
         try {
-            segmentId = config.getSegmentId(destSwId);
+            if (routerIp.isIp4()) {
+                segmentId = config.getIPv4SegmentId(destSwId);
+            } else {
+                segmentId = config.getIPv6SegmentId(destSwId);
+            }
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting populateMplsRule.");
             return false;
@@ -418,7 +427,8 @@
                                                nextHops,
                                                true,
                                                true,
-                                               metabuilder.build());
+                                               metabuilder.build(),
+                                               routerIp);
             if (fwdObjBosBuilder == null) {
                 return false;
             }
@@ -444,7 +454,8 @@
                                                nextHops,
                                                false,
                                                true,
-                                               metabuilder.build());
+                                               metabuilder.build(),
+                                               routerIp);
             if (fwdObjBosBuilder == null) {
                 return false;
             }
@@ -487,7 +498,8 @@
                                              Set<DeviceId> nextHops,
                                              boolean phpRequired,
                                              boolean isBos,
-                                             TrafficSelector meta) {
+                                             TrafficSelector meta,
+                                             IpAddress routerIp) {
 
         ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
                 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
@@ -499,8 +511,12 @@
             log.debug("getMplsForwardingObjective: php required");
             tbuilder.deferred().copyTtlIn();
             if (isBos) {
-                tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType())
-                    .decNwTtl();
+                if (routerIp.isIp4()) {
+                    tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType());
+                } else {
+                    tbuilder.deferred().popMpls(EthType.EtherType.IPV6.ethType());
+                }
+                tbuilder.decNwTtl();
             } else {
                 tbuilder.deferred().popMpls(EthType.EtherType.MPLS_UNICAST.ethType())
                     .decMplsTtl();
@@ -621,9 +637,11 @@
      * @param deviceId the switch dpid for the router
      */
     public void populateRouterIpPunts(DeviceId deviceId) {
-        Ip4Address routerIp;
+        Ip4Address routerIpv4;
+        Ip6Address routerIpv6;
         try {
-            routerIp = config.getRouterIp(deviceId);
+            routerIpv4 = config.getRouterIpv4(deviceId);
+            routerIpv6 = config.getRouterIpv6(deviceId);
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting populateRouterIpPunts.");
             return;
@@ -634,12 +652,13 @@
                       deviceId);
             return;
         }
-        Set<Ip4Address> allIps = new HashSet<>(config.getPortIPs(deviceId));
-        allIps.add(routerIp);
-        for (Ip4Address ipaddr : allIps) {
-            TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
-                    .matchEthType(Ethernet.TYPE_IPV4)
-                    .matchIPDst(IpPrefix.valueOf(ipaddr, IpPrefix.MAX_INET_MASK_LENGTH));
+        Set<IpAddress> allIps = new HashSet<>(config.getPortIPs(deviceId));
+        allIps.add(routerIpv4);
+        if (routerIpv6 != null) {
+            allIps.add(routerIpv6);
+        }
+        for (IpAddress ipaddr : allIps) {
+            TrafficSelector.Builder sbuilder = buildIpSelectorFromIpAddress(ipaddr);
             Optional<DeviceId> optDeviceId = Optional.of(deviceId);
 
             srManager.packetService.requestPackets(sbuilder.build(),
@@ -648,6 +667,38 @@
     }
 
     /**
+     * Method to build IPv4 or IPv6 selector.
+     *
+     * @param addressToMatch the address to match
+     */
+    private TrafficSelector.Builder buildIpSelectorFromIpAddress(IpAddress addressToMatch) {
+        return buildIpSelectorFromIpPrefix(addressToMatch.toIpPrefix());
+    }
+
+    /**
+     * Method to build IPv4 or IPv6 selector.
+     *
+     * @param prefixToMatch the prefix to match
+     */
+    private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        /*
+         * If the prefix is IPv4
+         */
+        if (prefixToMatch.isIp4()) {
+            selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
+            selectorBuilder.matchIPDst(prefixToMatch.getIp4Prefix());
+            return selectorBuilder;
+        }
+        /*
+         * If the prefix is IPv6
+         */
+        selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
+        selectorBuilder.matchIPv6Dst(prefixToMatch.getIp6Prefix());
+        return selectorBuilder;
+    }
+
+    /**
      * Creates forwarding objectives to punt ARP and NDP packets, to the controller.
      * Furthermore, these are applied only by the master instance. Deferred actions
      * are not cleared such that packets can be flooded in the cross connect use case
@@ -675,9 +726,7 @@
                 });
         srManager.flowObjectiveService.forward(deviceId, puntFwd);
 
-        // TODO: The driver does not support NDP at this moment. Turn it back on later.
         // We punt all NDP packets towards the controller.
-        /*
         puntFwd = puntNdpFwdObjective()
                 .add(new ObjectiveContext() {
                     @Override
@@ -687,7 +736,6 @@
                     }
                 });
         srManager.flowObjectiveService.forward(deviceId, puntFwd);
-        */
     }
 
     private ForwardingObjective.Builder fwdObjBuilder(TrafficSelector selector) {
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index b0bd717..fea2824 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -104,6 +104,7 @@
 import java.util.concurrent.TimeUnit;
 
 import static com.google.common.base.Preconditions.checkState;
+import static org.onlab.packet.Ethernet.TYPE_ARP;
 import static org.onlab.util.Tools.groupedThreads;
 
 /**
@@ -644,7 +645,7 @@
             InboundPacket pkt = context.inPacket();
             Ethernet ethernet = pkt.parsed();
             log.trace("Rcvd pktin: {}", ethernet);
-            if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+            if (ethernet.getEtherType() == TYPE_ARP) {
                 arpHandler.processPacketIn(pkt);
             } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
                 IPv4 ipPacket = (IPv4) ethernet.getPayload();
diff --git a/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
index 2bd9932..255f740 100644
--- a/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ b/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.SetMultimap;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
@@ -63,9 +64,11 @@
     private SegmentRoutingManager srManager;
 
     private class SegmentRouterInfo {
-        int nodeSid;
+        int ipv4NodeSid;
+        int ipv6NodeSid;
         DeviceId deviceId;
-        Ip4Address ip;
+        Ip4Address ipv4Loopback;
+        Ip6Address ipv6Loopback;
         MacAddress mac;
         boolean isEdge;
         Map<PortNumber, Ip4Address> gatewayIps;
@@ -95,14 +98,19 @@
                     srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
             SegmentRouterInfo info = new SegmentRouterInfo();
             info.deviceId = subject;
-            info.nodeSid = config.nodeSid();
-            info.ip = config.routerIp();
+            info.ipv4NodeSid = config.nodeSidIPv4();
+            info.ipv6NodeSid = config.nodeSidIPv6();
+            info.ipv4Loopback = config.routerIpv4();
+            info.ipv6Loopback = config.routerIpv6();
             info.mac = config.routerMac();
             info.isEdge = config.isEdgeRouter();
             info.adjacencySids = config.adjacencySids();
             deviceConfigMap.put(info.deviceId, info);
             log.info("Read device config for device: {}", info.deviceId);
-            allSegmentIds.add(info.nodeSid);
+            /*
+             * IPv6 sid is not inserted. this part of the code is not used for now.
+             */
+            allSegmentIds.add(info.ipv4NodeSid);
         });
 
         // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
@@ -148,28 +156,40 @@
     }
 
     @Override
-    public int getSegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
+    public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
         SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
         if (srinfo != null) {
-            log.trace("getSegmentId for device{} is {}", deviceId, srinfo.nodeSid);
-            return srinfo.nodeSid;
+            log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
+            return srinfo.ipv4NodeSid;
         } else {
-            String message = "getSegmentId fails for device: " + deviceId + ".";
+            String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
+            throw new DeviceConfigNotFoundException(message);
+        }
+    }
+
+    @Override
+    public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
+            return srinfo.ipv6NodeSid;
+        } else {
+            String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
             throw new DeviceConfigNotFoundException(message);
         }
     }
 
     /**
-     * Returns the Node segment id of a segment router given its Router mac address.
+     * Returns the IPv4 Node segment id of a segment router given its Router mac address.
      *
      * @param routerMac router mac address
      * @return node segment id, or -1 if not found in config
      */
-    public int getSegmentId(MacAddress routerMac) {
+    public int getIPv4SegmentId(MacAddress routerMac) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
                     deviceConfigMap.entrySet()) {
             if (entry.getValue().mac.equals(routerMac)) {
-                return entry.getValue().nodeSid;
+                return entry.getValue().ipv4NodeSid;
             }
         }
 
@@ -177,16 +197,50 @@
     }
 
     /**
-     * Returns the Node segment id of a segment router given its Router ip address.
+     * Returns the IPv6 Node segment id of a segment router given its Router mac address.
+     *
+     * @param routerMac router mac address
+     * @return node segment id, or -1 if not found in config
+     */
+    public int getIPv6SegmentId(MacAddress routerMac) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+                deviceConfigMap.entrySet()) {
+            if (entry.getValue().mac.equals(routerMac)) {
+                return entry.getValue().ipv6NodeSid;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns the IPv4 Node segment id of a segment router given its Router ip address.
      *
      * @param routerAddress router ip address
      * @return node segment id, or -1 if not found in config
      */
-    public int getSegmentId(Ip4Address routerAddress) {
+    public int getIPv4SegmentId(Ip4Address routerAddress) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
             deviceConfigMap.entrySet()) {
-            if (entry.getValue().ip.equals(routerAddress)) {
-                return entry.getValue().nodeSid;
+            if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
+                return entry.getValue().ipv4NodeSid;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns the IPv6 Node segment id of a segment router given its Router ip address.
+     *
+     * @param routerAddress router ip address
+     * @return node segment id, or -1 if not found in config
+     */
+    public int getIPv6SegmentId(Ip6Address routerAddress) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+                deviceConfigMap.entrySet()) {
+            if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
+                return entry.getValue().ipv6NodeSid;
             }
         }
 
@@ -206,13 +260,25 @@
     }
 
     @Override
-    public Ip4Address getRouterIp(DeviceId deviceId) throws DeviceConfigNotFoundException {
+    public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
         SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
         if (srinfo != null) {
-            log.trace("getDeviceIp for device{} is {}", deviceId, srinfo.ip);
-            return srinfo.ip;
+            log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
+            return srinfo.ipv4Loopback;
         } else {
-            String message = "getRouterIp fails for device: " + deviceId + ".";
+            String message = "getRouterIpv4 fails for device: " + deviceId + ".";
+            throw new DeviceConfigNotFoundException(message);
+        }
+    }
+
+    @Override
+    public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
+        SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
+        if (srinfo != null) {
+            log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
+            return srinfo.ipv6Loopback;
+        } else {
+            String message = "getRouterIpv6 fails for device: " + deviceId + ".";
             throw new DeviceConfigNotFoundException(message);
         }
     }
@@ -275,7 +341,8 @@
     public DeviceId getDeviceId(int sid) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
             deviceConfigMap.entrySet()) {
-            if (entry.getValue().nodeSid == sid) {
+            if (entry.getValue().ipv4NodeSid == sid ||
+                    entry.getValue().ipv6NodeSid == sid) {
                 return entry.getValue().deviceId;
             }
         }
@@ -293,7 +360,25 @@
     public DeviceId getDeviceId(Ip4Address ipAddress) {
         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
             deviceConfigMap.entrySet()) {
-            if (entry.getValue().ip.equals(ipAddress)) {
+            if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
+                return entry.getValue().deviceId;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the device identifier or data plane identifier (dpid)
+     * of a segment router given its router ipv6 address.
+     *
+     * @param ipAddress router ipv6 address
+     * @return deviceId device identifier
+     */
+    public DeviceId getDeviceId(Ip6Address ipAddress) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+                deviceConfigMap.entrySet()) {
+            if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
                 return entry.getValue().deviceId;
             }
         }
@@ -390,7 +475,32 @@
             return null;
         }
 
-        return srInfo.ip;
+        return srInfo.ipv4Loopback;
+    }
+
+    /**
+     * Returns the router ipv6 address of segment router that has the
+     * specified ip address in its subnets.
+     *
+     * @param destIpAddress target ip address
+     * @return router ip address
+     */
+    public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
+        Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
+
+        if (matchIntf == null) {
+            log.debug("No router was found for {}", destIpAddress);
+            return null;
+        }
+
+        DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
+        SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
+        if (srInfo == null) {
+            log.debug("No device config was found for {}", routerDeviceId);
+            return null;
+        }
+
+        return srInfo.ipv6Loopback;
     }
 
     /**
diff --git a/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java b/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
index 5ad9cdc..565dbe1 100644
--- a/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
+++ b/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
@@ -15,15 +15,15 @@
  */
 package org.onosproject.segmentrouting.config;
 
-import java.util.List;
-import java.util.Map;
-
-import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * Mechanism through which group handler module retrieves
  * the device specific attributes such as segment ID,
@@ -39,13 +39,22 @@
     boolean isConfigured(DeviceId deviceId);
 
     /**
-     * Returns the segment id of a device to be used in group creation.
+     * Returns the IPv4 segment id of a device to be used in group creation.
      *
      * @param deviceId device identifier
      * @throws DeviceConfigNotFoundException if the device configuration is not found
      * @return segment id of a device
      */
-    int getSegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException;
+    int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException;
+
+    /**
+     * Returns the IPv6 segment id of a device to be used in group creation.
+     *
+     * @param deviceId device identifier
+     * @throws DeviceConfigNotFoundException if the device configuration is not found
+     * @return segment id of a device
+     */
+    int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException;
 
     /**
      * Returns the Mac address of a device to be used in group creation.
@@ -57,13 +66,22 @@
     MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException;
 
     /**
-     * Returns the router ip address of a segment router.
+     * Returns the router ipv4 address of a segment router.
      *
      * @param deviceId device identifier
      * @throws DeviceConfigNotFoundException if the device configuration is not found
      * @return router ip address
      */
-    Ip4Address getRouterIp(DeviceId deviceId) throws DeviceConfigNotFoundException;
+    IpAddress getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException;
+
+    /**
+     * Returns the router ipv6 address of a segment router.
+     *
+     * @param deviceId device identifier
+     * @throws DeviceConfigNotFoundException if the device configuration is not found
+     * @return router ip address
+     */
+    IpAddress getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException;
 
     /**
      * Indicates whether a device is edge device or transit/core device.
diff --git a/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java b/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java
index 21ba1e6..bc0d329 100644
--- a/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java
+++ b/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfig.java
@@ -21,6 +21,7 @@
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.ImmutableMap;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.config.Config;
@@ -36,9 +37,11 @@
  */
 public class SegmentRoutingDeviceConfig extends Config<DeviceId> {
     private static final String NAME = "name";
-    private static final String IP = "routerIp";
+    private static final String IP4 = "ipv4Loopback";
+    private static final String IP6 = "ipv6Loopback";
     private static final String MAC = "routerMac";
-    private static final String SID = "nodeSid";
+    private static final String IP4_SID = "ipv4NodeSid";
+    private static final String IP6_SID = "ipv6NodeSid";
     private static final String EDGE = "isEdgeRouter";
     private static final String ADJSIDS = "adjacencySids";
     private static final String ADJSID = "adjSid";
@@ -46,11 +49,13 @@
 
     @Override
     public boolean isValid() {
-        return hasOnlyFields(NAME, IP, MAC, SID, EDGE, ADJSIDS, ADJSID, PORTS) &&
+        return hasOnlyFields(NAME, IP4, IP6, MAC,
+                             IP4_SID, IP6_SID, EDGE,
+                             ADJSIDS, ADJSID, PORTS) &&
                 name() != null &&
-                routerIp() != null &&
+                routerIpv4() != null &&
                 routerMac() != null &&
-                nodeSid() != -1 &&
+                nodeSidIPv4() != -1 &&
                 isEdgeRouter() != null &&
                 adjacencySids() != null;
     }
@@ -76,23 +81,43 @@
     }
 
     /**
-     * Gets the IP address of the router.
+     * Gets the IPv4 address of the router.
      *
      * @return IP address of the router. Or null if not configured.
      */
-    public Ip4Address routerIp() {
-        String ip = get(IP, null);
+    public Ip4Address routerIpv4() {
+        String ip = get(IP4, null);
         return ip != null ? Ip4Address.valueOf(ip) : null;
     }
 
     /**
-     * Sets the IP address of the router.
+     * Gets the IPv6 address of the router.
      *
-     * @param ip IP address of the router.
+     * @return IP address of the router. Or null if not configured.
+     */
+    public Ip6Address routerIpv6() {
+        String ip = get(IP6, null);
+        return ip != null ? Ip6Address.valueOf(ip) : null;
+    }
+
+    /**
+     * Sets the IPv4 address of the router.
+     *
+     * @param ip IPv4 address of the router.
      * @return the config of the router.
      */
-    public SegmentRoutingDeviceConfig setRouterIp(String ip) {
-        return (SegmentRoutingDeviceConfig) setOrClear(IP, ip);
+    public SegmentRoutingDeviceConfig setRouterIpv4(String ip) {
+        return (SegmentRoutingDeviceConfig) setOrClear(IP4, ip);
+    }
+
+    /**
+     * Sets the IPv6 address of the router.
+     *
+     * @param ip IPv6 address of the router.
+     * @return the config of the router.
+     */
+    public SegmentRoutingDeviceConfig setRouterIpv6(String ip) {
+        return (SegmentRoutingDeviceConfig) setOrClear(IP6, ip);
     }
 
     /**
@@ -116,22 +141,41 @@
     }
 
     /**
-     * Gets the node SID of the router.
+     * Gets the IPv4 node SID of the router.
      *
      * @return node SID of the router. Or -1 if not configured.
      */
-    public int nodeSid() {
-        return get(SID, -1);
+    public int nodeSidIPv4() {
+        return get(IP4_SID, -1);
     }
 
     /**
-     * Sets the node SID of the router.
+     * Gets the IPv6 node SID of the router.
+     *
+     * @return node SID of the router. Or -1 if not configured.
+     */
+    public int nodeSidIPv6() {
+        return get(IP6_SID, -1);
+    }
+
+    /**
+     * Sets the node IPv4 node SID of the router.
      *
      * @param sid node SID of the router.
      * @return the config of the router.
      */
-    public SegmentRoutingDeviceConfig setNodeSid(int sid) {
-        return (SegmentRoutingDeviceConfig) setOrClear(SID, sid);
+    public SegmentRoutingDeviceConfig setNodeSidIPv4(int sid) {
+        return (SegmentRoutingDeviceConfig) setOrClear(IP4_SID, sid);
+    }
+
+    /**
+     * Sets the node IPv6 node SID of the router.
+     *
+     * @param sid node SID of the router.
+     * @return the config of the router.
+     */
+    public SegmentRoutingDeviceConfig setNodeSidIPv6(int sid) {
+        return (SegmentRoutingDeviceConfig) setOrClear(IP6_SID, sid);
     }
 
     /**
@@ -222,4 +266,4 @@
 
         return this;
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index b76a04c..529a99c 100644
--- a/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -69,7 +69,8 @@
     protected final ApplicationId appId;
     protected final DeviceProperties deviceConfig;
     protected final List<Integer> allSegmentIds;
-    protected int nodeSegmentId = -1;
+    protected int ipv4NodeSegmentId = -1;
+    protected int ipv6NodeSegmentId = -1;
     protected boolean isEdgeRouter = false;
     protected MacAddress nodeMacAddr = null;
     protected LinkService linkService;
@@ -111,7 +112,8 @@
         this.linkService = checkNotNull(linkService);
         this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
         try {
-            this.nodeSegmentId = config.getSegmentId(deviceId);
+            this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
+            this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
             this.isEdgeRouter = config.isEdgeDevice(deviceId);
             this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
         } catch (DeviceConfigNotFoundException e) {
@@ -597,7 +599,10 @@
     private boolean isSegmentIdSameAsNodeSegmentId(DeviceId deviceId, int sId) {
         int segmentId;
         try {
-            segmentId = deviceConfig.getSegmentId(deviceId);
+            /*
+             * IPv6 sid is not inserted. this part of the code is not used for now.
+             */
+            segmentId = deviceConfig.getIPv4SegmentId(deviceId);
         } catch (DeviceConfigNotFoundException e) {
             log.warn(e.getMessage() + " Aborting isSegmentIdSameAsNodeSegmentId.");
             return false;
@@ -618,7 +623,7 @@
         // Filter out SegmentIds matching with the
         // nodes in the combo
         for (Integer sId : allSegmentIds) {
-            if (sId.equals(nodeSegmentId)) {
+            if (sId.equals(this.ipv4NodeSegmentId)) {
                 continue;
             }
             boolean filterOut = false;
diff --git a/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfigTest.java b/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfigTest.java
index 74f6498..7f165d8 100644
--- a/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfigTest.java
+++ b/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingDeviceConfigTest.java
@@ -41,6 +41,7 @@
  */
 public class SegmentRoutingDeviceConfigTest {
     private SegmentRoutingDeviceConfig config;
+    private SegmentRoutingDeviceConfig ipv6Config;
     private Map<Integer, Set<Integer>> adjacencySids1;
     private Map<Integer, Set<Integer>> adjacencySids2;
 
@@ -48,6 +49,8 @@
     public void setUp() throws Exception {
         InputStream jsonStream = SegmentRoutingDeviceConfigTest.class
                 .getResourceAsStream("/device.json");
+        InputStream ipv6JsonStream = SegmentRoutingDeviceConfigTest.class
+                .getResourceAsStream("/device-ipv6.json");
 
         adjacencySids1 = new HashMap<>();
         Set<Integer> ports1 = new HashSet<>();
@@ -68,10 +71,20 @@
         String key = "segmentrouting";
         ObjectMapper mapper = new ObjectMapper();
         JsonNode jsonNode = mapper.readTree(jsonStream);
+        JsonNode ipv6JsonNode = mapper.readTree(ipv6JsonStream);
         ConfigApplyDelegate delegate = new MockDelegate();
 
         config = new SegmentRoutingDeviceConfig();
         config.init(subject, key, jsonNode, mapper, delegate);
+
+        ipv6Config = new SegmentRoutingDeviceConfig();
+        ipv6Config.init(subject, key, ipv6JsonNode, mapper, delegate);
+    }
+
+    @Test
+    public void testIsValid() {
+        assertTrue(config.isValid());
+        assertTrue(ipv6Config.isValid());
     }
 
     @Test
@@ -89,13 +102,19 @@
 
     @Test
     public void testRouterIp() throws Exception {
-        assertThat(config.routerIp(), is(IpAddress.valueOf("10.0.1.254")));
+        assertThat(config.routerIpv4(), is(IpAddress.valueOf("10.0.1.254")));
+        assertThat(ipv6Config.routerIpv4(), is(IpAddress.valueOf("10.0.1.254")));
+        assertThat(ipv6Config.routerIpv6(), is(IpAddress.valueOf("2000::c0a8:0101")));
     }
 
     @Test
     public void testSetRouterIp() throws Exception {
-        config.setRouterIp("10.0.2.254");
-        assertThat(config.routerIp(), is(IpAddress.valueOf("10.0.2.254")));
+        config.setRouterIpv4("10.0.2.254");
+        assertThat(config.routerIpv4(), is(IpAddress.valueOf("10.0.2.254")));
+        ipv6Config.setRouterIpv4("10.0.2.254");
+        assertThat(ipv6Config.routerIpv4(), is(IpAddress.valueOf("10.0.2.254")));
+        ipv6Config.setRouterIpv6("2000::c0a9:0101");
+        assertThat(ipv6Config.routerIpv6(), is(IpAddress.valueOf("2000::c0a9:0101")));
     }
 
     @Test
@@ -111,13 +130,19 @@
 
     @Test
     public void testNodeSid() throws Exception {
-        assertThat(config.nodeSid(), is(101));
+        assertThat(config.nodeSidIPv4(), is(101));
+        assertThat(ipv6Config.nodeSidIPv4(), is(101));
+        assertThat(ipv6Config.nodeSidIPv6(), is(111));
     }
 
     @Test
     public void testSetNodeSid() throws Exception {
-        config.setNodeSid(200);
-        assertThat(config.nodeSid(), is(200));
+        config.setNodeSidIPv4(200);
+        assertThat(config.nodeSidIPv4(), is(200));
+        ipv6Config.setNodeSidIPv4(200);
+        assertThat(ipv6Config.nodeSidIPv4(), is(200));
+        ipv6Config.setNodeSidIPv6(201);
+        assertThat(ipv6Config.nodeSidIPv6(), is(201));
     }
 
     @Test
@@ -144,7 +169,7 @@
 
     private class MockDelegate implements ConfigApplyDelegate {
         @Override
-        public void onApply(Config config) {
+        public void onApply(Config configFile) {
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/resources/device-ipv6.json b/src/test/resources/device-ipv6.json
new file mode 100644
index 0000000..9832f8c
--- /dev/null
+++ b/src/test/resources/device-ipv6.json
@@ -0,0 +1,13 @@
+{
+  "name" : "Leaf-R1",
+  "ipv4NodeSid" : 101,
+  "ipv4Loopback" : "10.0.1.254",
+  "ipv6NodeSid" : 111,
+  "ipv6Loopback" : "2000::c0a8:0101",
+  "routerMac" : "00:00:00:00:01:80",
+  "isEdgeRouter" : true,
+  "adjacencySids" : [
+    { "adjSid" : 100, "ports" : [2, 3] },
+    { "adjSid" : 200, "ports" : [4, 5] }
+  ]
+}
diff --git a/src/test/resources/device.json b/src/test/resources/device.json
index 247d7f5..83aec6e 100644
--- a/src/test/resources/device.json
+++ b/src/test/resources/device.json
@@ -1,7 +1,7 @@
 {
   "name" : "Leaf-R1",
-  "nodeSid" : 101,
-  "routerIp" : "10.0.1.254",
+  "ipv4NodeSid" : 101,
+  "ipv4Loopback" : "10.0.1.254",
   "routerMac" : "00:00:00:00:01:80",
   "isEdgeRouter" : true,
   "adjacencySids" : [