Merge "Add radix trie to HashMapDb for fast IP LPM"
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / MappingService.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc.  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.implementation;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.concurrent.Future;
13
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
16 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
17 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
18 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
19 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
20 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
21 import org.opendaylight.lispflowmapping.implementation.config.ConfigIni;
22 import org.opendaylight.lispflowmapping.implementation.mdsal.AuthenticationKeyDataListener;
23 import org.opendaylight.lispflowmapping.dsbackend.DataStoreBackEnd;
24 import org.opendaylight.lispflowmapping.implementation.mdsal.MappingDataListener;
25 import org.opendaylight.lispflowmapping.implementation.util.DSBEInputUtil;
26 import org.opendaylight.lispflowmapping.implementation.util.RPCInputConvertorUtil;
27 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
28 import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService;
29 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecord;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddKeyInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddKeysInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddMappingInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.AddMappingsInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetAllKeysOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetAllMappingsOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeyInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeyOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeyOutputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeysInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetKeysOutput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingOutput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingOutputBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingsInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.GetMappingsOutput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.OdlMappingserviceService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveKeyInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveKeysInput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveMappingInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.RemoveMappingsInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateKeyInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateKeysInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateMappingInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.UpdateMappingsInput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.authkey.container.MappingAuthkey;
63 import org.opendaylight.yangtools.yang.common.RpcError;
64 import org.opendaylight.yangtools.yang.common.RpcResult;
65 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 import com.google.common.base.Preconditions;
70 import com.google.common.util.concurrent.Futures;
71
72 /**
73  * Dispatcher of API calls that implements the RPC and Java APIs in mappingservice.yang and IMappingService
74  * respectively. It also coordinates and acts as container for all objects in charge of
75  *  - saving and updating md-sal datastore stored mappings
76  *  - monitoring md-sal datastore mapping updates and pushing them to the in memory mapping-system
77  *  - in memory mapping-system
78  *
79  * @author Lorand Jakab
80  * @author Florin Coras
81  *
82  */
83 public class MappingService implements OdlMappingserviceService, IMappingService, BindingAwareProvider, AutoCloseable {
84     protected static final Logger LOG = LoggerFactory.getLogger(MappingService.class);
85     private static final String NOT_FOUND_TAG = "data-missing";
86     private static final String DATA_EXISTS_TAG = "data-exists";
87
88     private MappingSystem mappingSystem;
89     private DataStoreBackEnd dsbe;
90     private RpcRegistration<OdlMappingserviceService> mappingServiceRpc;
91     private AuthenticationKeyDataListener keyListener;
92     private MappingDataListener mappingListener;
93     private ILispDAO dao;
94
95     private DataBroker dataBroker;
96     private RpcProviderRegistry rpcRegistry;
97     private BindingAwareBroker bindingAwareBroker;
98     private NotificationPublishService notificationPublishService;
99
100     private boolean overwritePolicy = ConfigIni.getInstance().mappingOverwriteIsSet();
101     private boolean notificationPolicy = ConfigIni.getInstance().smrIsSet();
102     private boolean iterateMask = true;
103
104     public MappingService() {
105         LOG.debug("MappingService created!");
106     }
107
108     public void setDataBroker(DataBroker dataBroker) {
109         this.dataBroker = dataBroker;
110     }
111
112     public void setRpcProviderRegistry(RpcProviderRegistry rpc) {
113         this.rpcRegistry = rpc;
114     }
115
116     public void setBindingAwareBroker(BindingAwareBroker broker) {
117         this.bindingAwareBroker = broker;
118     }
119
120     public void setNotificationPublishService(NotificationPublishService nps) {
121         this.notificationPublishService = nps;
122     }
123
124     public void setDaoService(ILispDAO dao) {
125         this.dao = dao;
126     }
127
128     @Override
129     public void setMappingOverwrite(boolean overwrite) {
130         this.overwritePolicy = overwrite;
131         if (mappingSystem != null) {
132             mappingSystem.setOverwritePolicy(overwrite);
133             ConfigIni.getInstance().setMappingOverwrite(overwrite);
134         }
135     }
136
137     @Override
138     public void setLookupPolicy(IMappingService.LookupPolicy policy) {
139         ConfigIni.getInstance().setLookupPolicy(policy);
140     }
141
142     public void initialize() {
143         bindingAwareBroker.registerProvider(this);
144
145         mappingServiceRpc = rpcRegistry.addRpcImplementation(OdlMappingserviceService.class, this);
146         dsbe = new DataStoreBackEnd(dataBroker);
147
148         mappingSystem = new MappingSystem(dao, iterateMask, notificationPolicy, overwritePolicy);
149         mappingSystem.setDataStoreBackEnd(dsbe);
150         mappingSystem.initialize();
151
152         keyListener = new AuthenticationKeyDataListener(dataBroker, mappingSystem);
153         mappingListener = new MappingDataListener(dataBroker, mappingSystem, notificationPublishService);
154     }
155
156     @Override
157     public Future<RpcResult<Void>> addKey(AddKeyInput input) {
158         Preconditions.checkNotNull(input, "add-key RPC input must be not null!");
159         LOG.trace("RPC received to add the following key: " + input.toString());
160
161         RpcResultBuilder<Void> rpcResultBuilder;
162
163         MappingAuthkey key = mappingSystem.getAuthenticationKey(convertToBinaryIfNecessary(input.getEid()));
164
165         if (key != null) {
166             String message = "Key already exists! Please use update-key if you want to change it.";
167             rpcResultBuilder = RpcResultBuilder.<Void>failed()
168                     .withError(RpcError.ErrorType.PROTOCOL, DATA_EXISTS_TAG, message);
169             return Futures.immediateFuture(rpcResultBuilder.build());
170         }
171
172         dsbe.addAuthenticationKey(RPCInputConvertorUtil.toAuthenticationKey(input));
173         rpcResultBuilder = RpcResultBuilder.success();
174
175         return Futures.immediateFuture(rpcResultBuilder.build());
176     }
177
178     @Override
179     public Future<RpcResult<Void>> addMapping(AddMappingInput input) {
180         Preconditions.checkNotNull(input, "add-mapping RPC input must be not null!");
181         LOG.trace("RPC received to add the following mapping: " + input.toString());
182
183         dsbe.addMapping(RPCInputConvertorUtil.toMapping(input));
184
185         RpcResultBuilder<Void> rpcResultBuilder;
186
187         rpcResultBuilder = RpcResultBuilder.success();
188
189         return Futures.immediateFuture(rpcResultBuilder.build());
190     }
191
192     @Override
193     public Future<RpcResult<GetKeyOutput>> getKey(GetKeyInput input) {
194         Preconditions.checkNotNull(input, "get-key RPC input must be not null!");
195         LOG.trace("RPC received to get the following key: " + input.toString());
196
197         RpcResultBuilder<GetKeyOutput> rpcResultBuilder;
198
199         MappingAuthkey key = mappingSystem.getAuthenticationKey(convertToBinaryIfNecessary(input.getEid()));
200
201         if (key == null) {
202             String message = "Key was not found in the mapping database";
203             rpcResultBuilder = RpcResultBuilder.<GetKeyOutput>failed()
204                     .withError(RpcError.ErrorType.APPLICATION, NOT_FOUND_TAG, message);
205         } else {
206             rpcResultBuilder = RpcResultBuilder.success(new GetKeyOutputBuilder().setMappingAuthkey(key));
207         }
208
209         return Futures.immediateFuture(rpcResultBuilder.build());
210     }
211
212     @Override
213     public Future<RpcResult<GetMappingOutput>> getMapping(GetMappingInput input) {
214         Preconditions.checkNotNull(input, "get-mapping RPC input must be not null!");
215         LOG.trace("RPC received to get the following mapping: " + input.toString());
216
217         RpcResultBuilder<GetMappingOutput> rpcResultBuilder;
218
219         MappingRecord reply = (MappingRecord) mappingSystem.getMapping(convertToBinaryIfNecessary(input.getEid()));
220
221         if (reply == null) {
222             String message = "No mapping was found in the mapping database";
223             rpcResultBuilder = RpcResultBuilder.<GetMappingOutput>failed()
224                     .withError(RpcError.ErrorType.APPLICATION, NOT_FOUND_TAG, message);
225         } else {
226             final MappingRecord convertedReply = convertFromBinaryIfNecessary(reply);
227             rpcResultBuilder = RpcResultBuilder.success(new GetMappingOutputBuilder().setMappingRecord(convertedReply));
228         }
229
230         return Futures.immediateFuture(rpcResultBuilder.build());
231     }
232
233     @Override
234     public Future<RpcResult<Void>> removeKey(RemoveKeyInput input) {
235         Preconditions.checkNotNull(input, "remove-key RPC input must be not null!");
236         LOG.trace("RPC received to remove the following key: " + input.toString());
237
238         RpcResultBuilder<Void> rpcResultBuilder;
239
240         dsbe.removeAuthenticationKey(RPCInputConvertorUtil.toAuthenticationKey(input));
241
242         rpcResultBuilder = RpcResultBuilder.success();
243
244         return Futures.immediateFuture(rpcResultBuilder.build());
245     }
246
247     @Override
248     public Future<RpcResult<Void>> removeMapping(RemoveMappingInput input) {
249         Preconditions.checkNotNull(input, "remove-mapping RPC input must be not null!");
250         LOG.trace("RPC received to remove the following mapping: " + input.toString());
251
252         RpcResultBuilder<Void> rpcResultBuilder;
253
254         dsbe.removeMapping(RPCInputConvertorUtil.toMapping(input));
255
256         rpcResultBuilder = RpcResultBuilder.success();
257
258         return Futures.immediateFuture(rpcResultBuilder.build());
259     }
260
261     @Override
262     public Future<RpcResult<Void>> updateKey(UpdateKeyInput input) {
263         Preconditions.checkNotNull(input, "update-key RPC input must be not null!");
264         LOG.trace("RPC received to update the following key: " + input.toString());
265
266         RpcResultBuilder<Void> rpcResultBuilder;
267
268         MappingAuthkey key = mappingSystem.getAuthenticationKey(convertToBinaryIfNecessary(input.getEid()));
269
270         if (key == null) {
271             String message = "Key doesn't exist! Please use add-key if you want to create a new authentication key.";
272             rpcResultBuilder = RpcResultBuilder.<Void>failed()
273                     .withError(RpcError.ErrorType.PROTOCOL, NOT_FOUND_TAG, message);
274             return Futures.immediateFuture(rpcResultBuilder.build());
275         }
276
277         dsbe.updateAuthenticationKey(RPCInputConvertorUtil.toAuthenticationKey(input));
278         rpcResultBuilder = RpcResultBuilder.success();
279
280         return Futures.immediateFuture(rpcResultBuilder.build());
281     }
282
283     @Override
284     public Future<RpcResult<Void>> updateMapping(UpdateMappingInput input) {
285         LOG.trace("RPC received to update the following mapping: " + input.toString());
286         Preconditions.checkNotNull(input, "update-mapping RPC input must be not null!");
287
288         RpcResultBuilder<Void> rpcResultBuilder;
289
290         dsbe.updateMapping(RPCInputConvertorUtil.toMapping(input));
291
292         rpcResultBuilder = RpcResultBuilder.success();
293
294         return Futures.immediateFuture(rpcResultBuilder.build());
295     }
296
297     @Override
298     public Future<RpcResult<Void>> removeKeys(RemoveKeysInput input) {
299         // TODO Auto-generated method stub
300         return null;
301     }
302
303     @Override
304     public Future<RpcResult<Void>> removeMappings(RemoveMappingsInput input) {
305         // TODO Auto-generated method stub
306         return null;
307     }
308
309     @Override
310     public Future<RpcResult<GetKeysOutput>> getKeys(GetKeysInput input) {
311         // TODO Auto-generated method stub
312         return null;
313     }
314
315     @Override
316     public Future<RpcResult<Void>> addMappings(AddMappingsInput input) {
317         // TODO Auto-generated method stub
318         return null;
319     }
320
321     @Override
322     public Future<RpcResult<Void>> updateKeys(UpdateKeysInput input) {
323         // TODO Auto-generated method stub
324         return null;
325     }
326
327     @Override
328     public Future<RpcResult<Void>> removeAllMappings() {
329         // TODO Auto-generated method stub
330         return null;
331     }
332
333     @Override
334     public Future<RpcResult<Void>> removeAllKeys() {
335         // TODO Auto-generated method stub
336         return null;
337     }
338
339     @Override
340     public Future<RpcResult<GetAllKeysOutput>> getAllKeys() {
341         // TODO Auto-generated method stub
342         return null;
343     }
344
345     @Override
346     public Future<RpcResult<Void>> updateMappings(UpdateMappingsInput input) {
347         // TODO Auto-generated method stub
348         return null;
349     }
350
351     @Override
352     public Future<RpcResult<Void>> addKeys(AddKeysInput input) {
353         // TODO Auto-generated method stub
354         return null;
355     }
356
357     @Override
358     public Future<RpcResult<GetAllMappingsOutput>> getAllMappings() {
359         // TODO Auto-generated method stub
360         return null;
361     }
362
363     @Override
364     public Future<RpcResult<GetMappingsOutput>> getMappings(
365             GetMappingsInput input) {
366         // TODO Auto-generated method stub
367         return null;
368     }
369
370     @Override
371     public void addMapping(MappingOrigin origin, Eid key, SiteId siteId, Object data, boolean merge) {
372         // SB registrations are first written to the MappingSystem and only afterwards are persisted to the datastore
373         if (origin.equals(MappingOrigin.Southbound)) {
374             // Store data first in MapCache and only afterwards persist to datastore. This should be used only for SB
375             // registrations
376             mappingSystem.addMapping(origin, key, data, merge);
377             dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, (MappingRecord) data));
378             if (((MappingRecord) data).getXtrId() != null) {
379                 dsbe.addXtrIdMapping(DSBEInputUtil.toXtrIdMapping((MappingRecord) data));
380             }
381         } else {
382             dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, (MappingRecord) data));
383         }
384     }
385
386     @Override
387     public void updateMappingRegistration(MappingOrigin origin, Eid key, Long timestamp) {
388         mappingSystem.updateMappingRegistration(origin, key, timestamp);
389     }
390
391     @Override
392     public Object getMapping(MappingOrigin origin, Eid key) {
393         return mappingSystem.getMapping(origin, key);
394     }
395
396     @Override
397     public Object getMapping(Eid key) {
398         return mappingSystem.getMapping(key);
399     }
400
401     @Override
402     public Object getMapping(Eid srcKey, Eid dstKey) {
403         return mappingSystem.getMapping(srcKey, dstKey);
404     }
405
406     @Override
407     public Eid getWidestNegativePrefix(Eid key) {
408         return mappingSystem.getWidestNegativePrefix(key);
409     }
410
411     @Override
412     public void removeMapping(MappingOrigin origin, Eid key) {
413         dsbe.removeMapping(DSBEInputUtil.toMapping(origin, key));
414     }
415
416     @Override
417     public void addAuthenticationKey(Eid key, MappingAuthkey authKey) {
418         dsbe.addAuthenticationKey(DSBEInputUtil.toAuthenticationKey(key, authKey));
419     }
420
421     @Override
422     public MappingAuthkey getAuthenticationKey(Eid key) {
423         return mappingSystem.getAuthenticationKey(key);
424     }
425
426     @Override
427     public void removeAuthenticationKey(Eid key) {
428         dsbe.removeAuthenticationKey(DSBEInputUtil.toAuthenticationKey(key, null));
429     }
430
431     @Override
432     public void addData(MappingOrigin origin, Eid key, String subKey, Object data) {
433         mappingSystem.addData(origin, key, subKey, data);
434     }
435
436     @Override
437     public Object getData(MappingOrigin origin, Eid key, String subKey) {
438         return mappingSystem.getData(origin, key, subKey);
439     }
440
441     @Override
442     public void removeData(MappingOrigin origin, Eid key, String subKey) {
443         mappingSystem.removeData(origin, key, subKey);
444     }
445
446     @Override
447     public String printMappings() {
448         return mappingSystem.printMappings();
449     }
450
451     @Override
452     public void onSessionInitiated(ProviderContext session) {
453         LOG.info("Mapping Service provider session initializing!");
454     }
455
456     @Override
457     public void close() throws Exception {
458         LOG.info("Mapping Service is being destroyed!");
459         mappingServiceRpc.close();
460         keyListener.closeDataChangeListener();
461         mappingListener.closeDataChangeListener();
462     }
463
464     @Override
465     public void cleanCachedMappings() {
466         mappingSystem.cleanCaches();
467         dsbe.removeAllDatastoreContent();
468     }
469
470     private static Eid convertToBinaryIfNecessary(Eid eid) {
471         if (LispAddressUtil.addressNeedsConversionToBinary(eid.getAddress())) {
472             return LispAddressUtil.convertToBinary(eid);
473         }
474         return eid;
475     }
476
477     private static MappingRecord convertFromBinaryIfNecessary(MappingRecord originalRecord) {
478         List<LocatorRecord> originalLocators = originalRecord.getLocatorRecord();
479
480         List<LocatorRecord> convertedLocators = null;
481         if (originalLocators != null) {
482             // If convertedLocators is non-null, while originalLocators is also non-null, conversion has been made
483             convertedLocators = convertFromBinaryIfNecessary(originalLocators);
484         }
485
486         if (LispAddressUtil.addressNeedsConversionFromBinary(originalRecord.getEid().getAddress()) ||
487                 (originalLocators != null && convertedLocators != null)) {
488             MappingRecordBuilder mrb = new MappingRecordBuilder(originalRecord);
489             mrb.setEid(LispAddressUtil.convertFromBinary(originalRecord.getEid()));
490             if (convertedLocators != null) {
491                 mrb.setLocatorRecord(convertedLocators);
492             }
493             return mrb.build();
494         }
495         return originalRecord;
496     }
497
498     private static List<LocatorRecord> convertFromBinaryIfNecessary(List<LocatorRecord> originalLocators) {
499         List<LocatorRecord> convertedLocators = null;
500         for (LocatorRecord record : originalLocators) {
501             if (LispAddressUtil.addressNeedsConversionFromBinary(record.getRloc().getAddress())) {
502                 LocatorRecordBuilder lrb = new LocatorRecordBuilder(record);
503                 lrb.setRloc(LispAddressUtil.convertFromBinary(record.getRloc()));
504                 if (convertedLocators == null) {
505                     convertedLocators = new ArrayList<LocatorRecord>();
506                 }
507                 convertedLocators.add(lrb.build());
508             }
509         }
510         if (convertedLocators != null) {
511             return convertedLocators;
512         }
513         return originalLocators;
514     }
515 }