2 * Copyright (c) 2015 Cisco Systems, 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.mapcache;
11 import java.util.AbstractMap.SimpleImmutableEntry;
12 import java.util.ArrayList;
13 import java.util.Date;
14 import java.util.HashSet;
15 import java.util.List;
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.interfaces.dao.SubKeys;
23 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMapCache;
24 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.IpAddressBinary;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.authkey.container.MappingAuthkey;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * Simple map-cache that works with 'simple' addresses (see lisp-proto.yang). It can do longest prefix matching for IP
38 * @author Florin Coras
39 * @author Lorand Jakab
42 public class SimpleMapCache implements IMapCache {
43 private static final Logger LOG = LoggerFactory.getLogger(SimpleMapCache.class);
46 public SimpleMapCache(ILispDAO dao) {
50 private ILispDAO getVniTable(Eid eid) {
52 if (eid.getVirtualNetworkId() == null) {
55 vni = eid.getVirtualNetworkId().getValue();
57 return (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
60 private ILispDAO getOrInstantiateVniTable(Eid eid) {
62 if (eid.getVirtualNetworkId() == null) {
65 vni = eid.getVirtualNetworkId().getValue();
67 ILispDAO table = (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
69 table = dao.putNestedTable(vni, SubKeys.VNI);
74 private ILispDAO getXtrIdTable(Eid eid, ILispDAO dao) {
75 return (ILispDAO) dao.getSpecific(eid, SubKeys.XTRID_RECORDS);
78 private ILispDAO getOrInstantiateXtrIdTable(Eid eid, ILispDAO dao) {
79 ILispDAO table = (ILispDAO) dao.getSpecific(eid, SubKeys.XTRID_RECORDS);
81 table = dao.putNestedTable(eid, SubKeys.XTRID_RECORDS);
86 private void removeExpiredXtrIdTableEntries(ILispDAO xtrIdDao, List<XtrId> expiredMappings) {
87 for (XtrId xtrId : expiredMappings) {
88 xtrIdDao.removeSpecific(xtrId, SubKeys.RECORD);
92 public void addMapping(Eid key, Object value, boolean shouldOverwrite, boolean shouldMerge) {
94 LOG.warn("addMapping() called with null 'value', ignoring");
98 if (!(value instanceof MappingRecord)) {
99 LOG.warn("addMapping() called with a 'value' that is not a 'MappingRecord', ignoring");
103 MappingRecord record = (MappingRecord) value;
104 if (record.getXtrId() == null && !shouldOverwrite && shouldMerge) {
105 LOG.warn("addMapping() called will null xTR-ID in MappingRecord, while merge is set, ignoring");
109 Date regdate = new Date(record.getTimestamp()); // The serializer always sets it
110 Eid eid = MaskUtil.normalize(key);
111 ILispDAO table = getOrInstantiateVniTable(key);
113 ILispDAO xtrIdDao = null;
114 if (!shouldOverwrite) {
115 xtrIdDao = getOrInstantiateXtrIdTable(eid, table);
116 xtrIdDao.put(record.getXtrId(), new MappingEntry<>(SubKeys.RECORD, value));
120 List<XtrId> expiredMappings = new ArrayList<XtrId>();
121 Set<IpAddressBinary> sourceRlocs = new HashSet<IpAddressBinary>();
122 MappingRecord mergedEntry = MappingMergeUtil.mergeXtrIdMappings(getXtrIdMappingList(xtrIdDao),
123 expiredMappings, sourceRlocs);
124 removeExpiredXtrIdTableEntries(xtrIdDao, expiredMappings);
125 if (mergedEntry == null) {
128 regdate = new Date(mergedEntry.getTimestamp());
129 table.put(eid, new MappingEntry<>(SubKeys.REGDATE, regdate));
130 table.put(eid, new MappingEntry<>(SubKeys.RECORD, mergedEntry));
131 table.put(eid, new MappingEntry<>(SubKeys.SRC_RLOCS, sourceRlocs));
133 table.put(eid, new MappingEntry<>(SubKeys.REGDATE, regdate));
134 table.put(eid, new MappingEntry<>(SubKeys.RECORD, value));
138 // Returns the list of mappings stored in an xTR-ID DAO
139 private List<Object> getXtrIdMappingList(ILispDAO dao) {
141 final List<Object> records = new ArrayList<Object>();
142 dao.getAll(new IRowVisitor() {
143 public void visitRow(Object keyId, String valueKey, Object value) {
144 if (valueKey.equals(SubKeys.RECORD)) {
154 private SimpleImmutableEntry<byte[], Long> getXtrIdMinTimeStamp(ILispDAO dao) {
156 // We don't actually need a list here, but the external variable we modify inside the IRowVisitor
157 // implementation has to be final. So we use a List, and it's methods, to modify contents
158 final List<SimpleImmutableEntry<byte[], Long>> entries =
159 new ArrayList<SimpleImmutableEntry<byte[], Long>>();
160 entries.set(0, new SimpleImmutableEntry<byte[], Long>(null, System.currentTimeMillis()));
162 dao.getAll(new IRowVisitor() {
163 public void visitRow(Object keyId, String valueKey, Object value) {
164 if (valueKey.equals(SubKeys.RECORD)) {
165 byte[] currentXtrId = ((MappingRecord) value).getXtrId();
166 long currentTimestamp = ((MappingRecord) value).getTimestamp();
167 // If one of the timestamps is expired, we signal it to the caller by setting the returned
168 // timestamp to null. The caller will then have to remove that xTR-ID, and do a full merge
170 if (MappingMergeUtil.timestampIsExpired(currentTimestamp)) {
171 SimpleImmutableEntry<byte[], Long> entry =
172 new SimpleImmutableEntry<byte[], Long>(currentXtrId, null);
173 entries.set(0, entry);
176 if (entries.get(0).getValue() > currentTimestamp) {
177 SimpleImmutableEntry<byte[], Long> entry =
178 new SimpleImmutableEntry<byte[], Long>(currentXtrId, currentTimestamp);
179 entries.set(0, entry);
184 return entries.get(0);
189 // Returns the mapping corresponding to the longest prefix match for eid. eid must be a simple (maskable or not)
191 private Object getMappingLpmEid(Eid eid, byte[] xtrId, ILispDAO dao) {
192 SimpleImmutableEntry<Eid, Map<String, ?>> daoEntry = dao.getBestPair(MaskUtil.normalize(eid));
193 if (daoEntry != null) {
195 ILispDAO xtrIdTable = getXtrIdTable(eid, (ILispDAO) daoEntry.getValue().get(SubKeys.XTRID_RECORDS));
196 if (xtrIdTable != null) {
197 MappingRecord xtrIdRecord = (MappingRecord) xtrIdTable.getSpecific(xtrId, SubKeys.RECORD);
198 if (xtrIdRecord.getTimestamp() != null &&
199 MappingMergeUtil.timestampIsExpired(xtrIdRecord.getTimestamp())) {
200 xtrIdTable.removeSpecific(xtrId, SubKeys.RECORD);
209 Date timestamp = (Date) daoEntry.getValue().get(SubKeys.REGDATE);
210 if (timestamp != null && MappingMergeUtil.timestampIsExpired(timestamp)) {
211 dao.removeSpecific(daoEntry.getKey(), SubKeys.REGDATE);
212 dao.removeSpecific(daoEntry.getKey(), SubKeys.RECORD);
214 return daoEntry.getValue().get(SubKeys.RECORD);
221 public Object getMapping(Eid srcEid, Eid dstEid, byte[] xtrId) {
222 if (dstEid == null) {
226 ILispDAO table = getVniTable(dstEid);
230 return getMappingLpmEid(dstEid, xtrId, table);
233 public Object getMapping(Eid srcEid, Eid dstEid) {
234 return getMapping(srcEid, dstEid, null);
237 public List<Object> getAllXtrIdMappings(Eid eid) {
238 Map<String, ?> daoEntry = dao.getBest(MaskUtil.normalize(eid));
239 if (daoEntry != null) {
240 ILispDAO xtrIdTable = getXtrIdTable(eid, (ILispDAO) daoEntry.get(SubKeys.XTRID_RECORDS));
241 if (xtrIdTable != null) {
242 return getXtrIdMappingList(xtrIdTable);
248 public Eid getWidestNegativeMapping(Eid key) {
249 return dao.getWidestNegativePrefix(MaskUtil.normalize(key));
252 public void removeMapping(Eid eid, boolean overwrite) {
253 Eid key = MaskUtil.normalize(eid);
254 ILispDAO table = getVniTable(key);
259 table.removeSpecific(key, SubKeys.RECORD);
262 ILispDAO xtrIdTable = getXtrIdTable(key, table);
263 if (xtrIdTable != null) {
264 xtrIdTable.removeSpecific(key, SubKeys.RECORD);
269 public void addAuthenticationKey(Eid eid, MappingAuthkey authKey) {
270 Eid key = MaskUtil.normalize(eid);
271 ILispDAO table = getOrInstantiateVniTable(key);
272 table.put(key, new MappingEntry<>(SubKeys.AUTH_KEY, authKey));
275 private MappingAuthkey getAuthKeyLpm(Eid prefix, ILispDAO db) {
276 short maskLength = MaskUtil.getMaskForAddress(prefix.getAddress());
277 while (maskLength >= 0) {
278 Eid key = MaskUtil.normalize(prefix, maskLength);
279 Object password = db.getSpecific(key, SubKeys.AUTH_KEY);
280 if (password != null && password instanceof MappingAuthkey) {
281 return (MappingAuthkey) password;
288 public MappingAuthkey getAuthenticationKey(Eid eid) {
289 ILispDAO table = getVniTable(eid);
293 if (MaskUtil.isMaskable(eid.getAddress()) && !(eid.getAddress() instanceof SourceDestKey)) {
294 return getAuthKeyLpm(eid, table);
296 Eid key = MaskUtil.normalize(eid);
297 Object password = table.getSpecific(key, SubKeys.AUTH_KEY);
298 if (password != null && password instanceof MappingAuthkey) {
299 return (MappingAuthkey) password;
301 LOG.warn("Failed to find password!");
307 public void removeAuthenticationKey(Eid eid) {
308 Eid key = MaskUtil.normalize(eid);
309 ILispDAO table = getVniTable(key);
313 table.removeSpecific(key, SubKeys.AUTH_KEY);
316 public String printMappings() {
317 final StringBuffer sb = new StringBuffer();
318 sb.append("Keys\tValues\n");
320 final IRowVisitor innerVisitor = (new IRowVisitor() {
323 public void visitRow(Object keyId, String valueKey, Object value) {
324 String key = keyId.getClass().getSimpleName() + "#" + keyId;
325 if (!lastKey.equals(key)) {
326 sb.append("\n" + key + "\t");
328 sb.append(valueKey + "=" + value + "\t");
333 dao.getAll(new IRowVisitor() {
336 public void visitRow(Object keyId, String valueKey, Object value) {
337 String key = keyId.getClass().getSimpleName() + "#" + keyId;
338 if (!lastKey.equals(key)) {
339 sb.append("\n" + key + "\t");
341 if (valueKey.equals(SubKeys.VNI)) {
342 sb.append(valueKey + "= { ");
343 ((ILispDAO)value).getAll(innerVisitor);
346 sb.append(valueKey + "=" + value + "\t");
352 return sb.toString();
356 public void updateMappingRegistration(Eid eid, Long timestamp) {
357 ILispDAO table = getVniTable(eid);
361 if (timestamp == null) {
362 timestamp = System.currentTimeMillis();
364 Map<String, Object> daoEntry = table.getBest(MaskUtil.normalize(eid));
365 if (daoEntry != null) {
366 daoEntry.put(SubKeys.REGDATE, new Date(timestamp));
371 public void addData(Eid eid, String subKey, Object data) {
372 Eid key = MaskUtil.normalize(eid);
373 ILispDAO table = getOrInstantiateVniTable(key);
374 table.put(key, new MappingEntry<>(subKey, data));
378 public Object getData(Eid eid, String subKey) {
379 ILispDAO table = getOrInstantiateVniTable(eid);
383 Eid key = MaskUtil.normalize(eid);
384 return table.getSpecific(key, subKey);
388 public void removeData(Eid eid, String subKey) {
389 ILispDAO table = getOrInstantiateVniTable(eid);
393 Eid key = MaskUtil.normalize(eid);
394 table.removeSpecific(key, subKey);