2 * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.lispflowmapping.inmemorydb;
11 import java.util.AbstractMap.SimpleImmutableEntry;
12 import java.util.Collections;
13 import java.util.HashSet;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import org.opendaylight.lispflowmapping.inmemorydb.radixtrie.RadixTrie;
19 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
20 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
21 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
22 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 public class HashMapDb implements ILispDAO, AutoCloseable {
31 protected static final Logger LOG = LoggerFactory.getLogger(HashMapDb.class);
32 private static final Object TABLES = (Object) "tables";
33 private ConcurrentMap<Object, ConcurrentMap<String, Object>> data = new ConcurrentHashMap<>();
35 // IPv4 and IPv6 radix tries used for longest prefix matching
36 private RadixTrie<Object> ip4Trie = new RadixTrie<>(32, true);
37 private RadixTrie<Object> ip6Trie = new RadixTrie<>(128, true);
39 private enum GetPrefixMethods {
42 VIRTUAL_PARENT_SIBLING,
47 public void tryAddToIpTrie(Object key) {
48 if (key instanceof Eid) {
50 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
51 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
52 ip4Trie.insert(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength(), key);
53 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
54 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
55 ip6Trie.insert(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength(), key);
61 public void put(Object key, MappingEntry<?>... values) {
62 if (!data.containsKey(key)) {
63 data.put(key, new ConcurrentHashMap<String, Object>());
65 for (MappingEntry<?> entry : values) {
67 data.get(key).put(entry.getKey(), entry.getValue());
72 public Object getSpecific(Object key, String valueKey) {
73 Map<String, Object> keyToValues = data.get(key);
74 if (keyToValues == null) {
77 return keyToValues.get(valueKey);
81 public Map<String, Object> get(Object key) {
85 private RadixTrie<Object>.TrieNode lookupBestNode(Eid eid) {
86 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
87 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
88 return ip4Trie.lookupBest(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
89 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
90 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
91 return ip6Trie.lookupBest(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
97 public Map<String, Object> getBest(Object key) {
98 if (key instanceof Eid) {
100 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
104 return get(node.data());
110 public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
111 Map<String, ?> result = null;
113 if (key instanceof Eid) {
115 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
118 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)key, result);
120 result = get(node.data());
121 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), result);
127 public void getAll(IRowVisitor visitor) {
128 for (ConcurrentMap.Entry<Object, ConcurrentMap<String, Object>> keyEntry : data.entrySet()) {
129 for (Map.Entry<String, Object> valueEntry : keyEntry.getValue().entrySet()) {
130 visitor.visitRow(keyEntry.getKey(), valueEntry.getKey(), valueEntry.getValue());
135 private Eid getPrefix(Eid key, GetPrefixMethods method) {
136 RadixTrie<Object>.TrieNode node = null;
138 if (key.getAddress() instanceof Ipv4PrefixBinary) {
139 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
142 node = ip4Trie.lookupCoveringLessSpecific(prefix.getIpv4AddressBinary().getValue(),
143 prefix.getIpv4MaskLength());
146 node = ip4Trie.lookupParent(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
149 node = ip4Trie.lookupSibling(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
151 case VIRTUAL_PARENT_SIBLING:
152 node = ip4Trie.lookupVirtualParentSibling(prefix.getIpv4AddressBinary().getValue(),
153 prefix.getIpv4MaskLength());
155 case WIDEST_NEGATIVE:
156 node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(),
157 prefix.getIpv4MaskLength());
163 if (node != null && node.prefix() != null) {
164 return LispAddressUtil.asIpv4PrefixBinaryEid(
165 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
167 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
168 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
171 node = ip6Trie.lookupCoveringLessSpecific(prefix.getIpv6AddressBinary().getValue(),
172 prefix.getIpv6MaskLength());
175 node = ip6Trie.lookupParent(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
178 node = ip6Trie.lookupSibling(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
180 case VIRTUAL_PARENT_SIBLING:
181 node = ip6Trie.lookupVirtualParentSibling(prefix.getIpv6AddressBinary().getValue(),
182 prefix.getIpv6MaskLength());
184 case WIDEST_NEGATIVE:
185 node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(),
186 prefix.getIpv6MaskLength());
192 if (node != null && node.prefix() != null) {
193 return LispAddressUtil.asIpv6PrefixBinaryEid(
194 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
201 public Eid getCoveringLessSpecific(Eid key) {
202 return getPrefix(key, GetPrefixMethods.COVERING);
206 public Eid getParentPrefix(Eid key) {
207 return getPrefix(key, GetPrefixMethods.PARENT);
211 public Eid getSiblingPrefix(Eid key) {
212 return getPrefix(key, GetPrefixMethods.SIBLING);
216 public Eid getVirtualParentSiblingPrefix(Eid key) {
217 return getPrefix(key, GetPrefixMethods.VIRTUAL_PARENT_SIBLING);
221 public Eid getWidestNegativePrefix(Eid key) {
222 return getPrefix(key, GetPrefixMethods.WIDEST_NEGATIVE);
226 public Set<Eid> getSubtree(Eid key) {
227 Set<RadixTrie<Object>.TrieNode> nodes = null;
228 if (key.getAddress() instanceof Ipv4PrefixBinary) {
229 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
230 nodes = ip4Trie.lookupSubtree(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
231 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
232 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
233 nodes = ip6Trie.lookupSubtree(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
235 return nodesToEids(key, nodes);
238 private static Set<Eid> nodesToEids(Eid key, Set<RadixTrie<Object>.TrieNode> nodes) {
239 if (nodes == null || nodes.isEmpty()) {
240 return Collections.emptySet();
243 Set<Eid> children = new HashSet<>();
244 for (RadixTrie<Object>.TrieNode node : nodes) {
245 if (key.getAddress() instanceof Ipv4PrefixBinary) {
246 children.add(LispAddressUtil.asIpv4PrefixBinaryEid(
247 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
248 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
249 children.add(LispAddressUtil.asIpv6PrefixBinaryEid(
250 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
256 private void tryRemoveFromTrie(Object key) {
257 if (key instanceof Eid) {
259 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
260 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
261 ip4Trie.remove(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength());
262 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
263 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
264 ip6Trie.remove(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength());
270 public void remove(Object key) {
271 tryRemoveFromTrie(key);
276 public void removeSpecific(Object key, String valueKey) {
277 Map<String, Object> keyToValues = data.get(key);
278 if (keyToValues == null) {
282 synchronized (keyToValues) {
283 if (keyToValues.containsKey(valueKey)) {
284 keyToValues.remove(valueKey);
285 if (keyToValues.isEmpty()) {
293 public void removeAll() {
299 public void close() throws Exception {
304 public ILispDAO putNestedTable(Object key, String valueKey) {
305 ILispDAO nestedTable = (ILispDAO) getSpecific(key, valueKey);
306 if (nestedTable != null) {
307 LOG.warn("Trying to add nested table that already exists. Aborting!");
310 nestedTable = new HashMapDb();
311 put(key, new MappingEntry<>(valueKey, nestedTable));
316 public ILispDAO putTable(String key) {
317 ILispDAO table = (ILispDAO) getSpecific(TABLES, key);
319 LOG.warn("Trying to add table that already exists. Aborting!");
322 table = new HashMapDb();
323 put(TABLES, new MappingEntry<>(key, table));
328 public boolean isEmpty() {
329 return data.isEmpty();