blob: 1db6559e0c731b25957f8021b1ee6fca9dee74ac [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.lisp.ctl.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.onosproject.lisp.msg.protocols.DefaultLispEncapsulatedControl.DefaultEcmBuilder;
import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.DefaultMapRecordBuilder;
import org.onosproject.lisp.msg.protocols.DefaultLispMapReply.DefaultReplyBuilder;
import org.onosproject.lisp.msg.protocols.LispEidRecord;
import org.onosproject.lisp.msg.protocols.LispEncapsulatedControl;
import org.onosproject.lisp.msg.protocols.LispEncapsulatedControl.EcmBuilder;
import org.onosproject.lisp.msg.protocols.LispLocator;
import org.onosproject.lisp.msg.protocols.LispMapRecord;
import org.onosproject.lisp.msg.protocols.LispMapRecord.MapRecordBuilder;
import org.onosproject.lisp.msg.protocols.LispMapReply.ReplyBuilder;
import org.onosproject.lisp.msg.protocols.LispMapReplyAction;
import org.onosproject.lisp.msg.protocols.LispMapRequest;
import org.onosproject.lisp.msg.protocols.LispMapReply;
import org.onosproject.lisp.msg.protocols.LispMessage;
import org.onosproject.lisp.msg.types.LispAfiAddress;
import org.onosproject.lisp.msg.types.LispIpAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.List;
/**
* LISP map resolver class.
* Handles map-request message and acknowledges with map-reply message.
*/
public final class LispMapResolver {
private static final Logger log = LoggerFactory.getLogger(LispMapResolver.class);
private static final int ECM_DST_PORT = 4342;
private static final int NEGATIVE_REPLY_DST_PORT = 4342;
private static final int MAP_REPLY_RECORD_TTL = 15;
private static final short MAP_VERSION_NUMBER = 0;
private static final String NO_ITR_RLOCS_MSG =
"No ITR RLOC is found, cannot respond to ITR.";
private static final String NO_ETR_RLOCS_MSG =
"No ETR RLOC is found, cannot relay to ETR.";
private static final String NO_MAP_INFO_MSG = "Map information is not found.";
private LispMappingDatabase mapDb = LispMappingDatabase.getInstance();
// non-instantiable (except for our Singleton)
private LispMapResolver() {
}
static LispMapResolver getInstance() {
return SingletonHelper.INSTANCE;
}
/**
* Handles encapsulated control message and replies with map-reply message.
*
* @param message encapsulated control message
* @return map-reply message
*/
List<LispMessage> processMapRequest(LispMessage message) {
LispEncapsulatedControl ecm = (LispEncapsulatedControl) message;
LispMapRequest request = (LispMapRequest) ecm.getControlMessage();
List<LispMapRecord> mapReplyRecords =
mapDb.getMapRecordByEidRecords(request.getEids(), true);
List<LispMapRecord> mapRequestRecords =
mapDb.getMapRecordByEidRecords(request.getEids(), false);
if (mapReplyRecords.size() + mapRequestRecords.size() == 0) {
List<LispMessage> mapReplies = Lists.newArrayList();
// build natively-forward map reply messages based on map-request from ITR
ReplyBuilder replyBuilder = initMapReplyBuilder(request);
replyBuilder.withMapRecords(getNegativeMapRecords(request.getEids()));
LispMessage mapReply = replyBuilder.build();
mapReply.configSender(new InetSocketAddress(ecm.getSender().getAddress(),
NEGATIVE_REPLY_DST_PORT));
mapReplies.add(mapReply);
log.warn(NO_MAP_INFO_MSG);
} else {
if (!mapReplyRecords.isEmpty()) {
List<LispMessage> mapReplies = Lists.newArrayList();
// build map-reply message based on map-request from ITR
ReplyBuilder replyBuilder = initMapReplyBuilder(request);
replyBuilder.withMapRecords(mapReplyRecords);
List<InetSocketAddress> addresses =
getItrAddresses(request.getItrRlocs(),
ecm.innerUdp().getSourcePort());
addresses.forEach(address -> {
if (address != null) {
LispMapReply reply = replyBuilder.build();
reply.configSender(address);
mapReplies.add(reply);
} else {
log.warn(NO_ITR_RLOCS_MSG);
}
});
return mapReplies;
}
if (!mapRequestRecords.isEmpty()) {
List<LispMessage> ecms = Lists.newArrayList();
// re-encapsulate encapsulated control message from ITR
List<InetSocketAddress> addresses =
getEtrAddresses(mapRequestRecords, ECM_DST_PORT);
addresses.forEach(address -> {
if (address != null) {
LispEncapsulatedControl reencapEcm = cloneEcm(ecm);
reencapEcm.configSender(address);
ecms.add(reencapEcm);
} else {
log.warn(NO_ETR_RLOCS_MSG);
}
});
return ecms;
}
}
return ImmutableList.of();
}
/**
* Initializes MapReply builder without specifying map records.
*
* @param request received map request from ITR
* @return initialized MapReply builder
*/
private ReplyBuilder initMapReplyBuilder(LispMapRequest request) {
ReplyBuilder replyBuilder = new DefaultReplyBuilder();
replyBuilder.withNonce(request.getNonce());
replyBuilder.withIsEtr(false);
replyBuilder.withIsSecurity(false);
replyBuilder.withIsProbe(request.isProbe());
return replyBuilder;
}
/**
* Clones ECM from original ECM.
*
* @param ecm original ECM
* @return cloned ECM
*/
private LispEncapsulatedControl cloneEcm(LispEncapsulatedControl ecm) {
EcmBuilder ecmBuilder = new DefaultEcmBuilder();
ecmBuilder.innerLispMessage(ecm.getControlMessage());
ecmBuilder.isSecurity(ecm.isSecurity());
ecmBuilder.innerIpHeader(ecm.innerIpHeader());
ecmBuilder.innerUdpHeader(ecm.innerUdp());
return ecmBuilder.build();
}
/**
* Obtains a collection of map records with natively-forward action.
*
* @param eids endpoint identifier records
* @return a collection of map records with natively-forward action
*/
private List<LispMapRecord> getNegativeMapRecords(List<LispEidRecord> eids) {
List<LispMapRecord> mapRecords = Lists.newArrayList();
MapRecordBuilder recordBuilder = new DefaultMapRecordBuilder();
recordBuilder.withRecordTtl(MAP_REPLY_RECORD_TTL);
recordBuilder.withLocators(Lists.newArrayList());
recordBuilder.withIsAuthoritative(false);
recordBuilder.withMapVersionNumber(MAP_VERSION_NUMBER);
recordBuilder.withAction(LispMapReplyAction.NativelyForward);
eids.forEach(eid -> {
recordBuilder.withEidPrefixAfi(eid.getPrefix());
recordBuilder.withMaskLength(eid.getMaskLength());
mapRecords.add(recordBuilder.build());
});
return mapRecords;
}
/**
* Obtains a collection of valid ITR addresses with a port number specified.
* These addresses will be used to acknowledge map-reply to ITR.
*
* @param itrRlocs a collection of ITR RLOCs
* @param port port number
* @return a collection of valid ITR addresses with a port number specified
*/
private List<InetSocketAddress> getItrAddresses(List<LispAfiAddress> itrRlocs,
int port) {
List<InetSocketAddress> addresses = Lists.newArrayList();
for (LispAfiAddress itrRloc : itrRlocs) {
addresses.add(new InetSocketAddress(((LispIpAddress)
itrRloc).getAddress().toInetAddress(), port));
}
return addresses;
}
/**
* Obtains a collection of valid ETR addresses with a port number specified.
* These addresses will be used to relay map-request to ETR.
*
* @param mapRecords a collection of map records
* @param port port number
* @return a collection of valid ETR addresses with a port number specified
*/
private List<InetSocketAddress> getEtrAddresses(List<LispMapRecord> mapRecords,
int port) {
List<InetSocketAddress> addresses = Lists.newArrayList();
for (LispMapRecord mapRecord : mapRecords) {
// we only select the first locator record in all cases...
LispLocator locatorRecord = mapRecord.getLocators().get(0);
if (locatorRecord != null) {
addresses.add(new InetSocketAddress(((LispIpAddress)
locatorRecord.getLocatorAfi()).getAddress()
.toInetAddress(), port));
}
}
return addresses;
}
/**
* Prevents object instantiation from external.
*/
private static final class SingletonHelper {
private static final String ILLEGAL_ACCESS_MSG = "Should not instantiate this class.";
private static final LispMapResolver INSTANCE = new LispMapResolver();
private SingletonHelper() {
throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
}
}
}