Merge "Bug 6422: get VNI table in MapCache"
[lispflowmapping.git] / mappingservice / mapcache / src / main / java / org / opendaylight / lispflowmapping / mapcache / SimpleMapCache.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.lispflowmapping.mapcache;
10
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;
16 import java.util.Map;
17 import java.util.Set;
18 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
19 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
20 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
21 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
22 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMapCache;
23 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.IpAddressBinary;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.authkey.container.MappingAuthkey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * Simple map-cache that works with 'simple' addresses (see lisp-proto.yang). It can do longest prefix matching for IP
35  * addresses.
36  *
37  * @author Florin Coras
38  * @author Lorand Jakab
39  *
40  */
41 public class SimpleMapCache implements IMapCache {
42     private static final Logger LOG = LoggerFactory.getLogger(SimpleMapCache.class);
43     private ILispDAO dao;
44
45     public SimpleMapCache(ILispDAO dao) {
46         this.dao = dao;
47     }
48
49     private ILispDAO getVniTable(Eid eid) {
50         long vni = 0;
51         if (eid.getVirtualNetworkId() == null) {
52             vni = 0;
53         } else {
54             vni = eid.getVirtualNetworkId().getValue();
55         }
56         return (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
57     }
58
59     private ILispDAO getOrInstantiateVniTable(Eid eid) {
60         long vni = 0;
61         if (eid.getVirtualNetworkId() == null) {
62             vni = 0;
63         } else {
64             vni = eid.getVirtualNetworkId().getValue();
65         }
66         ILispDAO table = (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
67         if (table == null) {
68             table = dao.putNestedTable(vni, SubKeys.VNI);
69         }
70         return table;
71     }
72
73     private ILispDAO getXtrIdTable(Eid eid, ILispDAO dao) {
74         return (ILispDAO) dao.getSpecific(eid, SubKeys.XTRID_RECORDS);
75     }
76
77     private ILispDAO getOrInstantiateXtrIdTable(Eid eid, ILispDAO dao) {
78         ILispDAO table = (ILispDAO) dao.getSpecific(eid, SubKeys.XTRID_RECORDS);
79         if (table == null) {
80             table = dao.putNestedTable(eid, SubKeys.XTRID_RECORDS);
81         }
82         return table;
83     }
84
85     private void removeExpiredXtrIdTableEntries(ILispDAO xtrIdDao, List<XtrId> expiredMappings) {
86         for (XtrId xtrId : expiredMappings) {
87             xtrIdDao.removeSpecific(xtrId, SubKeys.RECORD);
88         }
89     }
90
91     public void addMapping(Eid key, Object value, boolean shouldOverwrite, boolean shouldMerge) {
92         if (value == null) {
93             LOG.warn("addMapping() called with null 'value', ignoring");
94             return;
95         }
96
97         if (!(value instanceof MappingRecord)) {
98             LOG.warn("addMapping() called with a 'value' that is not a 'MappingRecord', ignoring");
99             return;
100         }
101
102         MappingRecord record = (MappingRecord) value;
103         if (record.getXtrId() == null && !shouldOverwrite && shouldMerge) {
104             LOG.warn("addMapping() called will null xTR-ID in MappingRecord, while merge is set, ignoring");
105             return;
106         }
107
108         Date regdate = new Date(record.getTimestamp());     // The serializer always sets it
109         Eid eid = MaskUtil.normalize(key);
110         ILispDAO table = getOrInstantiateVniTable(key);
111
112         ILispDAO xtrIdDao = null;
113         if (!shouldOverwrite && record.getXtrId() != null) {
114             xtrIdDao = getOrInstantiateXtrIdTable(eid, table);
115             xtrIdDao.put(record.getXtrId(), new MappingEntry<>(SubKeys.RECORD, value));
116         }
117
118         if (shouldMerge) {
119             List<XtrId> expiredMappings = new ArrayList<>();
120             Set<IpAddressBinary> sourceRlocs = new HashSet<>();
121             MappingRecord mergedEntry = MappingMergeUtil.mergeXtrIdMappings(getXtrIdMappingList(xtrIdDao),
122                     expiredMappings, sourceRlocs);
123             removeExpiredXtrIdTableEntries(xtrIdDao, expiredMappings);
124             if (mergedEntry == null) {
125                 return;
126             }
127             regdate = new Date(mergedEntry.getTimestamp());
128             table.put(eid, new MappingEntry<>(SubKeys.REGDATE, regdate));
129             table.put(eid, new MappingEntry<>(SubKeys.RECORD, mergedEntry));
130             table.put(eid, new MappingEntry<>(SubKeys.SRC_RLOCS, sourceRlocs));
131         } else {
132             table.put(eid, new MappingEntry<>(SubKeys.REGDATE, regdate));
133             table.put(eid, new MappingEntry<>(SubKeys.RECORD, value));
134         }
135     }
136
137     // Returns the list of mappings stored in an xTR-ID DAO
138     private List<Object> getXtrIdMappingList(ILispDAO dao) {
139         if (dao != null) {
140             final List<Object> records = new ArrayList<>();
141             dao.getAll(new IRowVisitor() {
142                 public void visitRow(Object keyId, String valueKey, Object value) {
143                     if (valueKey.equals(SubKeys.RECORD)) {
144                         records.add(value);
145                     }
146                 }
147             });
148             return records;
149         }
150         return null;
151     }
152
153     // Returns the mapping corresponding to the longest prefix match for eid. eid must be a simple (maskable or not)
154     // address
155     private Object getMappingLpmEid(Eid eid, byte[] xtrId, ILispDAO dao) {
156         SimpleImmutableEntry<Eid, Map<String, ?>> daoEntry = dao.getBestPair(MaskUtil.normalize(eid));
157         if (daoEntry != null) {
158             if (xtrId != null) {
159                 ILispDAO xtrIdTable = getXtrIdTable(eid, (ILispDAO) daoEntry.getValue().get(SubKeys.XTRID_RECORDS));
160                 if (xtrIdTable != null) {
161                     MappingRecord xtrIdRecord = (MappingRecord) xtrIdTable.getSpecific(xtrId, SubKeys.RECORD);
162                     if (xtrIdRecord.getTimestamp() != null
163                             && MappingMergeUtil.timestampIsExpired(xtrIdRecord.getTimestamp())) {
164                         xtrIdTable.removeSpecific(xtrId, SubKeys.RECORD);
165                         return null;
166                     } else {
167                         return xtrIdRecord;
168                     }
169                 } else {
170                     return null;
171                 }
172             } else {
173                 Date timestamp = (Date) daoEntry.getValue().get(SubKeys.REGDATE);
174                 if (timestamp != null && MappingMergeUtil.timestampIsExpired(timestamp)) {
175                     dao.removeSpecific(daoEntry.getKey(), SubKeys.REGDATE);
176                     dao.removeSpecific(daoEntry.getKey(), SubKeys.RECORD);
177                 }
178                 return daoEntry.getValue().get(SubKeys.RECORD);
179             }
180         } else {
181             return null;
182         }
183     }
184
185     public Object getMapping(Eid srcEid, Eid dstEid, byte[] xtrId) {
186         if (dstEid == null) {
187             return null;
188         }
189
190         ILispDAO table = getVniTable(dstEid);
191         if (table == null) {
192             return null;
193         }
194         return getMappingLpmEid(dstEid, xtrId, table);
195     }
196
197     public Object getMapping(Eid srcEid, Eid dstEid) {
198         return getMapping(srcEid, dstEid, null);
199     }
200
201     public List<Object> getAllXtrIdMappings(Eid eid) {
202         Map<String, ?> daoEntry = dao.getBest(MaskUtil.normalize(eid));
203         if (daoEntry != null) {
204             ILispDAO xtrIdTable = getXtrIdTable(eid, (ILispDAO) daoEntry.get(SubKeys.XTRID_RECORDS));
205             if (xtrIdTable != null) {
206                 return getXtrIdMappingList(xtrIdTable);
207             }
208         }
209         return null;
210     }
211
212     public Eid getWidestNegativeMapping(Eid key) {
213         ILispDAO table = getVniTable(key);
214         if (table == null) {
215             return null;
216         }
217         return table.getWidestNegativePrefix(MaskUtil.normalize(key));
218     }
219
220     public void removeMapping(Eid eid, boolean overwrite) {
221         Eid key = MaskUtil.normalize(eid);
222         ILispDAO table = getVniTable(key);
223         if (table == null) {
224             return;
225         }
226
227         table.removeSpecific(key, SubKeys.RECORD);
228
229         if (!overwrite) {
230             ILispDAO xtrIdTable = getXtrIdTable(key, table);
231             if (xtrIdTable != null) {
232                 xtrIdTable.removeSpecific(key, SubKeys.RECORD);
233             }
234         }
235     }
236
237     public void addAuthenticationKey(Eid eid, MappingAuthkey authKey) {
238         Eid key = MaskUtil.normalize(eid);
239         ILispDAO table = getOrInstantiateVniTable(key);
240         table.put(key, new MappingEntry<>(SubKeys.AUTH_KEY, authKey));
241     }
242
243     private MappingAuthkey getAuthKeyLpm(Eid prefix, ILispDAO db) {
244         short maskLength = MaskUtil.getMaskForAddress(prefix.getAddress());
245         while (maskLength >= 0) {
246             Eid key = MaskUtil.normalize(prefix, maskLength);
247             Object password = db.getSpecific(key, SubKeys.AUTH_KEY);
248             if (password != null && password instanceof MappingAuthkey) {
249                 return (MappingAuthkey) password;
250             }
251             maskLength -= 1;
252         }
253         return null;
254     }
255
256     public MappingAuthkey getAuthenticationKey(Eid eid) {
257         ILispDAO table = getVniTable(eid);
258         if (table == null) {
259             return null;
260         }
261         if (MaskUtil.isMaskable(eid.getAddress()) && !(eid.getAddress() instanceof SourceDestKey)) {
262             return getAuthKeyLpm(eid, table);
263         } else {
264             Eid key = MaskUtil.normalize(eid);
265             Object password = table.getSpecific(key, SubKeys.AUTH_KEY);
266             if (password != null && password instanceof MappingAuthkey) {
267                 return (MappingAuthkey) password;
268             } else {
269                 LOG.warn("Failed to find password!");
270                 return null;
271             }
272         }
273     }
274
275     public void removeAuthenticationKey(Eid eid) {
276         Eid key = MaskUtil.normalize(eid);
277         ILispDAO table = getVniTable(key);
278         if (table == null) {
279             return;
280         }
281         table.removeSpecific(key, SubKeys.AUTH_KEY);
282     }
283
284     public String printMappings() {
285         final StringBuffer sb = new StringBuffer();
286         sb.append("Keys\tValues\n");
287
288         final IRowVisitor innerVisitor = (new IRowVisitor() {
289             String lastKey = "";
290
291             public void visitRow(Object keyId, String valueKey, Object value) {
292                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
293                 if (!lastKey.equals(key)) {
294                     sb.append("\n" + key + "\t");
295                 }
296                 sb.append(valueKey + "=" + value + "\t");
297                 lastKey = key;
298             }
299         });
300
301         dao.getAll(new IRowVisitor() {
302             String lastKey = "";
303
304             public void visitRow(Object keyId, String valueKey, Object value) {
305                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
306                 if (!lastKey.equals(key)) {
307                     sb.append("\n" + key + "\t");
308                 }
309                 if (valueKey.equals(SubKeys.VNI)) {
310                     sb.append(valueKey + "= { ");
311                     ((ILispDAO)value).getAll(innerVisitor);
312                     sb.append("}\t");
313                 } else {
314                     sb.append(valueKey + "=" + value + "\t");
315                 }
316                 lastKey = key;
317             }
318         });
319         sb.append("\n");
320         return sb.toString();
321     }
322
323     @Override
324     public void updateMappingRegistration(Eid eid, Long timestamp) {
325         ILispDAO table = getVniTable(eid);
326         if (table == null) {
327             return;
328         }
329         if (timestamp == null) {
330             timestamp = System.currentTimeMillis();
331         }
332         Map<String, Object> daoEntry = table.getBest(MaskUtil.normalize(eid));
333         if (daoEntry != null) {
334             daoEntry.put(SubKeys.REGDATE, new Date(timestamp));
335         }
336     }
337
338     @Override
339     public void addData(Eid eid, String subKey, Object data) {
340         Eid key = MaskUtil.normalize(eid);
341         ILispDAO table = getOrInstantiateVniTable(key);
342         table.put(key, new MappingEntry<>(subKey, data));
343     }
344
345     @Override
346     public Object getData(Eid eid, String subKey) {
347         ILispDAO table = getOrInstantiateVniTable(eid);
348         if (table == null) {
349             return null;
350         }
351         Eid key = MaskUtil.normalize(eid);
352         return table.getSpecific(key, subKey);
353     }
354
355     @Override
356     public void removeData(Eid eid, String subKey) {
357         ILispDAO table = getOrInstantiateVniTable(eid);
358         if (table == null) {
359             return;
360         }
361         Eid key = MaskUtil.normalize(eid);
362         table.removeSpecific(key, subKey);
363     }
364 }