e2489deccda190f70a91ce91be36df795b250fe9
[lispflowmapping.git] / mappingservice / mapcache / src / main / java / org / opendaylight / lispflowmapping / mapcache / MultiTableMapCache.java
1 /*
2  * Copyright (c) 2014 Contextream, 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 package org.opendaylight.lispflowmapping.mapcache;
9
10 import java.util.Date;
11 import java.util.Map;
12 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
13 import org.opendaylight.lispflowmapping.interfaces.dao.IRowVisitor;
14 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
15 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
16 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMapCache;
17 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
18 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
19 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.authkey.container.MappingAuthkey;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * Multi table map-cache that works with 'simple' and SourceDest LCAF addresses (see lisp-proto.yang). It can do longest
28  * prefix matching for IP and SourceDest LCAF addresses. In case of the latter, it uses two tables, one for dst and
29  * another for source, queried and populated in this exact order.
30  *
31  * @author Florin Coras
32  */
33 public class MultiTableMapCache implements IMapCache {
34     private static final Logger LOG = LoggerFactory.getLogger(MultiTableMapCache.class);
35
36     private ILispDAO dao;
37
38     public MultiTableMapCache(ILispDAO dao) {
39         this.dao = dao;
40     }
41
42     private ILispDAO getVniTable(Eid eid) {
43         long vni = 0;
44         if (eid.getVirtualNetworkId() == null) {
45             vni = 0;
46         } else {
47             vni = eid.getVirtualNetworkId().getValue();
48         }
49         return (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
50     }
51
52     private ILispDAO getOrInstantiateVniTable(Eid eid) {
53         long vni = 0;
54         if (eid.getVirtualNetworkId() == null) {
55             vni = 0;
56         } else {
57             vni = eid.getVirtualNetworkId().getValue();
58         }
59         ILispDAO table = (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
60         if (table == null) {
61             table = dao.putNestedTable(vni, SubKeys.VNI);
62         }
63         return table;
64     }
65
66     public void addMapping(Eid key, Object value, boolean shouldOverwrite, boolean shouldMerge) {
67         Eid eid = MaskUtil.normalize(key);
68         ILispDAO table = getOrInstantiateVniTable(key);
69
70         if (eid.getAddress() instanceof SourceDestKey) {
71             Eid srcKey = SourceDestKeyHelper.getSrcBinary(eid);
72             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, table);
73             srcDstDao.put(srcKey, new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
74             srcDstDao.put(srcKey, new MappingEntry<>(SubKeys.RECORD, value));
75         } else {
76             table.put(eid, new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
77             table.put(eid, new MappingEntry<>(SubKeys.RECORD, value));
78         }
79     }
80
81     // Returns the mapping corresponding to the longest prefix match for eid.
82     // eid must be a simple (maskable or not) address
83     private Object getMappingLpmEid(Eid eid, ILispDAO mappingsDb) {
84         if (eid == null) {
85             return null;
86         }
87         Map<String, ?> daoEntry = mappingsDb.getBest(MaskUtil.normalize(eid));
88         if (daoEntry != null) {
89             return daoEntry.get(SubKeys.RECORD);
90         } else {
91             return null;
92         }
93     }
94
95     // Returns a mapping corresponding to either the longest prefix match for both dstEid and srcEid,
96     // if a SourceDest mapping exists, or to dstEid
97     private Object getMappingLpmSD(Eid srcEid, Eid dstEid, ILispDAO mappingsDb) {
98         Map<String, ?> daoEntry = mappingsDb.getBest(MaskUtil.normalize(dstEid));
99         if (daoEntry != null) {
100             // try SrcDst eid lookup
101             ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
102             if (srcEid != null && srcDstDao != null) {
103                 // make sure that srcEid is a prefix, not an IP and binary
104                 Object mapping = getMappingLpmEid(LispAddressUtil.asIpPrefixBinaryEid(srcEid), srcDstDao);
105                 if (mapping !=  null) {
106                     return mapping;
107                 }
108             }
109
110             // if lookup fails, return whatever is found for dst eid
111             return daoEntry.get(SubKeys.RECORD);
112         }
113         return null;
114     }
115
116     public Object getMapping(Eid srcEid, Eid dstEid) {
117         if (dstEid == null) {
118             return null;
119         }
120
121         ILispDAO table = getVniTable(dstEid);
122         if (table == null) {
123             return null;
124         }
125
126         // a map-request for an actual SrcDst LCAF, ignore src eid
127         if (dstEid.getAddress() instanceof SourceDestKey) {
128             Eid srcAddr = SourceDestKeyHelper.getSrcBinary(dstEid);
129             Eid dstAddr = SourceDestKeyHelper.getDstBinary(dstEid);
130             return getMappingLpmSD(srcAddr, dstAddr, table);
131         }
132
133         // potential map-request for SrcDst LCAF from non SrcDst capable devices
134         return getMappingLpmSD(srcEid, dstEid, table);
135     }
136
137     @Override
138     public Object getMapping(Eid srcEid, Eid dstEid, byte[] xtrId) {
139         return null;
140     }
141
142     @Override
143     public Eid getWidestNegativeMapping(Eid key) {
144         ILispDAO table = getVniTable(key);
145         if (table == null) {
146             return null;
147         }
148         return table.getWidestNegativePrefix(key);
149     }
150
151     public void removeMapping(Eid eid, boolean overwrite) {
152         Eid key = MaskUtil.normalize(eid);
153         ILispDAO table = getVniTable(key);
154         if (table == null) {
155             return;
156         }
157
158         if (key.getAddress() instanceof SourceDestKey) {
159             ILispDAO db = getSDInnerDao(key, table);
160             if (db != null) {
161                 db.removeSpecific(SourceDestKeyHelper.getSrcBinary(key),
162                         SubKeys.RECORD);
163                 db.removeSpecific(SourceDestKeyHelper.getSrcBinary(key),
164                         SubKeys.REGDATE);
165             }
166         } else {
167             table.removeSpecific(key, SubKeys.RECORD);
168             table.removeSpecific(key, SubKeys.REGDATE);
169         }
170     }
171
172     public void addAuthenticationKey(Eid eid, MappingAuthkey authKey) {
173         Eid key = MaskUtil.normalize(eid);
174         ILispDAO table = getOrInstantiateVniTable(key);
175
176         if (key.getAddress() instanceof SourceDestKey) {
177             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(key, table);
178             srcDstDao.put(SourceDestKeyHelper.getSrcBinary(key), new MappingEntry<>(SubKeys.AUTH_KEY, authKey));
179         } else {
180             table.put(key, new MappingEntry<>(SubKeys.AUTH_KEY, authKey));
181         }
182     }
183
184     private MappingAuthkey getAuthKeyLpm(Eid prefix, ILispDAO db) {
185         short maskLength = MaskUtil.getMaskForAddress(prefix.getAddress());
186         while (maskLength >= 0) {
187             Eid key = MaskUtil.normalize(prefix, maskLength);
188             Object password = db.getSpecific(key, SubKeys.AUTH_KEY);
189             if (password != null && password instanceof MappingAuthkey) {
190                 return (MappingAuthkey) password;
191             }
192             maskLength -= 1;
193         }
194         return null;
195     }
196
197     public MappingAuthkey getAuthenticationKey(Eid eid) {
198         ILispDAO table = getVniTable(eid);
199         if (table == null) {
200             return null;
201         }
202
203         if (MaskUtil.isMaskable(eid.getAddress())) {
204             if (eid.getAddress() instanceof SourceDestKey) {
205                 // NOTE: this is an exact match, not a longest prefix match
206                 ILispDAO srcDstDao = getSDInnerDao(eid, table);
207                 if (srcDstDao != null) {
208                     return getAuthKeyLpm(SourceDestKeyHelper.getSrcBinary(eid), srcDstDao);
209                 }
210                 return null;
211             } else {
212                 return getAuthKeyLpm(eid, table);
213             }
214         } else {
215             Eid key = MaskUtil.normalize(eid);
216             Object password = table.getSpecific(key, SubKeys.AUTH_KEY);
217             if (password != null && password instanceof MappingAuthkey) {
218                 return (MappingAuthkey) password;
219             } else {
220                 LOG.warn("Failed to find password!");
221                 return null;
222             }
223         }
224     }
225
226     public void removeAuthenticationKey(Eid eid) {
227         Eid key = MaskUtil.normalize(eid);
228         ILispDAO table = getVniTable(key);
229         if (table == null) {
230             return;
231         }
232
233         if (key.getAddress() instanceof SourceDestKey) {
234             ILispDAO srcDstDao = getSDInnerDao(key, table);
235             if (srcDstDao != null) {
236                 srcDstDao.removeSpecific(key, SubKeys.AUTH_KEY);
237             }
238         } else {
239             table.removeSpecific(key, SubKeys.AUTH_KEY);
240         }
241     }
242
243     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
244     // This method returns the DAO associated to a dst or creates it if it doesn't exist.
245     private ILispDAO getOrInstantiateSDInnerDao(Eid address, ILispDAO mappingsDb) {
246         Eid dstKey = SourceDestKeyHelper.getDstBinary(address);
247         ILispDAO srcDstDao = (ILispDAO) mappingsDb.getSpecific(dstKey, SubKeys.LCAF_SRCDST);
248         if (srcDstDao == null) {
249             // inserts nested table for source
250             srcDstDao = mappingsDb.putNestedTable(dstKey, SubKeys.LCAF_SRCDST);
251         }
252         return srcDstDao;
253     }
254
255     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
256     // This method returns the DAO associated to dst or null if it doesn't exist.
257     private ILispDAO getSDInnerDao(Eid address, ILispDAO mappingsDb) {
258         return (ILispDAO) mappingsDb.getSpecific(SourceDestKeyHelper.getDstBinary(address), SubKeys.LCAF_SRCDST);
259     }
260
261     public String printMappings() {
262         final StringBuffer sb = new StringBuffer();
263         sb.append("Keys\tValues\n");
264         final IRowVisitor innerVisitor = (new IRowVisitor() {
265             String lastKey = "";
266
267             public void visitRow(Object keyId, String valueKey, Object value) {
268                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
269                 if (!lastKey.equals(key)) {
270                     sb.append("\n" + key + "\t");
271                 }
272                 sb.append(valueKey + "=" + value + "\t");
273                 lastKey = key;
274             }
275         });
276         final IRowVisitor vniVisitor = (new IRowVisitor() {
277             String lastKey = "";
278
279             public void visitRow(Object keyId, String valueKey, Object value) {
280                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
281                 if (!lastKey.equals(key)) {
282                     sb.append(key + "\t");
283                 }
284                 if ((valueKey.equals(SubKeys.LCAF_SRCDST))) {
285                     sb.append(valueKey + "= { ");
286                     ((ILispDAO)value).getAll(innerVisitor);
287                     sb.append("}\t");
288                 } else {
289                     sb.append(valueKey + "=" + value + "\t");
290                 }
291                 lastKey = key;
292             }
293         });
294         dao.getAll(new IRowVisitor() {
295             String lastKey = "";
296
297             public void visitRow(Object keyId, String valueKey, Object value) {
298                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
299                 if (!lastKey.equals(key)) {
300                     sb.append("\n" + key + "\t");
301                 }
302                 if (valueKey.equals(SubKeys.VNI)) {
303                     sb.append(valueKey + "= { ");
304                     ((ILispDAO)value).getAll(vniVisitor);
305                     sb.append("}\t");
306                 } else {
307                     sb.append(valueKey + "=" + value + "\t");
308                 }
309                 lastKey = key;
310             }
311         });
312         sb.append("\n");
313         return sb.toString();
314     }
315
316     @Override
317     public void updateMappingRegistration(Eid key, Long timestamp) {
318
319     }
320
321     @Override
322     public void addData(Eid eid, String subKey, Object data) {
323         Eid key = MaskUtil.normalize(eid);
324         ILispDAO table = getOrInstantiateVniTable(key);
325
326         if (key.getAddress() instanceof SourceDestKey) {
327             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(key, table);
328             srcDstDao.put(SourceDestKeyHelper.getSrcBinary(key), new MappingEntry<>(subKey, data));
329         } else {
330             table.put(key, new MappingEntry<>(subKey, data));
331         }
332     }
333
334     @Override
335     public Object getData(Eid eid, String subKey) {
336         Eid key = MaskUtil.normalize(eid);
337         ILispDAO table = getVniTable(key);
338         if (table == null) {
339             return null;
340         }
341
342         if (key.getAddress() instanceof SourceDestKey) {
343             ILispDAO srcDstDao = getSDInnerDao(key, table);
344             return srcDstDao.getSpecific(SourceDestKeyHelper.getSrcBinary(key), subKey);
345         } else {
346             return table.getSpecific(key, subKey);
347         }
348     }
349
350     @Override
351     public void removeData(Eid eid, String subKey) {
352         Eid key = MaskUtil.normalize(eid);
353         ILispDAO table = getVniTable(key);
354         if (table == null) {
355             return;
356         }
357         if (key.getAddress() instanceof SourceDestKey) {
358             ILispDAO db = getSDInnerDao(key, table);
359             if (db != null) {
360                 db.removeSpecific(SourceDestKeyHelper.getSrcBinary(key), subKey);
361             }
362         } else {
363             table.removeSpecific(key, subKey);
364         }
365     }
366 }