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