Migrate implementation/neutron/southbound to IETF YANG model
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / 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
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     public void addMapping(Eid key, Object value, boolean shouldOverwrite) {
44         Eid eid = MaskUtil.normalize(key);
45         if (eid.getAddress() instanceof SourceDestKey) {
46             Eid srcKey = SourceDestKeyHelper.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));
50         } else {
51             dao.put(eid, new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
52             dao.put(eid, new MappingEntry<>(SubKeys.RECORD, value));
53         }
54     }
55
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(Eid eid, ILispDAO dao) {
59         if (MaskUtil.isMaskable(eid.getAddress())) {
60             Eid key;
61             short mask = MaskUtil.getMaskForAddress(eid.getAddress());
62             while (mask > 0) {
63                 key = MaskUtil.normalize(eid, mask);
64                 mask--;
65                 Map<String, ?> entry = dao.get(key);
66                 if (entry != null) {
67                     return entry;
68                 }
69             }
70             return null;
71         } else {
72             Map<String, ?> entry = dao.get(eid);
73             if (entry != null) {
74                 return dao.get(eid);
75             } else {
76                 return null;
77             }
78         }
79     }
80
81     private Object getMappingExactSD(Eid srcEid, Eid dstEid, ILispDAO dao) {
82         Map<String, ?> daoEntry = dao.get(dstEid);
83         if (daoEntry != null) {
84             // try SrcDst eid lookup
85             ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
86             if (srcEid != null && srcDstDao != null) {
87                 return srcDstDao.getSpecific(srcEid, SubKeys.RECORD);
88             }
89             // if lookup fails, return whatever is found for dst eid
90             return daoEntry.get(SubKeys.RECORD);
91         }
92         return null;
93     }
94
95     // Returns the mapping corresponding to the longest prefix match for eid. eid must be a simple (maskable or not) address
96     private Object getMappingLpmEid(Eid eid, ILispDAO dao) {
97         if (eid == null) {
98             return null;
99         }
100         Map<String, ?> daoEntry = getDaoEntryBest(eid, dao);
101         if (daoEntry != null) {
102             return daoEntry.get(SubKeys.RECORD);
103         } else {
104             return null;
105         }
106     }
107
108     // Returns a mapping corresponding to either the longest prefix match for both dstEid and srcEid,
109     // if a SourceDest mapping exists, or to dstEid
110     private Object getMappingLpmSD(Eid srcEid, Eid dstEid, ILispDAO dao) {
111         Map<String, ?> daoEntry = getDaoEntryBest(dstEid, dao);
112         if (daoEntry != null) {
113             // try SrcDst eid lookup
114             ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
115             if (srcDstDao != null) {
116                 Object mapping = getMappingLpmEid(srcEid, srcDstDao);
117                 if (mapping!= null) {
118                     return mapping;
119                 }
120             }
121
122             // if lookup fails, return whatever is found for dst eid
123             return daoEntry.get(SubKeys.RECORD);
124         }
125         return null;
126     }
127
128     public Object getMapping(Eid srcEid, Eid dstEid) {
129         if (dstEid == null) {
130             return null;
131         }
132
133         // a map-request for an actual SrcDst LCAF, ignore src eid
134         if (dstEid.getAddress() instanceof SourceDestKey) {
135             Eid srcAddr = SourceDestKeyHelper.getSrc(dstEid);
136             Eid dstAddr = SourceDestKeyHelper.getDst(dstEid);
137             return getMappingLpmSD(srcAddr, dstAddr, dao);
138         }
139
140         // potential map-request for SrcDst LCAF from non SrcDst capable devices
141         return getMappingLpmSD(srcEid, dstEid, dao);
142     }
143
144     public void removeMapping(Eid eid, boolean overwrite) {
145         eid = MaskUtil.normalize(eid);
146         if (eid.getAddress() instanceof SourceDestKey) {
147             ILispDAO db = getSDInnerDao(eid, dao);
148             if (db != null) {
149                 db.removeSpecific(SourceDestKeyHelper.getSrc(eid),
150                         SubKeys.RECORD);
151             }
152         } else {
153             dao.removeSpecific(eid, SubKeys.RECORD);
154         }
155     }
156
157     public void addAuthenticationKey(Eid eid, MappingAuthkey key) {
158         eid = MaskUtil.normalize(eid);
159         if (eid.getAddress() instanceof SourceDestKey) {
160             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, dao);
161             srcDstDao.put(SourceDestKeyHelper.getSrc(eid), new MappingEntry<>(SubKeys.AUTH_KEY, key));
162         } else {
163             dao.put(eid, new MappingEntry<>(SubKeys.AUTH_KEY, key));
164         }
165     }
166
167     private MappingAuthkey getAuthKeyLpm(Eid prefix, ILispDAO db) {
168         short maskLength = MaskUtil.getMaskForAddress(prefix.getAddress());
169         while (maskLength >= 0) {
170             Eid key = MaskUtil.normalize(prefix, maskLength);
171             Object password = db.getSpecific(key, SubKeys.AUTH_KEY);
172             if (password != null && password instanceof MappingAuthkey) {
173                 return (MappingAuthkey) password;
174             }
175             maskLength -= 1;
176         }
177         return null;
178     }
179
180     public MappingAuthkey getAuthenticationKey(Eid eid) {
181         if (MaskUtil.isMaskable(eid.getAddress())) {
182             return getAuthKeyLpm(eid, dao);
183         } else if (eid.getAddress() instanceof SourceDestKey) {
184             // NOTE: this is an exact match, not a longest prefix match
185             ILispDAO srcDstDao = getSDInnerDao(eid, dao);
186             if (srcDstDao != null) {
187                 return getAuthKeyLpm(SourceDestKeyHelper.getSrc(eid), srcDstDao);
188             }
189             return null;
190         } else {
191             Object password = dao.getSpecific(eid, SubKeys.AUTH_KEY);
192             if (password != null && password instanceof MappingAuthkey) {
193                 return (MappingAuthkey) password;
194             } else {
195                 LOG.warn("Failed to find password!");
196                 return null;
197             }
198         }
199     }
200
201     public void removeAuthenticationKey(Eid eid) {
202         eid = MaskUtil.normalize(eid);
203         if (eid.getAddress() instanceof SourceDestKey) {
204             ILispDAO srcDstDao = getSDInnerDao(eid, dao);
205             if (srcDstDao != null) {
206                 srcDstDao.removeSpecific(eid, SubKeys.AUTH_KEY);
207             }
208         } else {
209             dao.removeSpecific(eid, SubKeys.AUTH_KEY);
210         }
211     }
212
213     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
214     // This method returns the DAO associated to a dst or creates it if it doesn't exist.
215     private ILispDAO getOrInstantiateSDInnerDao(Eid address, ILispDAO dao) {
216         Eid dstKey = SourceDestKeyHelper.getDst(address);
217         ILispDAO srcDstDao = (ILispDAO) dao.getSpecific(dstKey, SubKeys.LCAF_SRCDST);
218         if (srcDstDao == null) {
219             // inserts nested table for source
220             srcDstDao = dao.putNestedTable(dstKey, SubKeys.LCAF_SRCDST);
221         }
222         return srcDstDao;
223     }
224
225     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
226     // This method returns the DAO associated to dst or null if it doesn't exist.
227     private ILispDAO getSDInnerDao(Eid address, ILispDAO dao) {
228         return (ILispDAO) dao.getSpecific(SourceDestKeyHelper.getDst(address), SubKeys.LCAF_SRCDST);
229     }
230
231     public String printMappings() {
232         final StringBuffer sb = new StringBuffer();
233         sb.append("Keys\tValues\n");
234         final IRowVisitor innerVisitor = (new IRowVisitor() {
235             String lastKey = "";
236
237             public void visitRow(Object keyId, String valueKey, Object value) {
238                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
239                 if (!lastKey.equals(key)) {
240                     sb.append(key + "\t");
241                 }
242                 if (!(valueKey.equals(SubKeys.LCAF_SRCDST))) {
243                     sb.append(valueKey + "=" + value + "\t");
244                 }
245                 lastKey = key;
246             }
247         });
248         dao.getAll(new IRowVisitor() {
249             String lastKey = "";
250
251             public void visitRow(Object keyId, String valueKey, Object value) {
252                 String key = keyId.getClass().getSimpleName() + "#" + keyId;
253                 if (!lastKey.equals(key)) {
254                     sb.append("\n" + key + "\t");
255                 }
256                 if (valueKey.equals(SubKeys.LCAF_SRCDST)) {
257                     sb.append(valueKey + "= { ");
258                     ((ILispDAO)value).getAll(innerVisitor);
259                     sb.append("}\t");
260                 } else {
261                     sb.append(valueKey + "=" + value + "\t");
262                 }
263                 lastKey = key;
264             }
265         });
266         sb.append("\n");
267         return sb.toString();
268     }
269
270     @Override
271     public void updateMappingRegistration(Eid key) {
272
273     }
274
275     @Override
276     public void addData(Eid key, String subKey, Object data) {
277         key = MaskUtil.normalize(key);
278         if (key.getAddress() instanceof SourceDestKey) {
279             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(key, dao);
280             srcDstDao.put(SourceDestKeyHelper.getSrc(key), new MappingEntry<Object>(subKey, data));
281         } else {
282             dao.put(key, new MappingEntry<Object>(subKey, data));
283         }
284     }
285
286     @Override
287     public Object getData(Eid eid, String subKey) {
288         if (eid.getAddress() instanceof SourceDestKey) {
289             ILispDAO srcDstDao = getSDInnerDao(eid, dao);
290             return srcDstDao.getSpecific(SourceDestKeyHelper.getSrc(eid), subKey);
291         } else {
292             return dao.getSpecific(eid, subKey);
293         }
294     }
295
296     @Override
297     public void removeData(Eid key, String subKey) {
298         key = MaskUtil.normalize(key);
299         if (key.getAddress() instanceof SourceDestKey) {
300             ILispDAO db = getSDInnerDao(key, dao);
301             if (db != null) {
302                 db.removeSpecific(SourceDestKeyHelper.getSrc(key), subKey);
303             }
304         } else {
305             dao.removeSpecific(key, subKey);
306         }
307     }
308 }