/* * 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); } } }