6f62f72163906e9a6bde1ce4bad38a882283b3ee
[lispflowmapping.git] / mappingservice / mapcache / src / main / java / org / opendaylight / lispflowmapping / mapcache / MultiTableMapCache.java
1 /*
2  * Copyright (c) 2014, 2016 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.Collections;
11 import java.util.Map;
12 import java.util.Set;
13 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
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.lispflowmapping.mapcache.lisp.LispMapCacheStringifier;
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
24 /**
25  * Multi table map-cache that works with 'simple' and SourceDest LCAF addresses (see lisp-proto.yang). It can do longest
26  * prefix matching for IP and SourceDest LCAF addresses. In case of the latter, it uses two tables, one for dst and
27  * another for source, queried and populated in this exact order.
28  *
29  * @author Florin Coras
30  */
31 public class MultiTableMapCache implements IMapCache {
32     private ILispDAO dao;
33
34     public MultiTableMapCache(ILispDAO dao) {
35         this.dao = dao;
36     }
37
38     private long getVni(Eid eid) {
39         if (eid.getVirtualNetworkId() == null) {
40             return 0;
41         } else {
42             return eid.getVirtualNetworkId().getValue();
43         }
44     }
45
46     private ILispDAO getVniTable(Eid eid) {
47         return (ILispDAO) dao.getSpecific(getVni(eid), SubKeys.VNI);
48     }
49
50     private void removeVniTable(Eid eid) {
51         dao.removeSpecific(getVni(eid), SubKeys.VNI);
52     }
53
54     private ILispDAO getOrInstantiateVniTable(Eid eid) {
55         long vni = getVni(eid);
56         ILispDAO table = (ILispDAO) dao.getSpecific(vni, SubKeys.VNI);
57         if (table == null) {
58             table = dao.putNestedTable(vni, SubKeys.VNI);
59         }
60         return table;
61     }
62
63     public void addMapping(Eid key, Object value) {
64         Eid eid = MaskUtil.normalize(key);
65         ILispDAO table = getOrInstantiateVniTable(key);
66
67         if (eid.getAddress() instanceof SourceDestKey) {
68             Eid srcKey = SourceDestKeyHelper.getSrcBinary(eid);
69             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, table);
70             srcDstDao.put(srcKey, new MappingEntry<>(SubKeys.RECORD, value));
71         } else {
72             table.put(eid, new MappingEntry<>(SubKeys.RECORD, value));
73         }
74     }
75
76     // Returns the mapping corresponding to the longest prefix match for eid.
77     // eid must be a simple (maskable or not) address
78     private Object getMappingLpmEid(Eid eid, ILispDAO mappingsDb) {
79         if (eid == null) {
80             return null;
81         }
82         Map<String, ?> daoEntry = mappingsDb.getBest(MaskUtil.normalize(eid));
83         if (daoEntry != null) {
84             return daoEntry.get(SubKeys.RECORD);
85         } else {
86             return null;
87         }
88     }
89
90     // Returns a mapping corresponding to either the longest prefix match for both dstEid and srcEid,
91     // if a SourceDest mapping exists, or to dstEid
92     private Object getMappingLpmSD(Eid srcEid, Eid dstEid, ILispDAO mappingsDb) {
93         Map<String, ?> daoEntry = mappingsDb.getBest(MaskUtil.normalize(dstEid));
94         if (daoEntry != null) {
95             // try SrcDst eid lookup
96             ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
97             if (srcEid != null && srcDstDao != null) {
98                 // make sure that srcEid is a prefix, not an IP and binary
99                 Object mapping = getMappingLpmEid(LispAddressUtil.asIpPrefixBinaryEid(srcEid), srcDstDao);
100                 if (mapping !=  null) {
101                     return mapping;
102                 }
103             }
104
105             // if lookup fails, return whatever is found for dst eid
106             return daoEntry.get(SubKeys.RECORD);
107         }
108         return null;
109     }
110
111     public Object getMapping(Eid srcEid, Eid dstEid) {
112         if (dstEid == null) {
113             return null;
114         }
115
116         ILispDAO table = getVniTable(dstEid);
117         if (table == null) {
118             return null;
119         }
120
121         // a map-request for an actual SrcDst LCAF, ignore src eid
122         if (dstEid.getAddress() instanceof SourceDestKey) {
123             Eid srcAddr = SourceDestKeyHelper.getSrcBinary(dstEid);
124             Eid dstAddr = SourceDestKeyHelper.getDstBinary(dstEid);
125             return getMappingLpmSD(srcAddr, dstAddr, table);
126         }
127
128         // potential map-request for SrcDst LCAF from non SrcDst capable devices
129         return getMappingLpmSD(srcEid, dstEid, table);
130     }
131
132     // Returns null for positive mappings, and 0/0 for empty cache.
133     @Override
134     public Eid getWidestNegativeMapping(Eid key) {
135         ILispDAO table = getVniTable(key);
136         if (table == null) {
137             return MaskUtil.normalize(key, (short) 0);
138         }
139         return table.getWidestNegativePrefix(key);
140     }
141
142     @Override
143     public Set<Eid> getSubtree(Eid key) {
144         ILispDAO table = getVniTable(key);
145         if (table == null) {
146             return Collections.emptySet();
147         }
148         return table.getSubtree(key);
149     }
150
151     public void removeMapping(Eid eid) {
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.remove(SourceDestKeyHelper.getSrcBinary(key));
162                 if (db.isEmpty()) {
163                     removeSDInnerDao(key, table);
164                 }
165             }
166         } else {
167             table.remove(key);
168         }
169         if (table.isEmpty()) {
170             removeVniTable(eid);
171         }
172     }
173
174     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
175     // This method returns the DAO associated to a dst or creates it if it doesn't exist.
176     private ILispDAO getOrInstantiateSDInnerDao(Eid address, ILispDAO mappingsDb) {
177         Eid dstKey = SourceDestKeyHelper.getDstBinary(address);
178         ILispDAO srcDstDao = (ILispDAO) mappingsDb.getSpecific(dstKey, SubKeys.LCAF_SRCDST);
179         if (srcDstDao == null) {
180             // inserts nested table for source
181             srcDstDao = mappingsDb.putNestedTable(dstKey, SubKeys.LCAF_SRCDST);
182         }
183         return srcDstDao;
184     }
185
186     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
187     // This method returns the DAO associated to dst or null if it doesn't exist.
188     private ILispDAO getSDInnerDao(Eid address, ILispDAO mappingsDb) {
189         return (ILispDAO) mappingsDb.getSpecific(SourceDestKeyHelper.getDstBinary(address), SubKeys.LCAF_SRCDST);
190     }
191
192     private void removeSDInnerDao(Eid address, ILispDAO mappingsDb) {
193         mappingsDb.removeSpecific(SourceDestKeyHelper.getDstBinary(address), SubKeys.LCAF_SRCDST);
194     }
195
196     @Override
197     public void addData(Eid eid, String subKey, Object data) {
198         Eid key = MaskUtil.normalize(eid);
199         ILispDAO table = getOrInstantiateVniTable(key);
200
201         if (key.getAddress() instanceof SourceDestKey) {
202             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(key, table);
203             srcDstDao.put(SourceDestKeyHelper.getSrcBinary(key), new MappingEntry<>(subKey, data));
204         } else {
205             table.put(key, new MappingEntry<>(subKey, data));
206         }
207     }
208
209     @Override
210     public Object getData(Eid eid, String subKey) {
211         Eid key = MaskUtil.normalize(eid);
212         ILispDAO table = getVniTable(key);
213         if (table == null) {
214             return null;
215         }
216
217         if (key.getAddress() instanceof SourceDestKey) {
218             ILispDAO srcDstDao = getSDInnerDao(key, table);
219             return srcDstDao.getSpecific(SourceDestKeyHelper.getSrcBinary(key), subKey);
220         } else {
221             return table.getSpecific(key, subKey);
222         }
223     }
224
225     @Override
226     public void removeData(Eid eid, String subKey) {
227         Eid key = MaskUtil.normalize(eid);
228         ILispDAO table = getVniTable(key);
229         if (table == null) {
230             return;
231         }
232         if (key.getAddress() instanceof SourceDestKey) {
233             ILispDAO db = getSDInnerDao(key, table);
234             if (db != null) {
235                 db.removeSpecific(SourceDestKeyHelper.getSrcBinary(key), subKey);
236                 if (db.isEmpty()) {
237                     removeSDInnerDao(key, table);
238                 }
239             }
240         } else {
241             table.removeSpecific(key, subKey);
242         }
243         if (table.isEmpty()) {
244             removeVniTable(eid);
245         }
246     }
247
248     @Override
249     public String printMappings() {
250         return LispMapCacheStringifier.printMTMCMappings(dao);
251     }
252
253     @Override
254     public String prettyPrintMappings() {
255         return LispMapCacheStringifier.prettyPrintMTMCMappings(dao);
256     }
257 }