2 * Copyright (c) 2014, 2017 Contextream, Inc. and others. All rights reserved.
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
9 package org.opendaylight.lispflowmapping.implementation.lisp;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Lists;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.apache.commons.lang3.exception.ExceptionUtils;
16 import org.opendaylight.lispflowmapping.interfaces.dao.Subscriber;
17 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapRequestResultHandler;
18 import org.opendaylight.lispflowmapping.interfaces.lisp.IMapResolverAsync;
19 import org.opendaylight.lispflowmapping.interfaces.lisp.ISmrNotificationListener;
20 import org.opendaylight.lispflowmapping.interfaces.lisp.SmrEvent;
21 import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService;
22 import org.opendaylight.lispflowmapping.lisp.type.MappingData;
23 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
24 import org.opendaylight.lispflowmapping.lisp.util.MappingRecordUtil;
25 import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4Afi;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4PrefixAfi;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv6Afi;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv6PrefixAfi;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.SimpleAddress;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.SourceDestKeyLcaf;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.Address;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.ExplicitLocatorPath;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.NoAddress;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.explicit.locator.path.explicit.locator.path.Hop;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.IpAddressBinary;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv4BinaryAfi;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv4PrefixBinaryAfi;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv6BinaryAfi;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv6PrefixBinaryAfi;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRequest;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItem;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecord;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapreplymessage.MapReplyBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRloc;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rloc.container.Rloc;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 public class MapResolver implements IMapResolverAsync {
57 private static final Logger LOG = LoggerFactory.getLogger(MapResolver.class);
59 private IMappingService mapService;
60 private boolean subscriptionService;
61 private String elpPolicy;
62 private IMapRequestResultHandler requestHandler;
63 private boolean authenticate = true;
64 private ISmrNotificationListener smrNotificationListener;
65 private static final int TTL_DELETE_MAPPING = 0;
67 public MapResolver(IMappingService mapService, boolean smr, String elpPolicy,
68 IMapRequestResultHandler requestHandler) {
69 Preconditions.checkNotNull(mapService);
70 this.subscriptionService = smr;
71 this.mapService = mapService;
72 this.elpPolicy = elpPolicy;
73 this.requestHandler = requestHandler;
76 public void handleMapRequest(MapRequest request) {
77 LOG.trace("Map-Request received: {}", request);
78 // SMRs and RLOC probes are directed towards xTRs and we're a Map-Resolver here, so ignore them
79 if (request.isSmr() != null && request.isSmr()) {
80 LOG.debug("Map-Resolver ignoring incoming SMR control message.");
83 if (request.isProbe() != null && request.isProbe()) {
84 LOG.debug("Map-Resolver ignoring incoming RLOC probe control message.");
87 if (request.isSmrInvoked()) {
88 LOG.debug("SMR-invoked request received.");
89 LOG.trace("Map-Request object: {}", request);
90 for (EidItem eidItem : request.getEidItem()) {
91 final SmrEvent event = new SmrEvent(
92 subscriberListFromItrRlocs(request.getItrRloc(), request.getSourceEid().getEid()),
95 smrNotificationListener.onSmrInvokedReceived(event);
99 if (request.getSourceEid() != null) {
100 srcEid = request.getSourceEid().getEid();
102 MapReplyBuilder replyBuilder = new MapReplyBuilder();
103 replyBuilder.setEchoNonceEnabled(false);
104 replyBuilder.setProbe(false);
105 replyBuilder.setSecurityEnabled(false);
106 replyBuilder.setNonce(request.getNonce());
107 replyBuilder.setMappingRecordItem(new ArrayList<>());
108 List<ItrRloc> itrRlocs = request.getItrRloc();
109 final IpAddressBinary sourceRloc = request.getSourceRloc();
111 for (EidItem eidRecord : request.getEidItem()) {
112 MappingData mappingData = mapService.getMapping(srcEid, eidRecord.getEid());
113 MappingRecord mapping;
114 if (mappingData == null) {
115 mapping = mapService.addNegativeMapping(eidRecord.getEid()).getRecord();
117 mapping = mappingData.getRecord();
120 if (itrRlocs != null && itrRlocs.size() != 0) {
121 if (subscriptionService && isValidSourceEidForSubscriber(srcEid)) {
122 final Rloc resolvedRloc = resolveRloc(itrRlocs, sourceRloc);
123 updateSubscribers(resolvedRloc, eidRecord.getEid(), mapping.getEid(),
124 srcEid, mapping.getRecordTtl());
126 mapping = updateLocators(mapping, itrRlocs);
128 mapping = fixIfNotSDRequest(mapping, eidRecord.getEid());
129 mapping = fixTtlIfSmrInvoked(request, mapping);
130 replyBuilder.getMappingRecordItem().add(new MappingRecordItemBuilder().setMappingRecord(mapping).build());
132 requestHandler.handleMapReply(replyBuilder.build());
135 private static boolean isEqualIpVersion(IpAddressBinary srcRloc, Rloc rloc) {
136 if (srcRloc.getIpv4AddressBinary() != null) {
137 if (rloc.getAddressType() == Ipv4Afi.class
138 || rloc.getAddressType() == Ipv4BinaryAfi.class
139 || rloc.getAddressType() == Ipv4PrefixAfi.class
140 || rloc.getAddressType() == Ipv4PrefixBinaryAfi.class) {
143 } else if (rloc.getAddressType() == Ipv6Afi.class
144 || rloc.getAddressType() == Ipv6BinaryAfi.class
145 || rloc.getAddressType() == Ipv6PrefixAfi.class
146 || rloc.getAddressType() == Ipv6PrefixBinaryAfi.class) {
152 private static boolean isValidSourceEidForSubscriber(Eid eid) {
153 if (eid == null || eid.getAddress() instanceof NoAddress) {
159 private Rloc resolveRloc(List<ItrRloc> itrRlocList, IpAddressBinary srcRloc) {
160 if (srcRloc == null) {
161 return itrRlocList.get(0).getRloc();
164 if (srcRloc.getIpv4AddressBinary() != null) {
165 srcRlocByte = srcRloc.getIpv4AddressBinary().getValue();
167 srcRlocByte = srcRloc.getIpv6AddressBinary().getValue();
170 Rloc equalIpvRloc = null;
171 for (ItrRloc itrRloc : itrRlocList) {
172 final Rloc rloc = itrRloc.getRloc();
173 final byte[] itrRlocByte = LispAddressUtil.ipAddressToByteArray(rloc.getAddress());
175 // return an Rloc equal to the source Rloc
176 if (itrRlocByte != null && LispAddressUtil.compareIpAddressByteArrays(srcRlocByte, itrRlocByte) == 0) {
179 // else lookup the first Rloc with identical Ip version
180 if (equalIpvRloc == null && isEqualIpVersion(srcRloc, rloc)) {
184 if (equalIpvRloc != null) {
187 // if none of the above, return the first Rloc
188 return itrRlocList.get(0).getRloc();
192 private void updateSubscribers(Rloc itrRloc, Eid reqEid, Eid mapEid, Eid srcEid, Integer recordTtl) {
193 Subscriber subscriber = new Subscriber(itrRloc, srcEid, Subscriber.recordTtlToSubscriberTime(recordTtl));
194 Eid subscribedEid = mapEid;
196 // If the eid in the matched mapping is SourceDest and the requested eid IS NOT then we subscribe itrRloc only
197 // to dst from the src/dst since that what's been requested. Note though that any updates to to the src/dst
198 // mapping will be pushed to dst as well (see sendSMRs in MapServer)
199 if (mapEid.getAddressType().equals(SourceDestKeyLcaf.class)
200 && !reqEid.getAddressType().equals(SourceDestKeyLcaf.class)) {
201 subscribedEid = SourceDestKeyHelper.getDstBinary(mapEid);
204 mapService.subscribe(subscriber, subscribedEid);
207 // Fixes mapping if request was for simple dst EID but the matched mapping is a SourceDest
208 private MappingRecord fixIfNotSDRequest(MappingRecord mapping, Eid dstEid) {
209 if (mapping.getEid().getAddress() instanceof SourceDestKey
210 && !(dstEid.getAddress() instanceof SourceDestKey)) {
211 return new MappingRecordBuilder(mapping).setEid(
212 SourceDestKeyHelper.getDstBinary(mapping.getEid())).build();
217 // When an SMR-invoked Map-Request is asking for a mapping that is negative, it is most likely an attempt to delete
219 private MappingRecord fixTtlIfSmrInvoked(MapRequest request, MappingRecord mapping) {
220 if (request.isSmrInvoked() && MappingRecordUtil.isNegativeMapping(mapping)) {
221 return new MappingRecordBuilder(mapping).setRecordTtl(TTL_DELETE_MAPPING).build();
226 private boolean locatorsNeedFixing(List<LocatorRecord> locatorRecords) {
227 // no locators - no fixing needed ;)
228 if (locatorRecords == null) {
232 for (LocatorRecord record : locatorRecords) {
233 if (record.getRloc().getAddress() instanceof ExplicitLocatorPath) {
240 // Process locators according to configured policy
241 private MappingRecord updateLocators(MappingRecord mapping, List<ItrRloc> itrRlocs) {
242 // no fixing if elpPolicy is default
243 if (elpPolicy.equalsIgnoreCase("default")) {
247 List<LocatorRecord> locatorRecords = mapping.getLocatorRecord();
249 // if no updated is needed, just return the mapping
250 if (!locatorsNeedFixing(locatorRecords)) {
254 MappingRecordBuilder recordBuilder = new MappingRecordBuilder(mapping);
255 recordBuilder.setLocatorRecord(new ArrayList<LocatorRecord>());
257 for (LocatorRecord record : locatorRecords) {
258 Rloc container = record.getRloc();
260 // For non-ELP RLOCs, or when ELP policy is default, or itrRlocs is null, just add the locator and be
262 if ((!(container.getAddress() instanceof ExplicitLocatorPath))
263 || elpPolicy.equalsIgnoreCase("default") || itrRlocs == null) {
264 recordBuilder.getLocatorRecord().add(
265 new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator())
266 .setRlocProbed(record.isRlocProbed()).setWeight(record.getWeight())
267 .setPriority(record.getPriority()).setMulticastWeight(record.getMulticastWeight())
268 .setMulticastPriority(record.getMulticastPriority()).setRouted(record.isRouted())
269 .setRloc(container).setLocatorId(record.getLocatorId()).build());
273 ExplicitLocatorPath teAddress = ((ExplicitLocatorPath) container.getAddress());
274 SimpleAddress nextHop = getNextELPHop(teAddress, itrRlocs);
275 if (nextHop != null) {
276 java.lang.Short priority = record.getPriority();
277 if (elpPolicy.equalsIgnoreCase("both")) {
278 recordBuilder.getLocatorRecord().add(
279 new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator())
280 .setRlocProbed(record.isRlocProbed()).setWeight(record.getWeight())
281 .setPriority(record.getPriority())
282 .setMulticastWeight(record.getMulticastWeight())
283 .setMulticastPriority(record.getMulticastPriority())
284 .setRouted(record.isRouted()).setRloc(container)
285 .setLocatorId(record.getLocatorId()).build());
286 // Make the priority of the added simple locator lower so that ELP is used by default if
287 // the xTR understands ELP. Exclude 255, since that means don't use for unicast forwarding
288 // XXX Complex cases like several ELPs with different priorities are not handled
289 if (priority != 254 || priority != 255) {
293 // Build and add the simple RLOC
294 recordBuilder.getLocatorRecord().add(
295 new LocatorRecordBuilder().setLocalLocator(record.isLocalLocator())
296 .setRlocProbed(record.isRlocProbed()).setWeight(record.getWeight())
297 .setPriority(priority).setMulticastWeight(record.getMulticastWeight())
298 .setMulticastPriority(record.getMulticastPriority()).setRouted(record.isRouted())
299 .setRloc(LispAddressUtil.toRloc(nextHop))
300 .setLocatorId(record.getLocatorId()).build());
303 } catch (ClassCastException cce) {
304 LOG.error("Class Cast Exception while building EidToLocatorRecord: {}", ExceptionUtils.getStackTrace(cce));
307 return recordBuilder.build();
310 private SimpleAddress getNextELPHop(ExplicitLocatorPath elp, List<ItrRloc> itrRlocs) {
311 SimpleAddress nextHop = null;
312 List<Hop> hops = elp.getExplicitLocatorPath().getHop();
314 if (hops != null && hops.size() > 0) {
315 // By default we return the first hop
316 nextHop = hops.get(0).getAddress();
317 for (Hop hop : hops) {
318 Address hopAddress = LispAddressUtil.addressFromSimpleAddress(hop.getAddress());
319 for (ItrRloc itrRloc : itrRlocs) {
320 if (itrRloc.getRloc().getAddress().equals(hopAddress)) {
321 int iterator = hops.indexOf(hop);
322 if (iterator < hops.size() - 1) {
323 nextHop = hops.get(iterator + 1).getAddress();
334 private static List<Subscriber> subscriberListFromItrRlocs(List<ItrRloc> itrRlocs, Eid srcEid) {
335 List<Subscriber> subscriberList = Lists.newArrayList();
336 for (ItrRloc itrRloc : itrRlocs) {
337 subscriberList.add(new Subscriber(itrRloc.getRloc(), srcEid, Subscriber.DEFAULT_SUBSCRIBER_TIMEOUT));
339 return subscriberList;
343 public void setSubscriptionService(boolean smr) {
344 subscriptionService = smr;
348 public void setElpPolicy(String elpPolicy) {
349 this.elpPolicy = elpPolicy;
353 public void setShouldAuthenticate(boolean shouldAuthenticate) {
354 this.authenticate = shouldAuthenticate;
358 public void setSmrNotificationListener(ISmrNotificationListener smrNotificationListener) {
359 this.smrNotificationListener = smrNotificationListener;