Update DAO API
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / mapcache / TopologyMapCache.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 import java.util.Set;
14
15 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
16 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
17 import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys;
18 import org.opendaylight.lispflowmapping.interfaces.dao.SubscriberRLOC;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.eidtolocatorrecords.EidToLocatorRecord;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.eidtolocatorrecords.EidToLocatorRecordBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.lispaddress.LispAddressContainer;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev150820.lispaddress.lispaddresscontainer.address.LcafSourceDest;
23 import org.opendaylight.lispflowmapping.lisp.util.LcafSourceDestHelper;
24 import org.opendaylight.lispflowmapping.lisp.util.LispAFIConvertor;
25 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 public class TopologyMapCache {
30     private static final Logger LOG = LoggerFactory.getLogger(TopologyMapCache.class);
31
32     public static boolean addMapping(EidToLocatorRecord record, boolean checkForChanges, ILispDAO dao,
33             boolean shouldIterate, boolean shouldOverwrite) {
34         LispAddressContainer eid = MaskUtil.normalize(record.getLispAddressContainer());
35         EidToLocatorRecord oldMapping = null;
36         if (eid.getAddress() instanceof LcafSourceDest) {
37             LispAddressContainer srcAddr = LcafSourceDestHelper.getSrc(eid);
38             LispAddressContainer dstAddr = LcafSourceDestHelper.getDst(eid);
39
40             if (checkForChanges) {
41                 oldMapping = getMappingExactSD(srcAddr, dstAddr, dao);
42             }
43             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, dao);
44             srcDstDao.put(LcafSourceDestHelper.getSrc(eid),
45                     new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
46             srcDstDao.put(LcafSourceDestHelper.getSrc(eid), new MappingEntry<>(SubKeys.RECORD, record));
47             if (checkForChanges && oldMapping != null && eid.equals(oldMapping.getLispAddressContainer())) {
48                 return true;
49             }
50         } else {
51             if (checkForChanges) {
52                 oldMapping = getMappingExactSD(null, eid, dao);
53             }
54             dao.put(eid, new MappingEntry<>(SubKeys.REGDATE, new Date(System.currentTimeMillis())));
55             dao.put(eid, new MappingEntry<>(SubKeys.RECORD, record));
56             if (checkForChanges && oldMapping != null && eid.equals(oldMapping.getLispAddressContainer())) {
57                 return true;
58             }
59         }
60         return false;
61     }
62
63     // Method returns the DAO entry (hash) corresponding to either the longest prefix match of eid, if eid is maskable,
64     // or the exact match otherwise. eid must be a 'simple' address
65     private static Map<String, ?> getDaoEntryBest(LispAddressContainer eid, ILispDAO dao) {
66         if (MaskUtil.isMaskable(eid)) {
67             LispAddressContainer key;
68             short mask = MaskUtil.getMaskForAddress(eid);
69             while (mask > 0) {
70                 key = MaskUtil.normalize(eid, mask);
71                 mask--;
72                 Map<String, ?> entry = dao.get(key);
73                 if (entry != null) {
74                     return entry;
75                 }
76             }
77             return null;
78         } else {
79             Map<String, ?> entry = dao.get(eid);
80             if (entry != null) {
81                 return dao.get(eid);
82             } else {
83                 return null;
84             }
85         }
86     }
87
88     private static EidToLocatorRecord getMappingExactSD(LispAddressContainer srcEid, LispAddressContainer dstEid,
89             ILispDAO dao) {
90         Map<String, ?> daoEntry = dao.get(dstEid);
91         if (daoEntry != null) {
92             // try SrcDst eid lookup
93             ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
94             if (srcEid != null && srcDstDao != null) {
95                 EidToLocatorRecord mapping = (EidToLocatorRecord) srcDstDao.getSpecific(srcEid, SubKeys.RECORD);
96                 return mapping;
97             }
98             // if lookup fails, return whatever is found for dst eid
99             return (EidToLocatorRecord) daoEntry.get(SubKeys.RECORD);
100         }
101         return null;
102     }
103
104     // Returns the mapping corresponding to the longest prefix match for eid. eid must be a simple (maskable or not) address
105     private static EidToLocatorRecord getMappingLpmEid(LispAddressContainer eid, ILispDAO dao) {
106         Map<String, ?> daoEntry = getDaoEntryBest(eid, dao);
107         if (daoEntry != null) {
108             return (EidToLocatorRecord) daoEntry.get(SubKeys.RECORD);
109         } else {
110             return null;
111         }
112     }
113
114     // Returns a mapping corresponding to either the longest prefix match for both dstEid and srcEid,
115     // if a SourceDest mapping exists, or to dstEid
116     private static EidToLocatorRecord getMappingLpmSD(LispAddressContainer srcEid, LispAddressContainer dstEid, ILispDAO dao) {
117         Map<String, ?> daoEntry = getDaoEntryBest(dstEid, dao);
118         if (daoEntry != null) {
119
120             // try SrcDst eid lookup
121             ILispDAO srcDstDao = (ILispDAO) daoEntry.get(SubKeys.LCAF_SRCDST);
122             if (srcDstDao != null) {
123                 EidToLocatorRecord mapping = getMappingLpmEid(srcEid, srcDstDao);
124                 if (mapping!= null) {
125                     return mapping;
126                 }
127             }
128
129             // if lookup fails, return whatever is found for dst eid
130             return (EidToLocatorRecord) daoEntry.get(SubKeys.RECORD);
131         }
132         return null;
133     }
134
135     public static EidToLocatorRecord getMapping(LispAddressContainer srcEid, LispAddressContainer dstEid,
136             ILispDAO dao) {
137         // a map-request for an actual SrcDst LCAF, ignore src eid
138         if (dstEid.getAddress() instanceof LcafSourceDest) {
139             LispAddressContainer srcAddr = LcafSourceDestHelper.getSrc(dstEid);
140             LispAddressContainer dstAddr = LcafSourceDestHelper.getDst(dstEid);
141             return getMappingLpmSD(srcAddr, dstAddr, dao);
142         }
143
144         // potential map-request for SrcDst LCAF from non SrcDst capable devices
145         EidToLocatorRecord mapping = getMappingLpmSD(srcEid, dstEid, dao);
146
147         if (mapping == null) {
148             return null;
149         }
150
151         // if indeed SrcDst LCAF change the mapping's eid to matched dstEid
152         if (mapping.getLispAddressContainer().getAddress() instanceof LcafSourceDest) {
153             EidToLocatorRecord newMapping = new EidToLocatorRecordBuilder(mapping).setLispAddressContainer(
154                     LcafSourceDestHelper.getDst(mapping.getLispAddressContainer())).build();
155             return newMapping;
156         }
157
158         return mapping;
159     }
160
161     public static void removeMapping(LispAddressContainer address, ILispDAO dao, boolean oerwrite) {
162         if (address.getAddress() instanceof LcafSourceDest) {
163             ILispDAO db = getSDInnerDao(address, dao);
164             if (db != null) {
165                 db.removeSpecific(LcafSourceDestHelper.getSrc(address),
166                         SubKeys.RECORD);
167             }
168         } else {
169             dao.removeSpecific(address, SubKeys.RECORD);
170         }
171     }
172
173     public static void addAuthenticationKey(LispAddressContainer address, String key, ILispDAO dao) {
174         if (address.getAddress() instanceof LcafSourceDest) {
175             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(address, dao);
176             srcDstDao.put(LcafSourceDestHelper.getSrc(address), new MappingEntry<String>(SubKeys.PASSWORD, key));
177         } else {
178             dao.put(address, new MappingEntry<String>(SubKeys.PASSWORD, key));
179         }
180     }
181
182     private static String getAuthKeyLpm(LispAddressContainer prefix, ILispDAO db) {
183         short maskLength = MaskUtil.getMaskForAddress(prefix);
184         while (maskLength >= 0) {
185             LispAddressContainer key = MaskUtil.normalize(prefix, maskLength);
186             Object password = db.getSpecific(key, SubKeys.PASSWORD);
187             if (password != null && password instanceof String) {
188                 return (String) password;
189             }
190             maskLength -= 1;
191         }
192         return null;
193     }
194
195     public static String getAuthenticationKey(LispAddressContainer eid, ILispDAO dao, boolean iterate) {
196         if (MaskUtil.isMaskable(LispAFIConvertor.toAFI(eid)) && iterate) {
197             return getAuthKeyLpm(eid, dao);
198         } else if (eid.getAddress() instanceof LcafSourceDest && iterate) {
199             // NOTE: this is an exact match, not a longest prefix match
200             ILispDAO srcDstDao = getSDInnerDao(eid, dao);
201             if (srcDstDao != null) {
202                 return getAuthKeyLpm(LcafSourceDestHelper.getSrc(eid), srcDstDao);
203             }
204             return null;
205         } else {
206             Object password = dao.getSpecific(eid, SubKeys.PASSWORD);
207             if (password != null && password instanceof String) {
208                 return (String) password;
209             } else {
210                 LOG.warn("Failed to find password!");
211                 return null;
212             }
213         }
214     }
215
216     public static void removeAuthenticationKey(LispAddressContainer eid, ILispDAO dao) {
217         if (eid.getAddress() instanceof LcafSourceDest) {
218             ILispDAO srcDstDao = getSDInnerDao(eid, dao);
219             if (srcDstDao != null) {
220                 srcDstDao.removeSpecific(eid, SubKeys.PASSWORD);
221             }
222         } else {
223             dao.removeSpecific(eid, SubKeys.PASSWORD);
224         }
225     }
226
227     public static void addSubscribers(LispAddressContainer eid, Set<SubscriberRLOC> subscribers,
228             ILispDAO dao) {
229         if (eid.getAddress() instanceof LcafSourceDest) {
230             ILispDAO srcDstDao = getOrInstantiateSDInnerDao(eid, dao);
231             srcDstDao.put(LcafSourceDestHelper.getSrc(eid), new MappingEntry<Set<SubscriberRLOC>>(
232                     SubKeys.SUBSCRIBERS, subscribers));
233         } else {
234             dao.put(eid, new MappingEntry<Set<SubscriberRLOC>>(SubKeys.SUBSCRIBERS, subscribers));
235         }
236     }
237
238     @SuppressWarnings("unchecked")
239     public static Set<SubscriberRLOC> getSubscribers(LispAddressContainer eid, ILispDAO dao) {
240         Object subscribers;
241         if (eid.getAddress() instanceof LcafSourceDest) {
242             ILispDAO srcDstDao = getSDInnerDao(eid, dao);
243             subscribers = srcDstDao.getSpecific(LcafSourceDestHelper.getSrc(eid), SubKeys.SUBSCRIBERS);
244         } else {
245             subscribers = dao.getSpecific(eid, SubKeys.SUBSCRIBERS);
246         }
247
248         if (subscribers != null && subscribers instanceof Set<?>) {
249             return (Set<SubscriberRLOC>) subscribers;
250         }
251         return null;
252     }
253
254     public static void removeSubscribers(LispAddressContainer address, ILispDAO dao, boolean shouldOverwrite) {
255         if (address.getAddress() instanceof LcafSourceDest) {
256             ILispDAO db = getSDInnerDao(address, dao);
257             if (db != null) {
258                 db.removeSpecific(LcafSourceDestHelper.getSrc(address), SubKeys.SUBSCRIBERS);
259             }
260         } else {
261             dao.removeSpecific(address, SubKeys.SUBSCRIBERS);
262         }
263     }
264
265     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
266     // This method returns the DAO associated to a dst or creates it if it doesn't exist.
267     public static ILispDAO getOrInstantiateSDInnerDao(LispAddressContainer address, ILispDAO dao) {
268         ILispDAO srcDstDao = (ILispDAO) dao.getSpecific(LcafSourceDestHelper.getDst(address),
269                 SubKeys.LCAF_SRCDST);
270         if (srcDstDao == null) {
271             // inserts nested table for source
272             srcDstDao = dao.putNestedTable(LcafSourceDestHelper.getDst(address), SubKeys.LCAF_SRCDST);
273         }
274         return srcDstDao;
275     }
276
277     // SrcDst LCAFs are stored in a 2-tier DAO with dst having priority over src.
278     // This method returns the DAO associated to dst or null if it doesn't exist.
279     public static ILispDAO getSDInnerDao(LispAddressContainer address, ILispDAO dao) {
280         return (ILispDAO) dao.getSpecific(LcafSourceDestHelper.getDst(address), SubKeys.LCAF_SRCDST);
281     }
282 }