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