View Javadoc

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