Bug 9116: Add getChildPrefixes() method to caches 56/63056/14
authorLorand Jakab <lojakab@cisco.com>
Fri, 8 Sep 2017 12:26:24 +0000 (15:26 +0300)
committerLorand Jakab <lojakab@cisco.com>
Fri, 20 Oct 2017 12:19:11 +0000 (15:19 +0300)
As a first step to fixing the bug, we need a way to find child prefixes
of a given prefix.

Change-Id: Icaf45888766e79fb2800fb4e24f3aa4e67eb580e
Signed-off-by: Lorand Jakab <lojakab@cisco.com>
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/dao/ILispDAO.java
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/mapcache/IMapCache.java
mappingservice/inmemorydb/src/main/java/org/opendaylight/lispflowmapping/inmemorydb/HashMapDb.java
mappingservice/inmemorydb/src/main/java/org/opendaylight/lispflowmapping/inmemorydb/radixtrie/RadixTrie.java
mappingservice/inmemorydb/src/test/java/org/opendaylight/lispflowmapping/inmemorydb/radixtrie/RadixTrieTest.java
mappingservice/lisp-proto/src/main/java/org/opendaylight/lispflowmapping/lisp/util/LispAddressUtil.java
mappingservice/mapcache/src/main/java/org/opendaylight/lispflowmapping/mapcache/FlatMapCache.java
mappingservice/mapcache/src/main/java/org/opendaylight/lispflowmapping/mapcache/MultiTableMapCache.java
mappingservice/mapcache/src/main/java/org/opendaylight/lispflowmapping/mapcache/SimpleMapCache.java

index 06f76661318e91e3a83ab13b923cfbd0d19fca0c..65a4e748b45d14997b0d8ec3393da3106560300d 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.lispflowmapping.interfaces.dao;
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.Map;
 
+import java.util.Set;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
 
 public interface ILispDAO {
@@ -99,6 +100,15 @@ public interface ILispDAO {
      */
     Eid getWidestNegativePrefix(Eid key);
 
+    /**
+     * Get the subtree of the given prefix.
+     *
+     * @param key
+     *            The eid prefix, IPv4 or IPv6, to be looked up. Key must be normalized.
+     * @return The set of EIDs that part of the subtree of the given EID.
+     */
+    Set<Eid> getSubtree(Eid key);
+
     /**
      * Enumerate all the entries from the DAO.
      *
index 597ab4c8e3af44b10925e8f4c68a8780b133e78f..6ddf4af4d650b4f1f4515e3e66cae0c19cdbec59 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.lispflowmapping.interfaces.mapcache;
 
+import java.util.Set;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
 
 /**
@@ -48,6 +49,15 @@ public interface IMapCache {
      */
     Eid getWidestNegativeMapping(Eid key);
 
+    /**
+     * Retrieves the subtree of a prefix.
+     *
+     * @param key
+     *            Key to be looked up
+     * @return The set of prefixes in the subtree for the prefix
+     */
+    Set<Eid> getSubtree(Eid key);
+
     /**
      * Remove mapping.
      *
index 03a28fbb4e4c766e44b196f5ce5c51d446d0ce5b..0df70387a75e4986ac4371e30a37de8c69c535eb 100644 (file)
@@ -9,7 +9,10 @@
 package org.opendaylight.lispflowmapping.inmemorydb;
 
 import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.opendaylight.lispflowmapping.inmemorydb.radixtrie.RadixTrie;
@@ -153,7 +156,8 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
                     break;
             }
             if (node != null) {
-                return LispAddressUtil.asIpv4PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
+                return LispAddressUtil.asIpv4PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
             }
         } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
             Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
@@ -177,7 +181,8 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
                     break;
             }
             if (node != null) {
-                return LispAddressUtil.asIpv6PrefixBinaryEid(key, node.prefix(), (short) node.prefixLength());
+                return LispAddressUtil.asIpv6PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
             }
         }
         return null;
@@ -203,6 +208,37 @@ public class HashMapDb implements ILispDAO, AutoCloseable {
         return getPrefix(key, GetPrefixMethods.WIDEST_NEGATIVE);
     }
 
+    @Override
+    public Set<Eid> getSubtree(Eid key) {
+        Set<RadixTrie<Object>.TrieNode> nodes = null;
+        if (key.getAddress() instanceof Ipv4PrefixBinary) {
+            Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
+            nodes = ip4Trie.lookupSubtree(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
+        } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
+            Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
+            nodes = ip6Trie.lookupSubtree(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
+        }
+        return nodesToEids(key, nodes);
+    }
+
+    private static Set<Eid> nodesToEids(Eid key, Set<RadixTrie<Object>.TrieNode> nodes) {
+        if (nodes == null || nodes.isEmpty()) {
+            return Collections.emptySet();
+        }
+
+        Set<Eid> children = new HashSet<>();
+        for (RadixTrie<Object>.TrieNode node : nodes) {
+            if (key.getAddress() instanceof Ipv4PrefixBinary) {
+                children.add(LispAddressUtil.asIpv4PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
+            } else if  (key.getAddress() instanceof Ipv6PrefixBinary) {
+                children.add(LispAddressUtil.asIpv6PrefixBinaryEid(
+                        key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
+            }
+        }
+        return children;
+    }
+
     private void tryRemoveFromTrie(Object key) {
         if (key instanceof Eid) {
             Eid eid = (Eid) key;
index c06ddb91f5a13c415f8750055a4f360c25305c33..744bfe605dc00d5057ae183b59132ab312a32742 100644 (file)
@@ -12,9 +12,12 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Deque;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.ListIterator;
+import java.util.Set;
 
 /**
  * Radix trie/tree (also known as Patricia tree) implementation. Supports CRD operations for
@@ -289,6 +292,37 @@ public class RadixTrie<T> {
         return null;
     }
 
+    /**
+     * Return the subtree for a prefix, including the prefix itself if present, excluding virtual nodes.
+     *
+     * @param prefix Big endian byte array representation of the prefix to be looked up.
+     * @param preflen Prefix length
+     * @return Subtree from the prefix
+     */
+    public Set<TrieNode> lookupSubtree(byte[] prefix, int preflen) {
+        if (root == null || preflen > maxBits) {
+            return Collections.emptySet();
+        }
+
+        TrieNode node = root.findClosest(prefix, preflen);
+
+        // if no node is found or if node not a prefix
+        if (node == null || node.prefix == null) {
+            return Collections.emptySet();
+        }
+
+        Set<TrieNode> children = new HashSet<>();
+        children.add(node);
+        Iterator<TrieNode> it = node.iterator();
+        while (it.hasNext()) {
+            node = it.next();
+            if (node.prefix != null) {
+                children.add(node);
+            }
+        }
+
+        return children;
+    }
 
     /**
      * Remove prefix from radix trie.
index d8f0d45a19f4c801f6e0a0739ed09d6e3b2477d4..6b17a29744680a4c62c00a93fe0e75a75c91af75 100644 (file)
@@ -17,6 +17,7 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.Set;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -335,6 +336,21 @@ public class RadixTrieTest {
         assertTrue(res.prefixLength() == 2);
     }
 
+    @Test
+    public void testIpv4ChildrenLookup() {
+        radixTrie4 = new RadixTrie<>(32, true);
+
+        addIp4Addresses(radixTrie4);
+        Set<RadixTrie<Integer>.TrieNode> res = radixTrie4.lookupSubtree(IP4_BYTES4, 24);
+        assertEquals(3, res.size());
+
+        radixTrie4 = new RadixTrie<>(32, true);
+
+        radixTrie4.insert(IP4_BYTES4, 24, 1);
+        res = radixTrie4.lookupSubtree(IP4_BYTES1, 16);
+        assertEquals(1, res.size());
+    }
+
     /**
      * Tests v6 CRD operations.
      * It just makes sure v6 prefix lengths don't generate problems. Therefore it's not as thorough as v4.
@@ -402,12 +418,25 @@ public class RadixTrieTest {
     }
 
     private void addIp4Addresses(RadixTrie<Integer> trie) {
+        // 192.168.1.1/32
         trie.insert(IP4_BYTES7, 32, 7);
+
+        // 192.168.1.0/25
         trie.insert(IP4_BYTES6, 25, 6);
+
+        // 192.168.2.0/24
         trie.insert(IP4_BYTES5, 24, 5);
+
+        // 192.168.1.0/24
         trie.insert(IP4_BYTES4, 24, 4);
+
+        // 192.169.0.0/16
         trie.insert(IP4_BYTES3, 16, 3);
+
+        // 192.167.0.0/16
         trie.insert(IP4_BYTES2, 16, 2);
+
+        // 192.168.0.0/16
         trie.insert(IP4_BYTES1, 16, 1);
     }
 
index f9a642c759aa93085d2878037c50b9be1b876e86..0821879c97a61be576aa94c9ff82f76806177fac 100644 (file)
@@ -485,11 +485,19 @@ public final class LispAddressUtil {
     }
 
     public static Eid asIpv4PrefixBinaryEid(Eid eid, byte[] address, short mask) {
+        return asIpv4PrefixBinaryEid(eid.getVirtualNetworkId(), address, mask);
+    }
+
+    public static Eid asIpv4PrefixBinaryEid(long vni, byte[] address, short mask) {
+        return asIpv4PrefixBinaryEid(new InstanceIdType(vni), address, mask);
+    }
+
+    public static Eid asIpv4PrefixBinaryEid(InstanceIdType vni, byte[] address, short mask) {
         Preconditions.checkArgument(address.length == 4,
                 "asIpv4PrefixBinaryEid called with incorrect length byte array ({})", address.length);
         EidBuilder builder = new EidBuilder();
         builder.setAddressType(Ipv4PrefixBinaryAfi.class);
-        builder.setVirtualNetworkId(eid.getVirtualNetworkId());
+        builder.setVirtualNetworkId(vni);
         builder.setAddress(new Ipv4PrefixBinaryBuilder().setIpv4AddressBinary(new Ipv4AddressBinary(address))
                 .setIpv4MaskLength(mask).build());
         return builder.build();
@@ -546,11 +554,19 @@ public final class LispAddressUtil {
     }
 
     public static Eid asIpv6PrefixBinaryEid(Eid eid, byte[] address, short mask) {
+        return asIpv6PrefixBinaryEid(eid.getVirtualNetworkId(), address, mask);
+    }
+
+    public static Eid asIpv6PrefixBinaryEid(long vni, byte[] address, short mask) {
+        return asIpv6PrefixBinaryEid(new InstanceIdType(vni), address, mask);
+    }
+
+    public static Eid asIpv6PrefixBinaryEid(InstanceIdType vni, byte[] address, short mask) {
         Preconditions.checkArgument(address.length == 16,
                 "asIpv6PrefixBinaryEid called with incorrect length byte array ({})", address.length);
         EidBuilder builder = new EidBuilder();
         builder.setAddressType(Ipv6PrefixBinaryAfi.class);
-        builder.setVirtualNetworkId(eid.getVirtualNetworkId());
+        builder.setVirtualNetworkId(vni);
         builder.setAddress(new Ipv6PrefixBinaryBuilder().setIpv6AddressBinary(new Ipv6AddressBinary(address))
                 .setIpv6MaskLength(mask).build());
         return builder.build();
index 32ab47f4e48be360ee69a9603842c4fe14d7f3f2..28165b855f2f548c1d45d53ad9e08227f60949d9 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.lispflowmapping.mapcache;
 
+import java.util.Collections;
+import java.util.Set;
 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
@@ -51,6 +53,11 @@ public class FlatMapCache implements IMapCache {
         return null;
     }
 
+    @Override
+    public Set<Eid> getSubtree(Eid key) {
+        return Collections.emptySet();
+    }
+
     @Override
     public void removeMapping(Eid eid) {
         Eid key = MaskUtil.normalize(eid);
index ebc9da441cbba1a46cdbe821726bd7e51a7c8999..6f62f72163906e9a6bde1ce4bad38a882283b3ee 100644 (file)
@@ -7,7 +7,9 @@
  */
 package org.opendaylight.lispflowmapping.mapcache;
 
+import java.util.Collections;
 import java.util.Map;
+import java.util.Set;
 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
@@ -137,6 +139,15 @@ public class MultiTableMapCache implements IMapCache {
         return table.getWidestNegativePrefix(key);
     }
 
+    @Override
+    public Set<Eid> getSubtree(Eid key) {
+        ILispDAO table = getVniTable(key);
+        if (table == null) {
+            return Collections.emptySet();
+        }
+        return table.getSubtree(key);
+    }
+
     public void removeMapping(Eid eid) {
         Eid key = MaskUtil.normalize(eid);
         ILispDAO table = getVniTable(key);
index 494129a5c28b7e1330b39e2be1abaa748a5921ae..562cd3fa19bb5e1256e3f56635dcd452b5853cd7 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.lispflowmapping.mapcache;
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -201,6 +202,15 @@ public class SimpleMapCache implements ILispMapCache {
         return table.getVirtualParentSiblingPrefix(MaskUtil.normalize(eid));
     }
 
+    @Override
+    public Set<Eid> getSubtree(Eid eid) {
+        ILispDAO table = getVniTable(eid);
+        if (table == null) {
+            return Collections.emptySet();
+        }
+        return table.getSubtree(eid);
+    }
+
     @Override
     public void removeMapping(Eid eid) {
         ILispDAO table = getVniTable(eid);