Bug 3813: Fix elp handling in map-replies
[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.HashSet;
13 import java.util.List;
14 import java.util.Map.Entry;
15
16 import org.opendaylight.lispflowmapping.implementation.config.ConfigIni;
17 import org.opendaylight.lispflowmapping.implementation.dao.MappingServiceKeyUtil;
18 import org.opendaylight.lispflowmapping.implementation.util.DAOMappingUtil;
19 import org.opendaylight.lispflowmapping.implementation.util.LispAFIConvertor;
20 import org.opendaylight.lispflowmapping.implementation.util.LispAddressStringifier;
21 import org.opendaylight.lispflowmapping.implementation.util.LispNotificationHelper;
22 import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
23 import org.opendaylight.lispflowmapping.interfaces.dao.IMappingServiceKey;
24 import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry;
25 import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceRLOCGroup;
26 import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceSubscriberRLOC;
27 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapRequestResultHandler;
28 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapResolverAsync;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.EidToLocatorRecord.Action;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.LcafTrafficEngineeringAddress;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.LispAFIAddress;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.MapRequest;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.eidrecords.EidRecord;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.eidtolocatorrecords.EidToLocatorRecord;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.eidtolocatorrecords.EidToLocatorRecordBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lcaftrafficengineeringaddress.Hops;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispaddress.LispAddressContainer;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispaddress.lispaddresscontainer.address.LcafTrafficEngineering;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.locatorrecords.LocatorRecord;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.locatorrecords.LocatorRecordBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.mapreplymessage.MapReplyBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.maprequest.ItrRloc;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 public class MapResolver extends AbstractLispComponent implements IMapResolverAsync {
47
48     private static final int TTL_RLOC_TIMED_OUT = 1;
49     private static final int TTL_NO_RLOC_KNOWN = 15;
50     protected static final Logger LOG = LoggerFactory.getLogger(MapResolver.class);
51
52     private static final ConfigIni configIni = new ConfigIni();
53     private static final String elpPolicy = configIni.getElpPolicy();
54
55     public MapResolver(ILispDAO dao) {
56         this(dao, true, true);
57     }
58
59     public MapResolver(ILispDAO dao, boolean authenticate, boolean iterateMask) {
60         super(dao, authenticate, iterateMask);
61     }
62
63     public void handleMapRequest(MapRequest request, boolean smr, IMapRequestResultHandler callback) {
64         if (dao == null) {
65             LOG.warn("handleMapRequest called while dao is uninitialized");
66             return;
67         }
68         if (request.isPitr()) {
69             if (request.getEidRecord().size() > 0) {
70                 EidRecord eid = request.getEidRecord().get(0);
71                 Object result = DAOMappingUtil.getLocatorsSpecificByEidRecord(eid, dao, ADDRESS_SUBKEY, shouldIterateMask());
72                 if (result != null && result instanceof MappingServiceRLOCGroup) {
73                     MappingServiceRLOCGroup locatorsGroup = (MappingServiceRLOCGroup) result;
74                     if (locatorsGroup != null && locatorsGroup.getRecords().size() > 0) {
75                         callback.handleNonProxyMapRequest(request,
76                                 LispNotificationHelper.getTransportAddressFromContainer(locatorsGroup.getRecords().get(0).getLispAddressContainer()));
77                     }
78                 }
79             }
80
81         } else {
82             LispAFIAddress srcEid = null;
83             if (request.getSourceEid() != null) {
84                 srcEid = LispAFIConvertor.toAFI(request.getSourceEid().getLispAddressContainer());
85             }
86             MapReplyBuilder builder = new MapReplyBuilder();
87             builder.setEchoNonceEnabled(false);
88             builder.setProbe(false);
89             builder.setSecurityEnabled(false);
90             builder.setNonce(request.getNonce());
91             builder.setEidToLocatorRecord(new ArrayList<EidToLocatorRecord>());
92             for (EidRecord eid : request.getEidRecord()) {
93                 EidToLocatorRecordBuilder recordBuilder = new EidToLocatorRecordBuilder();
94                 Entry<IMappingServiceKey, List<MappingServiceRLOCGroup>> mapping = DAOMappingUtil.getMapping(srcEid, eid, dao);
95                 recordBuilder.setRecordTtl(0);
96                 recordBuilder.setAction(Action.NoAction);
97                 recordBuilder.setAuthoritative(false);
98                 recordBuilder.setMapVersion((short) 0);
99                 recordBuilder.setMaskLength((short) mapping.getKey().getMask());
100                 recordBuilder.setLispAddressContainer(mapping.getKey().getEID());
101                 recordBuilder.setLocatorRecord(new ArrayList<LocatorRecord>());
102                 List<MappingServiceRLOCGroup> locators = mapping.getValue();
103                 if (locators != null && locators.size() > 0) {
104                     List<ItrRloc> itrRlocs = request.getItrRloc();
105                     addLocatorGroups(recordBuilder, locators, itrRlocs);
106                     if (itrRlocs != null && itrRlocs.size() > 0) {
107                         LispAddressContainer itrRloc = itrRlocs.get(0).getLispAddressContainer();
108                         MappingServiceSubscriberRLOC subscriberRloc = new MappingServiceSubscriberRLOC(itrRloc);
109                         HashSet<MappingServiceSubscriberRLOC> subscribers = getSubscribers(mapping.getKey().getEID(), mapping.getKey().getMask());
110                         if (subscribers == null) {
111                             subscribers = new HashSet<MappingServiceSubscriberRLOC>();
112                         } else if (subscribers.contains(subscriberRloc)) {
113                             /*
114                              * If there is an entry already for this
115                              * subscriberRloc, remove it, so that it gets the
116                              * new timestamp
117                              */
118                             subscribers.remove(subscriberRloc);
119                         }
120                         if (smr) {
121                             IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(mapping.getKey().getEID(),
122                                     mapping.getKey().getMask());
123                             LOG.trace("Adding new subscriber: " + subscriberRloc.toString());
124                             subscribers.add(subscriberRloc);
125                             dao.put(key, new MappingEntry<HashSet<MappingServiceSubscriberRLOC>>(SUBSCRIBERS_SUBKEY, subscribers));
126                         }
127                     }
128                 } else {
129                     recordBuilder.setAction(Action.NativelyForward);
130                     if (shouldAuthenticate() && getPassword(eid.getLispAddressContainer(), eid.getMask()) != null) {
131                         recordBuilder.setRecordTtl(TTL_RLOC_TIMED_OUT);
132                     } else {
133                         recordBuilder.setRecordTtl(TTL_NO_RLOC_KNOWN);
134
135                     }
136                 }
137                 builder.getEidToLocatorRecord().add(recordBuilder.build());
138             }
139
140             callback.handleMapReply(builder.build());
141         }
142     }
143
144     private void addLocatorGroups(EidToLocatorRecordBuilder recordBuilder, List<MappingServiceRLOCGroup> rlocs, List<ItrRloc> itrRlocs) {
145         for (MappingServiceRLOCGroup rloc : rlocs) {
146             addLocators(recordBuilder, rloc, itrRlocs);
147             recordBuilder.setRecordTtl(rloc.getTtl());
148         }
149     }
150
151     private void addLocators(EidToLocatorRecordBuilder recordBuilder, MappingServiceRLOCGroup locatorObject, List<ItrRloc> itrRlocs) {
152         if (locatorObject == null) {
153             return;
154         }
155
156         recordBuilder.setAction(locatorObject.getAction());
157         recordBuilder.setAuthoritative(locatorObject.isAuthoritative());
158         recordBuilder.setRecordTtl(locatorObject.getTtl());
159
160         try {
161             for (LocatorRecord record : locatorObject.getRecords()) {
162                 LispAddressContainer container = record.getLispAddressContainer();
163
164                 // For non-ELP RLOCs, or when ELP policy is default, just add the locator and be done
165                 if ((!(container.getAddress() instanceof LcafTrafficEngineering)) || elpPolicy.equalsIgnoreCase("default")) {
166                     recordBuilder.getLocatorRecord().add(
167                             new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator()).setRlocProbed(record.isRlocProbed())
168                                     .setWeight(record.getWeight()).setPriority(record.getPriority()).setMulticastWeight(record.getMulticastWeight())
169                                     .setMulticastPriority(record.getMulticastPriority()).setRouted(true)
170                                     .setLispAddressContainer(container).setName(LispAddressStringifier.getString(container)).build());
171                                                                     // TODO HACK ^^^^^^^^^^^^^
172                     continue;
173                 }
174
175                 LcafTrafficEngineeringAddress teAddress = ((LcafTrafficEngineering) container.getAddress()).getLcafTrafficEngineeringAddr();
176                 LispAddressContainer nextHop = getNextELPHop(teAddress, itrRlocs);
177                 if (nextHop != null) {
178                     java.lang.Short priority = record.getPriority();
179                     if (elpPolicy.equalsIgnoreCase("both")) {
180                         recordBuilder.getLocatorRecord().add(
181                                 new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator()).setRlocProbed(record.isRlocProbed())
182                                         .setWeight(record.getWeight()).setPriority(record.getPriority()).setMulticastWeight(record.getMulticastWeight())
183                                         .setMulticastPriority(record.getMulticastPriority()).setRouted(true)
184                                         .setLispAddressContainer(container).build());
185                         // Make the priority of the added simple locator lower so that ELP is used by default if
186                         // the xTR understands ELP.  Exclude 255, since that means don't use for unicast forwarding
187                         // XXX Complex cases like several ELPs with different priorities are not handled
188                         if (priority != 254 || priority !=255) {
189                             priority++;
190                         }
191                     }
192                     // Build and add the simple RLOC
193                     recordBuilder.getLocatorRecord().add(
194                             new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator()).setRlocProbed(record.isRlocProbed())
195                             .setWeight(record.getWeight()).setPriority(priority).setMulticastWeight(record.getMulticastWeight())
196                             .setMulticastPriority(record.getMulticastPriority()).setRouted(true)
197                             .setLispAddressContainer(nextHop).build());
198                 }
199             }
200         } catch (ClassCastException cce) {
201             LOG.error("Class Cast Exception while building EidToLocatorRecord: {}", cce);
202         }
203     }
204
205     private LispAddressContainer getNextELPHop(LcafTrafficEngineeringAddress elp, List<ItrRloc> itrRlocs) {
206         LispAddressContainer nextHop = null;
207         List<Hops> hops = elp.getHops();
208
209         if (hops != null && hops.size() > 0) {
210             // By default we return the first hop
211             nextHop = LispAFIConvertor.toContainer(LispAFIConvertor.toAFIfromPrimitive(hops.get(0).getHop().getPrimitiveAddress()));
212             for (Hops hop : hops) {
213                 LispAddressContainer hopContainer = LispAFIConvertor.toContainer(LispAFIConvertor.toAFIfromPrimitive(hop.getHop().getPrimitiveAddress()));
214                 for (ItrRloc itrRloc : itrRlocs) {
215                     if (itrRloc.getLispAddressContainer().equals(hopContainer)) {
216                         int i = hops.indexOf(hop);
217                         if (i < hops.size() - 1) {
218                             nextHop = LispAFIConvertor.toContainer(LispAFIConvertor.toAFIfromPrimitive(hops.get(i+1).getHop().getPrimitiveAddress()));
219                             return nextHop;
220                         }
221                     }
222                 }
223             }
224         }
225
226         return nextHop;
227     }
228
229 }