Add Map-Request source RLOC to DAO (needed for SMR)
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / lisp / MapResolver.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.lisp;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.HashSet;
14 import java.util.Map;
15 import java.net.InetAddress;
16
17 import org.opendaylight.lispflowmapping.implementation.dao.MappingServiceKeyUtil;
18 import org.opendaylight.lispflowmapping.implementation.util.LispNotificationHelper;
19 import org.opendaylight.lispflowmapping.implementation.util.MapRequestUtil;
20 import org.opendaylight.lispflowmapping.implementation.util.MaskUtil;
21 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
22 import org.opendaylight.lispflowmapping.interfaces.dao.IMappingServiceKey;
23 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
24 import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceRLOCGroup;
25 import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceSubscriberRLOC;
26 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapRequestResultHandler;
27 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapResolverAsync;
28 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapRequest;
29 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidrecords.EidRecord;
30 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidtolocatorrecords.EidToLocatorRecord;
31 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidtolocatorrecords.EidToLocatorRecord.Action;
32 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidtolocatorrecords.EidToLocatorRecordBuilder;
33 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispaddress.LispAddressContainerBuilder;
34 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.locatorrecords.LocatorRecord;
35 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.locatorrecords.LocatorRecordBuilder;
36 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.mapreplymessage.MapReplyBuilder;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 public class MapResolver extends AbstractLispComponent implements IMapResolverAsync {
41
42     private static final int TTL_RLOC_TIMED_OUT = 1;
43     private static final int TTL_NO_RLOC_KNOWN = 15;
44     protected static final Logger logger = LoggerFactory.getLogger(MapResolver.class);
45
46     public MapResolver(ILispDAO dao) {
47         this(dao, true, true);
48     }
49
50     public MapResolver(ILispDAO dao, boolean authenticate, boolean iterateMask) {
51         super(dao, authenticate, iterateMask);
52     }
53
54     public void handleMapRequest(MapRequest request, IMapRequestResultHandler callback) {
55         if (dao == null) {
56             logger.warn("handleMapRequest called while dao is uninitialized");
57             return;
58         }
59         InetAddress itrRloc = MapRequestUtil.selectItrRloc(request);
60         logger.trace("Map-Request itrRloc is " + ((itrRloc == null) ? "MISSING" : itrRloc.toString()));
61         if (request.isPitr()) {
62             if (request.getEidRecord().size() > 0) {
63                 EidRecord eid = request.getEidRecord().get(0);
64                 Object result = getLocatorsSpecific(eid, ADDRESS_SUBKEY);
65                 if (result != null && result instanceof MappingServiceRLOCGroup) {
66                     MappingServiceRLOCGroup locatorsGroup = (MappingServiceRLOCGroup) result;
67                     if (locatorsGroup != null && locatorsGroup.getRecords().size() > 0) {
68                         callback.handleNonProxyMapRequest(request,
69                                 LispNotificationHelper.getInetAddressFromContainer(locatorsGroup.getRecords().get(0).getLispAddressContainer()));
70                     }
71                 }
72             }
73
74         } else {
75             MapReplyBuilder builder = new MapReplyBuilder();
76             builder.setEchoNonceEnabled(false);
77             builder.setProbe(false);
78             builder.setSecurityEnabled(false);
79             builder.setNonce(request.getNonce());
80             builder.setEidToLocatorRecord(new ArrayList<EidToLocatorRecord>());
81             for (EidRecord eid : request.getEidRecord()) {
82                 EidToLocatorRecordBuilder recordBuilder = new EidToLocatorRecordBuilder();
83                 recordBuilder.setRecordTtl(0);
84                 recordBuilder.setAction(Action.NoAction);
85                 recordBuilder.setAuthoritative(false);
86                 recordBuilder.setMapVersion((short) 0);
87                 recordBuilder.setMaskLength(eid.getMask());
88                 recordBuilder.setLispAddressContainer(eid.getLispAddressContainer());
89                 recordBuilder.setLocatorRecord(new ArrayList<LocatorRecord>());
90                 List<MappingServiceRLOCGroup> locators = getLocators(eid);
91                 if (locators != null && locators.size() > 0) {
92                     addLocatorGroups(recordBuilder, locators);
93                     if (itrRloc != null) {
94                         MappingServiceSubscriberRLOC subscriberRloc = new MappingServiceSubscriberRLOC(itrRloc);
95                         HashSet<MappingServiceSubscriberRLOC> subscribers = getSubscribers(eid.getLispAddressContainer(), eid.getMask());
96                         if (subscribers == null) {
97                             subscribers = new HashSet<MappingServiceSubscriberRLOC>();
98                         } else if (subscribers.contains(subscriberRloc)) {
99                             /* If there is an entry already for this subscriberRloc, remove it, so that it gets the new timestamp */
100                             subscribers.remove(subscriberRloc);
101                         }
102                         IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(eid.getLispAddressContainer(), eid.getMask());
103                         subscribers.add(subscriberRloc);
104                         dao.put(key, new MappingEntry<HashSet<MappingServiceSubscriberRLOC>>(SUBSCRIBERS_SUBKEY, subscribers));
105                     }
106                 } else {
107                     recordBuilder
108                             .setAction(org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidtolocatorrecords.EidToLocatorRecord.Action.NativelyForward);
109                     if (getPassword(eid.getLispAddressContainer(), eid.getMask()) != null) {
110                         recordBuilder.setRecordTtl(TTL_RLOC_TIMED_OUT);
111                     } else {
112                         recordBuilder.setRecordTtl(TTL_NO_RLOC_KNOWN);
113
114                     }
115                 }
116                 builder.getEidToLocatorRecord().add(recordBuilder.build());
117             }
118
119             callback.handleMapReply(builder.build());
120         }
121     }
122
123     private List<MappingServiceRLOCGroup> getLocators(EidRecord eid) {
124         IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(eid.getLispAddressContainer(), eid.getMask());
125         Map<String, ?> locators = dao.get(key);
126         List<MappingServiceRLOCGroup> result = aggregateLocators(locators);
127         if (shouldIterateMask() && result.isEmpty() && MaskUtil.isMaskable(key.getEID().getAddress())) {
128             result = findMaskLocators(key);
129         }
130         return result;
131     }
132
133     private List<MappingServiceRLOCGroup> aggregateLocators(Map<String, ?> locators) {
134         List<MappingServiceRLOCGroup> result = new ArrayList<MappingServiceRLOCGroup>();
135         if (locators != null) {
136             for (Object value : locators.values()) {
137                 if (value != null && value instanceof MappingServiceRLOCGroup) {
138                     if (!((MappingServiceRLOCGroup) value).getRecords().isEmpty()) {
139                         result.add((MappingServiceRLOCGroup) value);
140                     }
141                 }
142             }
143         }
144         return result;
145     }
146
147     private Object getLocatorsSpecific(EidRecord eid, String subkey) {
148         IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(eid.getLispAddressContainer(), eid.getMask());
149         Object locators = dao.getSpecific(key, subkey);
150         if (shouldIterateMask() && locators == null && MaskUtil.isMaskable(key.getEID().getAddress())) {
151             locators = findMaskLocatorsSpecific(key, subkey);
152         }
153         return locators;
154     }
155
156     private Object findMaskLocatorsSpecific(IMappingServiceKey key, String subkey) {
157         int mask = key.getMask();
158         while (mask > 0) {
159             key = MappingServiceKeyUtil.generateMappingServiceKey(
160                     new LispAddressContainerBuilder().setAddress(MaskUtil.normalize(key.getEID().getAddress(), mask)).build(), mask);
161             mask--;
162             Object locators = dao.getSpecific(key, subkey);
163             if (locators != null) {
164                 return locators;
165             }
166         }
167         return null;
168     }
169
170     private List<MappingServiceRLOCGroup> findMaskLocators(IMappingServiceKey key) {
171         int mask = key.getMask();
172         while (mask > 0) {
173             key = MappingServiceKeyUtil.generateMappingServiceKey(
174                     new LispAddressContainerBuilder().setAddress(MaskUtil.normalize(key.getEID().getAddress(), mask)).build(), mask);
175             mask--;
176             Map<String, ?> locators = dao.get(key);
177             if (locators != null) {
178                 List<MappingServiceRLOCGroup> result = aggregateLocators(locators);
179                 if (result != null && !result.isEmpty()) {
180                     return result;
181                 }
182             }
183         }
184         return null;
185     }
186
187     private void addLocatorGroups(EidToLocatorRecordBuilder recordBuilder, List<MappingServiceRLOCGroup> rlocs) {
188         for (MappingServiceRLOCGroup rloc : rlocs) {
189             addLocators(recordBuilder, rloc);
190             recordBuilder.setRecordTtl(rloc.getTtl());
191         }
192     }
193
194     private void addLocators(EidToLocatorRecordBuilder recordBuilder, MappingServiceRLOCGroup locatorObject) {
195         if (locatorObject == null) {
196             return;
197         }
198         try {
199             for (LocatorRecord record : locatorObject.getRecords()) {
200                 recordBuilder.getLocatorRecord().add(
201                         new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator()).setRlocProbed(record.isRlocProbed())
202                                 .setWeight(record.getWeight()).setPriority(record.getPriority()).setMulticastWeight(record.getMulticastWeight())
203                                 .setMulticastPriority(record.getMulticastPriority()).setRouted(true)
204                                 .setLispAddressContainer(record.getLispAddressContainer()).build());
205             }
206             recordBuilder.setAction(locatorObject.getAction());
207             recordBuilder.setAuthoritative(locatorObject.isAuthoritative());
208             recordBuilder.setRecordTtl(locatorObject.getTtl());
209         } catch (ClassCastException cce) {
210         }
211     }
212
213 }