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.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.lispaddress.LispAddressContainer;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.lispaddress.lispaddresscontainer.address.LcafSourceDest;
21 import org.opendaylight.lispflowmapping.lisp.util.LcafSourceDestHelper;
22 import org.opendaylight.lispflowmapping.lisp.util.LispAFIConvertor;
23 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
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(LispAddressContainer key, Object value, boolean shouldOverwrite) {
44 LispAddressContainer eid = MaskUtil.normalize(key);
45 if (eid.getAddress() instanceof LcafSourceDest) {
46 LispAddressContainer srcKey = LcafSourceDestHelper.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(LispAddressContainer eid, ILispDAO dao) {
59 if (MaskUtil.isMaskable(eid)) {
60 LispAddressContainer key;
61 short mask = MaskUtil.getMaskForAddress(eid);
63 key = MaskUtil.normalize(eid, mask);
65 Map<String, ?> entry = dao.get(key);
72 Map<String, ?> entry = dao.get(eid);
81 private Object getMappingExactSD(LispAddressContainer srcEid, LispAddressContainer dstEid,
83 Map<String, ?> daoEntry = dao.get(dstEid);
84 if (daoEntry != null) {
85 // try SrcDst eid lookup
86 ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
87 if (srcEid != null && srcDstDao != null) {
88 return srcDstDao.getSpecific(srcEid, SubKeys.RECORD);
90 // if lookup fails, return whatever is found for dst eid
91 return daoEntry.get(SubKeys.RECORD);
96 // Returns the mapping corresponding to the longest prefix match for eid. eid must be a simple (maskable or not) address
97 private Object getMappingLpmEid(LispAddressContainer eid, ILispDAO dao) {
101 Map<String, ?> daoEntry = getDaoEntryBest(eid, dao);
102 if (daoEntry != null) {
103 return daoEntry.get(SubKeys.RECORD);
109 // Returns a mapping corresponding to either the longest prefix match for both dstEid and srcEid,
110 // if a SourceDest mapping exists, or to dstEid
111 private Object getMappingLpmSD(LispAddressContainer srcEid, LispAddressContainer dstEid, ILispDAO dao) {
112 Map<String, ?> daoEntry = getDaoEntryBest(dstEid, dao);
113 if (daoEntry != null) {
114 // try SrcDst eid lookup
115 ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
116 if (srcDstDao != null) {
117 Object mapping = getMappingLpmEid(srcEid, srcDstDao);
118 if (mapping!= null) {
123 // if lookup fails, return whatever is found for dst eid
124 return daoEntry.get(SubKeys.RECORD);
129 public Object getMapping(LispAddressContainer srcEid, LispAddressContainer dstEid) {
130 if (dstEid == null) {
134 // a map-request for an actual SrcDst LCAF, ignore src eid
135 if (dstEid.getAddress() instanceof LcafSourceDest) {
136 LispAddressContainer srcAddr = LcafSourceDestHelper.getSrc(dstEid);
137 LispAddressContainer dstAddr = LcafSourceDestHelper.getDst(dstEid);
138 return getMappingLpmSD(srcAddr, dstAddr, dao);
141 // potential map-request for SrcDst LCAF from non SrcDst capable devices
142 return getMappingLpmSD(srcEid, dstEid, dao);
145 public void removeMapping(LispAddressContainer eid, boolean overwrite) {
146 eid = MaskUtil.normalize(eid);
147 if (eid.getAddress() instanceof LcafSourceDest) {
148 ILispDAO db = getSDInnerDao(eid, dao);
150 db.removeSpecific(LcafSourceDestHelper.getSrc(eid),
154 dao.removeSpecific(eid, SubKeys.RECORD);
158 public void addAuthenticationKey(LispAddressContainer eid, String key) {
159 eid = MaskUtil.normalize(eid);
160 if (eid.getAddress() instanceof LcafSourceDest) {
161 ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, dao);
162 srcDstDao.put(LcafSourceDestHelper.getSrc(eid), new MappingEntry<String>(SubKeys.AUTH_KEY, key));
164 dao.put(eid, new MappingEntry<String>(SubKeys.AUTH_KEY, key));
168 private String getAuthKeyLpm(LispAddressContainer prefix, ILispDAO db) {
169 short maskLength = MaskUtil.getMaskForAddress(prefix);
170 while (maskLength >= 0) {
171 LispAddressContainer key = MaskUtil.normalize(prefix, maskLength);
172 Object password = db.getSpecific(key, SubKeys.AUTH_KEY);
173 if (password != null && password instanceof String) {
174 return (String) password;
181 public String getAuthenticationKey(LispAddressContainer eid) {
182 if (MaskUtil.isMaskable(LispAFIConvertor.toAFI(eid))) {
183 return getAuthKeyLpm(eid, dao);
184 } else if (eid.getAddress() instanceof LcafSourceDest) {
185 // NOTE: this is an exact match, not a longest prefix match
186 ILispDAO srcDstDao = getSDInnerDao(eid, dao);
187 if (srcDstDao != null) {
188 return getAuthKeyLpm(LcafSourceDestHelper.getSrc(eid), srcDstDao);
192 Object password = dao.getSpecific(eid, SubKeys.AUTH_KEY);
193 if (password != null && password instanceof String) {
194 return (String) password;
196 LOG.warn("Failed to find password!");
202 public void removeAuthenticationKey(LispAddressContainer eid) {
203 eid = MaskUtil.normalize(eid);
204 if (eid.getAddress() instanceof LcafSourceDest) {
205 ILispDAO srcDstDao = getSDInnerDao(eid, dao);
206 if (srcDstDao != null) {
207 srcDstDao.removeSpecific(eid, SubKeys.AUTH_KEY);
210 dao.removeSpecific(eid, SubKeys.AUTH_KEY);
214 // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
215 // This method returns the DAO associated to a dst or creates it if it doesn't exist.
216 private ILispDAO getOrInstantiateSDInnerDao(LispAddressContainer address, ILispDAO dao) {
217 LispAddressContainer dstKey = LcafSourceDestHelper.getDst(address);
218 ILispDAO srcDstDao = (ILispDAO) dao.getSpecific(dstKey, SubKeys.LCAF_SRCDST);
219 if (srcDstDao == null) {
220 // inserts nested table for source
221 srcDstDao = dao.putNestedTable(dstKey, SubKeys.LCAF_SRCDST);
226 // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
227 // This method returns the DAO associated to dst or null if it doesn't exist.
228 private ILispDAO getSDInnerDao(LispAddressContainer address, ILispDAO dao) {
229 return (ILispDAO) dao.getSpecific(LcafSourceDestHelper.getDst(address), SubKeys.LCAF_SRCDST);
232 public String printMappings() {
233 final StringBuffer sb = new StringBuffer();
234 sb.append("Keys\tValues\n");
235 final IRowVisitor innerVisitor = (new IRowVisitor() {
238 public void visitRow(Object keyId, String valueKey, Object value) {
239 String key = keyId.getClass().getSimpleName() + "#" + keyId;
240 if (!lastKey.equals(key)) {
241 sb.append(key + "\t");
243 if (!(valueKey.equals(SubKeys.LCAF_SRCDST))) {
244 sb.append(valueKey + "=" + value + "\t");
249 dao.getAll(new IRowVisitor() {
252 public void visitRow(Object keyId, String valueKey, Object value) {
253 String key = keyId.getClass().getSimpleName() + "#" + keyId;
254 if (!lastKey.equals(key)) {
255 sb.append("\n" + key + "\t");
257 if (valueKey.equals(SubKeys.LCAF_SRCDST)) {
258 sb.append(valueKey + "= { ");
259 ((ILispDAO)value).getAll(innerVisitor);
262 sb.append(valueKey + "=" + value + "\t");
268 return sb.toString();
272 public void updateMappingRegistration(LispAddressContainer key) {
277 public void addData(LispAddressContainer key, String subKey, Object data) {
278 key = MaskUtil.normalize(key);
279 if (key.getAddress() instanceof LcafSourceDest) {
280 ILispDAO srcDstDao = getOrInstantiateSDInnerDao(key, dao);
281 srcDstDao.put(LcafSourceDestHelper.getSrc(key), new MappingEntry<Object>(subKey, data));
283 dao.put(key, new MappingEntry<Object>(subKey, data));
288 public Object getData(LispAddressContainer eid, String subKey) {
289 if (eid.getAddress() instanceof LcafSourceDest) {
290 ILispDAO srcDstDao = getSDInnerDao(eid, dao);
291 return srcDstDao.getSpecific(LcafSourceDestHelper.getSrc(eid), subKey);
293 return dao.getSpecific(eid, subKey);
298 public void removeData(LispAddressContainer key, String subKey) {
299 key = MaskUtil.normalize(key);
300 if (key.getAddress() instanceof LcafSourceDest) {
301 ILispDAO db = getSDInnerDao(key, dao);
303 db.removeSpecific(LcafSourceDestHelper.getSrc(key), subKey);
306 dao.removeSpecific(key, subKey);