Bug 7947: Move subscribers to a separate cache
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / mdsal / MappingDataListener.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.mdsal;
9
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.List;
13 import java.util.Set;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
16 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
18 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
19 import org.opendaylight.lispflowmapping.implementation.util.MSNotificationInputUtil;
20 import org.opendaylight.lispflowmapping.interfaces.dao.Subscriber;
21 import org.opendaylight.lispflowmapping.interfaces.mapcache.IMappingSystem;
22 import org.opendaylight.lispflowmapping.lisp.type.MappingData;
23 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
24 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
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.record.container.MappingRecord;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingChange;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingDatabase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.Mapping;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.MappingBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.VirtualNetworkIdentifier;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * DataListener for all Mapping modification events.
43  *
44  * @author Lorand Jakab
45  * @author Florin Coras
46  *
47  */
48 public class MappingDataListener extends AbstractDataListener<Mapping> {
49     private static final Logger LOG = LoggerFactory.getLogger(MappingDataListener.class);
50     private IMappingSystem mapSystem;
51     private NotificationPublishService notificationPublishService;
52     private boolean isMaster = false;
53
54     public MappingDataListener(DataBroker broker, IMappingSystem msmr, NotificationPublishService nps) {
55         setBroker(broker);
56         setMappingSystem(msmr);
57         setNotificationProviderService(nps);
58         setPath(InstanceIdentifier.create(MappingDatabase.class).child(VirtualNetworkIdentifier.class)
59                 .child(Mapping.class));
60         LOG.trace("Registering Mapping listener.");
61         registerDataChangeListener();
62     }
63
64     public void setNotificationProviderService(NotificationPublishService nps) {
65         this.notificationPublishService = nps;
66     }
67
68     void setMappingSystem(IMappingSystem msmr) {
69         this.mapSystem = msmr;
70     }
71
72     @Override
73     public void onDataTreeChanged(Collection<DataTreeModification<Mapping>> changes) {
74         for (DataTreeModification<Mapping> change : changes) {
75             final DataObjectModification<Mapping> mod = change.getRootNode();
76
77             if (ModificationType.DELETE == mod.getModificationType()) {
78                 // Process deleted mappings
79
80                 final Mapping mapping = mod.getDataBefore();
81
82                 // Only treat mapping changes caused by Northbound, since Southbound changes are already handled
83                 // before being persisted, except for cluster slaves
84                 if (mapping.getOrigin() == MappingOrigin.Southbound && mapSystem.isMaster()) {
85                     continue;
86                 }
87
88                 LOG.trace("Received deleted data");
89                 LOG.trace("Key: {}", change.getRootPath().getRootIdentifier());
90                 LOG.trace("Value: {}", mapping);
91
92                 final Mapping convertedMapping = convertToBinaryIfNecessary(mapping);
93
94                 mapSystem.removeMapping(convertedMapping.getOrigin(), convertedMapping.getMappingRecord().getEid());
95
96             } else if (ModificationType.SUBTREE_MODIFIED == mod.getModificationType() || ModificationType.WRITE == mod
97                     .getModificationType()) {
98                 final Mapping mapping = mod.getDataAfter();
99
100                 // Only treat mapping changes caused by Northbound, since Southbound changes are already handled
101                 // before being persisted, except for cluster slaves XXX separate NB and SB to avoid ignoring
102                 // SB notifications
103                 if (mapping.getOrigin() == MappingOrigin.Southbound && mapSystem.isMaster()) {
104                     continue;
105                 }
106
107                 MappingChange mappingChange;
108
109                 if (ModificationType.SUBTREE_MODIFIED == mod.getModificationType()) {
110                     LOG.trace("Received update data");
111                     mappingChange = MappingChange.Updated;
112                 } else {
113                     LOG.trace("Received write data");
114                     mappingChange = MappingChange.Created;
115                 }
116                 LOG.trace("Key: {}", change.getRootPath().getRootIdentifier());
117                 LOG.trace("Value: {}", mapping);
118
119                 final Mapping convertedMapping = convertToBinaryIfNecessary(mapping);
120                 Eid convertedEid = convertedMapping.getMappingRecord().getEid();
121
122                 mapSystem.addMapping(convertedMapping.getOrigin(), convertedEid,
123                         new MappingData(convertedMapping.getMappingRecord()));
124                 Set<Subscriber> subscribers = mapSystem.getSubscribers(convertedEid);
125
126                 Set<Subscriber> dstSubscribers = null;
127                 // For SrcDst LCAF also send SMRs to Dst prefix
128                 if (convertedEid.getAddress() instanceof SourceDestKey) {
129                     Eid dstAddr = SourceDestKeyHelper.getDstBinary(convertedEid);
130                     dstSubscribers = mapSystem.getSubscribers(dstAddr);
131                 }
132
133                 try {
134                     // The notifications are used for sending SMR.
135                     notificationPublishService.putNotification(MSNotificationInputUtil.toMappingChanged(
136                             convertedMapping, subscribers, dstSubscribers, mappingChange));
137                 } catch (InterruptedException e) {
138                     LOG.warn("Notification publication interrupted!");
139                 }
140
141             } else {
142                 LOG.warn("Ignoring unhandled modification type {}", mod.getModificationType());
143             }
144         }
145     }
146
147     private static Mapping convertToBinaryIfNecessary(Mapping mapping) {
148         MappingRecord originalRecord = mapping.getMappingRecord();
149         List<LocatorRecord> originalLocators = originalRecord.getLocatorRecord();
150
151         List<LocatorRecord> convertedLocators = null;
152         if (originalLocators != null) {
153             // If convertedLocators is non-null, while originalLocators is also non-null, conversion has been made
154             convertedLocators = convertToBinaryIfNecessary(originalLocators);
155         }
156
157         if (LispAddressUtil.addressNeedsConversionToBinary(originalRecord.getEid().getAddress())
158                 || (originalLocators != null && convertedLocators != null)) {
159             MappingRecordBuilder mrb = new MappingRecordBuilder(originalRecord);
160             mrb.setEid(LispAddressUtil.convertToBinary(originalRecord.getEid()));
161             if (convertedLocators != null) {
162                 mrb.setLocatorRecord(convertedLocators);
163             }
164             return new MappingBuilder(mapping).setMappingRecord(mrb.build()).build();
165         }
166         return mapping;
167     }
168
169     private static List<LocatorRecord> convertToBinaryIfNecessary(List<LocatorRecord> originalLocators) {
170         List<LocatorRecord> convertedLocators = null;
171         for (LocatorRecord record : originalLocators) {
172             if (LispAddressUtil.addressNeedsConversionToBinary(record.getRloc().getAddress())) {
173                 LocatorRecordBuilder lrb = new LocatorRecordBuilder(record);
174                 lrb.setRloc(LispAddressUtil.convertToBinary(record.getRloc()));
175                 if (convertedLocators == null) {
176                     convertedLocators = new ArrayList<LocatorRecord>();
177                 }
178                 convertedLocators.add(lrb.build());
179             }
180         }
181         if (convertedLocators != null) {
182             return convertedLocators;
183         }
184         return originalLocators;
185     }
186 }