2 * Copyright (c) 2014 Contextream, Inc. and others. 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.implementation.mapcache;
11 import java.util.Date;
14 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
15 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
16 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
17 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
18 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMapCache;
19 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
20 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.authkey.container.MappingAuthkey;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Multi table map-cache that works with 'simple' and SourceDest LCAF addresses (see lisp-proto.yang). It can do longest
29 * prefix matching for IP and SourceDest LCAF addresses. In case of the latter, it uses two tables, one for dst and
30 * another for source, queried and populated in this exact order.
32 * @author Florin Coras
35 public class MultiTableMapCache implements IMapCache {
36 private static final Logger LOG = LoggerFactory.getLogger(MultiTableMapCache.class);
39 public MultiTableMapCache(ILispDAO dao) {
43 public void addMapping(Eid key, Object value, boolean shouldOverwrite) {
44 Eid eid = MaskUtil.normalize(key);
45 if (eid.getAddress() instanceof SourceDestKey) {
46 Eid srcKey = SourceDestKeyHelper.getSrc(eid);
47 ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, dao);
48 srcDstDao.put(srcKey, new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
49 srcDstDao.put(srcKey, new MappingEntry<>(SubKeys.RECORD, value));
51 dao.put(eid, new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
52 dao.put(eid, new MappingEntry<>(SubKeys.RECORD, value));
56 // Method returns the DAO entry (hash) corresponding to either the longest prefix match of eid, if eid is maskable,
57 // or the exact match otherwise. eid must be a 'simple' address
58 private Map<String, ?> getDaoEntryBest(Eid eid, ILispDAO dao) {
59 if (MaskUtil.isMaskable(eid.getAddress())) {
61 short mask = MaskUtil.getMaskForAddress(eid.getAddress());
63 key = MaskUtil.normalize(eid, mask);
65 Map<String, ?> entry = dao.get(key);
72 Map<String, ?> entry = dao.get(eid);
81 private Object getMappingExactSD(Eid srcEid, Eid dstEid, ILispDAO dao) {
82 Map<String, ?> daoEntry = dao.get(dstEid);
83 if (daoEntry != null) {
84 // try SrcDst eid lookup
85 ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
86 if (srcEid != null && srcDstDao != null) {
87 return srcDstDao.getSpecific(srcEid, SubKeys.RECORD);
89 // if lookup fails, return whatever is found for dst eid
90 return daoEntry.get(SubKeys.RECORD);
95 // Returns the mapping corresponding to the longest prefix match for eid. eid must be a simple (maskable or not) address
96 private Object getMappingLpmEid(Eid eid, ILispDAO dao) {
100 Map<String, ?> daoEntry = getDaoEntryBest(eid, dao);
101 if (daoEntry != null) {
102 return daoEntry.get(SubKeys.RECORD);
108 // Returns a mapping corresponding to either the longest prefix match for both dstEid and srcEid,
109 // if a SourceDest mapping exists, or to dstEid
110 private Object getMappingLpmSD(Eid srcEid, Eid dstEid, ILispDAO dao) {
111 Map<String, ?> daoEntry = getDaoEntryBest(dstEid, dao);
112 if (daoEntry != null) {
113 // try SrcDst eid lookup
114 ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
115 if (srcDstDao != null) {
116 Object mapping = getMappingLpmEid(srcEid, srcDstDao);
117 if (mapping!= null) {
122 // if lookup fails, return whatever is found for dst eid
123 return daoEntry.get(SubKeys.RECORD);
128 public Object getMapping(Eid srcEid, Eid dstEid) {
129 if (dstEid == null) {
133 // a map-request for an actual SrcDst LCAF, ignore src eid
134 if (dstEid.getAddress() instanceof SourceDestKey) {
135 Eid srcAddr = SourceDestKeyHelper.getSrc(dstEid);
136 Eid dstAddr = SourceDestKeyHelper.getDst(dstEid);
137 return getMappingLpmSD(srcAddr, dstAddr, dao);
140 // potential map-request for SrcDst LCAF from non SrcDst capable devices
141 return getMappingLpmSD(srcEid, dstEid, dao);
144 public void removeMapping(Eid eid, boolean overwrite) {
145 eid = MaskUtil.normalize(eid);
146 if (eid.getAddress() instanceof SourceDestKey) {
147 ILispDAO db = getSDInnerDao(eid, dao);
149 db.removeSpecific(SourceDestKeyHelper.getSrc(eid),
153 dao.removeSpecific(eid, SubKeys.RECORD);
157 public void addAuthenticationKey(Eid eid, MappingAuthkey key) {
158 eid = MaskUtil.normalize(eid);
159 if (eid.getAddress() instanceof SourceDestKey) {
160 ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, dao);
161 srcDstDao.put(SourceDestKeyHelper.getSrc(eid), new MappingEntry<>(SubKeys.AUTH_KEY, key));
163 dao.put(eid, new MappingEntry<>(SubKeys.AUTH_KEY, key));
167 private MappingAuthkey getAuthKeyLpm(Eid prefix, ILispDAO db) {
168 short maskLength = MaskUtil.getMaskForAddress(prefix.getAddress());
169 while (maskLength >= 0) {
170 Eid key = MaskUtil.normalize(prefix, maskLength);
171 Object password = db.getSpecific(key, SubKeys.AUTH_KEY);
172 if (password != null && password instanceof MappingAuthkey) {
173 return (MappingAuthkey) password;
180 public MappingAuthkey getAuthenticationKey(Eid eid) {
181 if (MaskUtil.isMaskable(eid.getAddress())) {
182 return getAuthKeyLpm(eid, dao);
183 } else if (eid.getAddress() instanceof SourceDestKey) {
184 // NOTE: this is an exact match, not a longest prefix match
185 ILispDAO srcDstDao = getSDInnerDao(eid, dao);
186 if (srcDstDao != null) {
187 return getAuthKeyLpm(SourceDestKeyHelper.getSrc(eid), srcDstDao);
191 Object password = dao.getSpecific(eid, SubKeys.AUTH_KEY);
192 if (password != null && password instanceof MappingAuthkey) {
193 return (MappingAuthkey) password;
195 LOG.warn("Failed to find password!");
201 public void removeAuthenticationKey(Eid eid) {
202 eid = MaskUtil.normalize(eid);
203 if (eid.getAddress() instanceof SourceDestKey) {
204 ILispDAO srcDstDao = getSDInnerDao(eid, dao);
205 if (srcDstDao != null) {
206 srcDstDao.removeSpecific(eid, SubKeys.AUTH_KEY);
209 dao.removeSpecific(eid, SubKeys.AUTH_KEY);
213 // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
214 // This method returns the DAO associated to a dst or creates it if it doesn't exist.
215 private ILispDAO getOrInstantiateSDInnerDao(Eid address, ILispDAO dao) {
216 Eid dstKey = SourceDestKeyHelper.getDst(address);
217 ILispDAO srcDstDao = (ILispDAO) dao.getSpecific(dstKey, SubKeys.LCAF_SRCDST);
218 if (srcDstDao == null) {
219 // inserts nested table for source
220 srcDstDao = dao.putNestedTable(dstKey, SubKeys.LCAF_SRCDST);
225 // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
226 // This method returns the DAO associated to dst or null if it doesn't exist.
227 private ILispDAO getSDInnerDao(Eid address, ILispDAO dao) {
228 return (ILispDAO) dao.getSpecific(SourceDestKeyHelper.getDst(address), SubKeys.LCAF_SRCDST);
231 public String printMappings() {
232 final StringBuffer sb = new StringBuffer();
233 sb.append("Keys\tValues\n");
234 final IRowVisitor innerVisitor = (new IRowVisitor() {
237 public void visitRow(Object keyId, String valueKey, Object value) {
238 String key = keyId.getClass().getSimpleName() + "#" + keyId;
239 if (!lastKey.equals(key)) {
240 sb.append(key + "\t");
242 if (!(valueKey.equals(SubKeys.LCAF_SRCDST))) {
243 sb.append(valueKey + "=" + value + "\t");
248 dao.getAll(new IRowVisitor() {
251 public void visitRow(Object keyId, String valueKey, Object value) {
252 String key = keyId.getClass().getSimpleName() + "#" + keyId;
253 if (!lastKey.equals(key)) {
254 sb.append("\n" + key + "\t");
256 if (valueKey.equals(SubKeys.LCAF_SRCDST)) {
257 sb.append(valueKey + "= { ");
258 ((ILispDAO)value).getAll(innerVisitor);
261 sb.append(valueKey + "=" + value + "\t");
267 return sb.toString();
271 public void updateMappingRegistration(Eid key) {
276 public void addData(Eid key, String subKey, Object data) {
277 key = MaskUtil.normalize(key);
278 if (key.getAddress() instanceof SourceDestKey) {
279 ILispDAO srcDstDao = getOrInstantiateSDInnerDao(key, dao);
280 srcDstDao.put(SourceDestKeyHelper.getSrc(key), new MappingEntry<Object>(subKey, data));
282 dao.put(key, new MappingEntry<Object>(subKey, data));
287 public Object getData(Eid eid, String subKey) {
288 if (eid.getAddress() instanceof SourceDestKey) {
289 ILispDAO srcDstDao = getSDInnerDao(eid, dao);
290 return srcDstDao.getSpecific(SourceDestKeyHelper.getSrc(eid), subKey);
292 return dao.getSpecific(eid, subKey);
297 public void removeData(Eid key, String subKey) {
298 key = MaskUtil.normalize(key);
299 if (key.getAddress() instanceof SourceDestKey) {
300 ILispDAO db = getSDInnerDao(key, dao);
302 db.removeSpecific(SourceDestKeyHelper.getSrc(key), subKey);
305 dao.removeSpecific(key, subKey);