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
8 package org.opendaylight.lispflowmapping.inmemorydb;
10 import java.util.AbstractMap.SimpleImmutableEntry;
11 import java.util.HashSet;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.lispflowmapping.inmemorydb.radixtrie.RadixTrie;
20 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
21 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
22 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
23 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
27 import org.osgi.service.component.annotations.Activate;
28 import org.osgi.service.component.annotations.Component;
29 import org.osgi.service.component.annotations.Deactivate;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 @Component(service = ILispDAO.class, immediate = true, property = "type=default")
35 public class HashMapDb implements ILispDAO, AutoCloseable {
36 private static final Logger LOG = LoggerFactory.getLogger(HashMapDb.class);
37 private static final Object TABLES = "tables";
39 private final ConcurrentMap<Object, ConcurrentMap<String, Object>> data = new ConcurrentHashMap<>();
41 // IPv4 and IPv6 radix tries used for longest prefix matching
42 private final RadixTrie<Object> ip4Trie = new RadixTrie<>(32, true);
43 private final RadixTrie<Object> ip6Trie = new RadixTrie<>(128, true);
45 private enum GetPrefixMethods {
48 VIRTUAL_PARENT_SIBLING,
66 public void tryAddToIpTrie(Object key) {
67 if (key instanceof Eid) {
69 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
70 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
71 ip4Trie.insert(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength().toJava(), key);
72 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
73 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
74 ip6Trie.insert(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength().toJava(), key);
80 public void put(Object key, MappingEntry<?>... values) {
81 if (!data.containsKey(key)) {
82 data.put(key, new ConcurrentHashMap<String, Object>());
84 for (MappingEntry<?> entry : values) {
86 data.get(key).put(entry.getKey(), entry.getValue());
91 public Object getSpecific(Object key, String valueKey) {
92 Map<String, Object> keyToValues = data.get(key);
93 if (keyToValues == null) {
96 return keyToValues.get(valueKey);
100 public Map<String, Object> get(Object key) {
101 return data.get(key);
104 private RadixTrie<Object>.TrieNode lookupBestNode(Eid eid) {
105 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
106 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
107 return ip4Trie.lookupBest(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength().toJava());
108 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
109 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
110 return ip6Trie.lookupBest(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength().toJava());
116 public Map<String, Object> getBest(Object key) {
117 if (key instanceof Eid) {
119 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
123 return get(node.data());
129 public SimpleImmutableEntry<Eid, Map<String, ?>> getBestPair(Object key) {
130 Map<String, ?> result = null;
132 if (key instanceof Eid) {
134 RadixTrie<Object>.TrieNode node = lookupBestNode(eid);
137 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)key, result);
139 result = get(node.data());
140 return (result == null) ? null : new SimpleImmutableEntry<>((Eid)node.data(), result);
146 public void getAll(IRowVisitor visitor) {
147 for (ConcurrentMap.Entry<Object, ConcurrentMap<String, Object>> keyEntry : data.entrySet()) {
148 for (Map.Entry<String, Object> valueEntry : keyEntry.getValue().entrySet()) {
149 visitor.visitRow(keyEntry.getKey(), valueEntry.getKey(), valueEntry.getValue());
154 private Eid getPrefix(Eid key, GetPrefixMethods method) {
155 RadixTrie<Object>.TrieNode node = null;
157 if (key.getAddress() instanceof Ipv4PrefixBinary) {
158 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
161 node = ip4Trie.lookupCoveringLessSpecific(prefix.getIpv4AddressBinary().getValue(),
162 prefix.getIpv4MaskLength().toJava());
165 node = ip4Trie.lookupParent(prefix.getIpv4AddressBinary().getValue(),
166 prefix.getIpv4MaskLength().toJava());
169 node = ip4Trie.lookupSibling(prefix.getIpv4AddressBinary().getValue(),
170 prefix.getIpv4MaskLength().toJava());
172 case VIRTUAL_PARENT_SIBLING:
173 node = ip4Trie.lookupVirtualParentSibling(prefix.getIpv4AddressBinary().getValue(),
174 prefix.getIpv4MaskLength().toJava());
176 case WIDEST_NEGATIVE:
177 node = ip4Trie.lookupWidestNegative(prefix.getIpv4AddressBinary().getValue(),
178 prefix.getIpv4MaskLength().toJava());
184 if (node != null && node.prefix() != null) {
185 return LispAddressUtil.asIpv4PrefixBinaryEid(
186 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
188 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
189 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
192 node = ip6Trie.lookupCoveringLessSpecific(prefix.getIpv6AddressBinary().getValue(),
193 prefix.getIpv6MaskLength().toJava());
196 node = ip6Trie.lookupParent(prefix.getIpv6AddressBinary().getValue(),
197 prefix.getIpv6MaskLength().toJava());
200 node = ip6Trie.lookupSibling(prefix.getIpv6AddressBinary().getValue(),
201 prefix.getIpv6MaskLength().toJava());
203 case VIRTUAL_PARENT_SIBLING:
204 node = ip6Trie.lookupVirtualParentSibling(prefix.getIpv6AddressBinary().getValue(),
205 prefix.getIpv6MaskLength().toJava());
207 case WIDEST_NEGATIVE:
208 node = ip6Trie.lookupWidestNegative(prefix.getIpv6AddressBinary().getValue(),
209 prefix.getIpv6MaskLength().toJava());
215 if (node != null && node.prefix() != null) {
216 return LispAddressUtil.asIpv6PrefixBinaryEid(
217 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength());
224 public Eid getCoveringLessSpecific(Eid key) {
225 return getPrefix(key, GetPrefixMethods.COVERING);
229 public Eid getParentPrefix(Eid key) {
230 return getPrefix(key, GetPrefixMethods.PARENT);
234 public Eid getSiblingPrefix(Eid key) {
235 return getPrefix(key, GetPrefixMethods.SIBLING);
239 public Eid getVirtualParentSiblingPrefix(Eid key) {
240 return getPrefix(key, GetPrefixMethods.VIRTUAL_PARENT_SIBLING);
244 public Eid getWidestNegativePrefix(Eid key) {
245 return getPrefix(key, GetPrefixMethods.WIDEST_NEGATIVE);
249 public Set<Eid> getSubtree(Eid key) {
250 Set<RadixTrie<Object>.TrieNode> nodes = null;
251 if (key.getAddress() instanceof Ipv4PrefixBinary) {
252 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) key.getAddress();
253 nodes = ip4Trie.lookupSubtree(prefix.getIpv4AddressBinary().getValue(),
254 prefix.getIpv4MaskLength().toJava());
255 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
256 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) key.getAddress();
257 nodes = ip6Trie.lookupSubtree(prefix.getIpv6AddressBinary().getValue(),
258 prefix.getIpv6MaskLength().toJava());
260 return nodesToEids(key, nodes);
263 private static Set<Eid> nodesToEids(Eid key, Set<RadixTrie<Object>.TrieNode> nodes) {
264 if (nodes == null || nodes.isEmpty()) {
268 Set<Eid> children = new HashSet<>();
269 for (RadixTrie<Object>.TrieNode node : nodes) {
270 if (key.getAddress() instanceof Ipv4PrefixBinary) {
271 children.add(LispAddressUtil.asIpv4PrefixBinaryEid(
272 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
273 } else if (key.getAddress() instanceof Ipv6PrefixBinary) {
274 children.add(LispAddressUtil.asIpv6PrefixBinaryEid(
275 key.getVirtualNetworkId(), node.prefix(), (short) node.prefixLength()));
281 private void tryRemoveFromTrie(Object key) {
282 if (key instanceof Eid) {
284 if (eid.getAddress() instanceof Ipv4PrefixBinary) {
285 Ipv4PrefixBinary prefix = (Ipv4PrefixBinary) eid.getAddress();
286 ip4Trie.remove(prefix.getIpv4AddressBinary().getValue(), prefix.getIpv4MaskLength().toJava());
287 } else if (eid.getAddress() instanceof Ipv6PrefixBinary) {
288 Ipv6PrefixBinary prefix = (Ipv6PrefixBinary) eid.getAddress();
289 ip6Trie.remove(prefix.getIpv6AddressBinary().getValue(), prefix.getIpv6MaskLength().toJava());
295 public void remove(Object key) {
296 tryRemoveFromTrie(key);
301 public void removeSpecific(Object key, String valueKey) {
302 Map<String, Object> keyToValues = data.get(key);
303 if (keyToValues == null) {
307 synchronized (keyToValues) {
308 if (keyToValues.containsKey(valueKey)) {
309 keyToValues.remove(valueKey);
310 if (keyToValues.isEmpty()) {
318 public void removeAll() {
325 public ILispDAO putNestedTable(Object key, String valueKey) {
326 ILispDAO nestedTable = (ILispDAO) getSpecific(key, valueKey);
327 if (nestedTable != null) {
328 LOG.warn("Trying to add nested table that already exists. Aborting!");
331 nestedTable = new HashMapDb();
332 put(key, new MappingEntry<>(valueKey, nestedTable));
337 public ILispDAO putTable(String key) {
338 ILispDAO table = (ILispDAO) getSpecific(TABLES, key);
340 LOG.warn("Trying to add table that already exists. Aborting!");
343 table = new HashMapDb();
344 put(TABLES, new MappingEntry<>(key, table));
349 public boolean isEmpty() {
350 return data.isEmpty();