X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=mappingservice%2Fsouthbound%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Flispflowmapping%2Fsouthbound%2Flisp%2FLispSouthboundHandler.java;h=2261b43149759cb70950684b7d879c47c97fc65c;hb=1af4913ccb1fbe8db5079c7b11911a0363e87798;hp=347a835ddb7d79d17c4210a14d00111836bb2dbe;hpb=072838407d20d5b1e45e1625289dc20f94c750ef;p=lispflowmapping.git diff --git a/mappingservice/southbound/src/main/java/org/opendaylight/lispflowmapping/southbound/lisp/LispSouthboundHandler.java b/mappingservice/southbound/src/main/java/org/opendaylight/lispflowmapping/southbound/lisp/LispSouthboundHandler.java index 347a835dd..2261b4314 100644 --- a/mappingservice/southbound/src/main/java/org/opendaylight/lispflowmapping/southbound/lisp/LispSouthboundHandler.java +++ b/mappingservice/southbound/src/main/java/org/opendaylight/lispflowmapping/southbound/lisp/LispSouthboundHandler.java @@ -8,6 +8,7 @@ package org.opendaylight.lispflowmapping.southbound.lisp; +import com.google.common.base.Preconditions; import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -19,7 +20,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; +import org.opendaylight.lispflowmapping.dsbackend.DataStoreBackEnd; +import org.opendaylight.lispflowmapping.inmemorydb.HashMapDb; +import org.opendaylight.lispflowmapping.lisp.authentication.ILispAuthentication; +import org.opendaylight.lispflowmapping.lisp.authentication.LispAuthenticationUtil; import org.opendaylight.lispflowmapping.lisp.serializer.MapNotifySerializer; import org.opendaylight.lispflowmapping.lisp.serializer.MapRegisterSerializer; import org.opendaylight.lispflowmapping.lisp.serializer.MapReplySerializer; @@ -28,6 +35,7 @@ import org.opendaylight.lispflowmapping.lisp.type.LispMessage; import org.opendaylight.lispflowmapping.lisp.util.ByteUtil; import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier; import org.opendaylight.lispflowmapping.lisp.util.MapRequestUtil; +import org.opendaylight.lispflowmapping.mapcache.SimpleMapCache; import org.opendaylight.lispflowmapping.southbound.LispSouthboundPlugin; import org.opendaylight.lispflowmapping.southbound.LispSouthboundStats; import org.opendaylight.lispflowmapping.southbound.lisp.cache.MapRegisterCache; @@ -35,7 +43,7 @@ import org.opendaylight.lispflowmapping.southbound.lisp.cache.MapRegisterPartial import org.opendaylight.lispflowmapping.southbound.lisp.exception.LispMalformedPacketException; import org.opendaylight.lispflowmapping.southbound.lisp.network.PacketHeader; import org.opendaylight.lispflowmapping.southbound.util.LispNotificationHelper; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.AddMappingBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.GotMapNotifyBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.GotMapReplyBuilder; @@ -55,44 +63,43 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.ma import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.map.register.cache.metadata.container.map.register.cache.metadata.EidLispAddressBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.map.register.cache.value.grouping.MapRegisterCacheValue; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.map.register.cache.value.grouping.MapRegisterCacheValueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.authkey.container.MappingAuthkey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItem; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.transport.address.TransportAddressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKey; import org.opendaylight.yangtools.yang.binding.Notification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ChannelHandler.Sharable public class LispSouthboundHandler extends SimpleChannelInboundHandler - implements ILispSouthboundService { - private final MapRegisterCache mapRegisterCache; - - /** - * How long is record supposed to be relevant. After this time record isn't valid. - * - * If you modify this value, please update the LispSouthboundServiceTest class too. - */ - private static final long CACHE_RECORD_TIMEOUT = 90000; + implements ILispSouthboundService, AutoCloseable { + private MapRegisterCache mapRegisterCache; + private boolean mapRegisterCacheEnabled = true; + private long mapRegisterCacheTimeout; + private DataBroker dataBroker; private NotificationPublishService notificationPublishService; + protected static final Logger LOG = LoggerFactory.getLogger(LispSouthboundHandler.class); + //TODO: think whether this field can be accessed through mappingservice or some other configuration parameter + private boolean authenticationEnabled = true; private final LispSouthboundPlugin lispSbPlugin; private LispSouthboundStats lispSbStats = null; + private SimpleMapCache smc; + private AuthenticationKeyDataListener authenticationKeyDataListener; + private DataStoreBackEnd dsbe; + private boolean isReadFromChannelEnabled = true; - public LispSouthboundHandler(LispSouthboundPlugin lispSbPlugin, final MapRegisterCache mapRegisterCache) { + public LispSouthboundHandler(LispSouthboundPlugin lispSbPlugin) { this.lispSbPlugin = lispSbPlugin; if (lispSbPlugin != null) { this.lispSbStats = lispSbPlugin.getStats(); } - this.mapRegisterCache = mapRegisterCache; - } - - public LispSouthboundHandler(LispSouthboundPlugin lispSbPlugin) { - this(lispSbPlugin, new MapRegisterCache()); - } - - public void setNotificationProvider(NotificationPublishService nps) { - this.notificationPublishService = nps; + this.mapRegisterCache = new MapRegisterCache(); + this.smc = new SimpleMapCache(new HashMapDb()); } public void handlePacket(DatagramPacket msg) { @@ -105,7 +112,7 @@ public class LispSouthboundHandler extends SimpleChannelInboundHandler artificialEntry = MapRegisterPartialDeserializer - .deserializePartially(inBuffer, sourceAddress); - final MapRegisterCacheKey cacheKey = artificialEntry == null ? null : artificialEntry.getKey(); - - final MapRegisterCacheValue cacheValue = resolveCacheValue(artificialEntry); + Map.Entry artificialEntry = null; + MapRegisterCacheKey cacheKey = null; + MapRegisterCacheValue cacheValue = null; + if (mapRegisterCacheEnabled) { + artificialEntry = MapRegisterPartialDeserializer.deserializePartially(inBuffer, sourceAddress); + cacheKey = artificialEntry == null ? null : artificialEntry.getKey(); + cacheValue = resolveCacheValue(artificialEntry); + } if (cacheValue != null) { - final MapRegisterCacheMetadata mapRegisterValue = cacheValue.getMapRegisterCacheMetadata(); - LOG.debug("Map register message site-ID: {} xTR-ID: {} from cache.", mapRegisterValue.getSiteId(), - mapRegisterValue.getXtrId()); - mapRegisterCache.refreshEntry(cacheKey); - sendNotificationIfPossible(createMappingKeepAlive(cacheValue)); - if (mapRegisterValue.isWantMapNotify()) { - sendMapNotifyMsg(inBuffer, sourceAddress, port); + MapRegisterCacheMetadata mapRegisterMeta = cacheValue.getMapRegisterCacheMetadata(); + LOG.debug("Map register message site-ID: {} xTR-ID: {} from cache.", mapRegisterMeta.getSiteId(), + mapRegisterMeta.getXtrId()); + cacheValue = refreshEntry(cacheKey); + if (cacheValue != null) { + sendNotificationIfPossible(createMappingKeepAlive(cacheValue)); + if (cacheValue.getMapRegisterCacheMetadata().isWantMapNotify()) { + sendMapNotifyMsg(inBuffer, sourceAddress, port, cacheValue); + } } + lispSbStats.incrementCacheHits(); } else { MapRegister mapRegister = MapRegisterSerializer.getInstance().deserialize(inBuffer, sourceAddress); - AddMappingBuilder addMappingBuilder = new AddMappingBuilder(); - addMappingBuilder.setMapRegister(LispNotificationHelper.convertMapRegister(mapRegister)); - TransportAddressBuilder transportAddressBuilder = new TransportAddressBuilder(); - transportAddressBuilder.setIpAddress(LispNotificationHelper.getIpAddressBinaryFromInetAddress( - sourceAddress)); - transportAddressBuilder.setPort(new PortNumber(port)); - addMappingBuilder.setTransportAddress(transportAddressBuilder.build()); - sendNotificationIfPossible(addMappingBuilder.build()); - if (artificialEntry != null) { - final MapRegisterCacheMetadataBuilder cacheMetadataBldNew = new MapRegisterCacheMetadataBuilder(); - cacheMetadataBldNew.setEidLispAddress(provideEidPrefixesFromMessage(mapRegister)); - cacheMetadataBldNew.setXtrId(mapRegister.getXtrId()); - cacheMetadataBldNew.setSiteId(mapRegister.getSiteId()); - cacheMetadataBldNew.setWantMapNotify(mapRegister.isWantMapNotify()); - cacheMetadataBldNew.setMergeEnabled(mapRegister.isMergeEnabled()); - cacheMetadataBldNew.setTimestamp(System.currentTimeMillis()); - - final MapRegisterCacheValueBuilder cacheValueBldNew = new MapRegisterCacheValueBuilder(); - cacheValueBldNew.setPacketData(artificialEntry.getValue()); - cacheValueBldNew.setMapRegisterCacheMetadata(cacheMetadataBldNew.build()); - - mapRegisterCache.addEntry(cacheKey, cacheValueBldNew.build()); + final MappingAuthkey mappingAuthkey = tryToAuthenticateMessage(mapRegister, inBuffer); + if (mappingAuthkey != null) { + AddMappingBuilder addMappingBuilder = new AddMappingBuilder(); + addMappingBuilder.setMapRegister(LispNotificationHelper.convertMapRegister(mapRegister)); + TransportAddressBuilder transportAddressBuilder = new TransportAddressBuilder(); + transportAddressBuilder.setIpAddress(LispNotificationHelper.getIpAddressBinaryFromInetAddress( + sourceAddress)); + transportAddressBuilder.setPort(new PortNumber(port)); + addMappingBuilder.setTransportAddress(transportAddressBuilder.build()); + sendNotificationIfPossible(addMappingBuilder.build()); + if (artificialEntry != null) { + final MapRegisterCacheMetadataBuilder cacheMetadataBldNew = new + MapRegisterCacheMetadataBuilder(); + cacheMetadataBldNew.setEidLispAddress(provideEidPrefixesFromMessage(mapRegister)); + cacheMetadataBldNew.setXtrId(mapRegister.getXtrId()); + cacheMetadataBldNew.setSiteId(mapRegister.getSiteId()); + cacheMetadataBldNew.setWantMapNotify(mapRegister.isWantMapNotify()); + cacheMetadataBldNew.setMergeEnabled(mapRegister.isMergeEnabled()); + cacheMetadataBldNew.setTimestamp(System.currentTimeMillis()); + + final MapRegisterCacheValueBuilder cacheValueBldNew = new MapRegisterCacheValueBuilder(); + cacheValueBldNew.setPacketData(artificialEntry.getValue()); + cacheValueBldNew.setMappingAuthkey(mappingAuthkey); + cacheValueBldNew.setMapRegisterCacheMetadata(cacheMetadataBldNew.build()); + + mapRegisterCache.addEntry(cacheKey, cacheValueBldNew.build()); + } } + lispSbStats.incrementCacheMisses(); } } catch (RuntimeException re) { throw new LispMalformedPacketException("Couldn't deserialize Map-Register (len=" @@ -230,13 +253,48 @@ public class LispSouthboundHandler extends SimpleChannelInboundHandler mapRegisterCacheTimeout; + if (shouldAuthKeyRefreshingStop) { + authenticationKeyDataListener.setAuthKeyRefreshing(false); + } else { + final MappingAuthkey mappingAuthkey = provideAuthenticateKey(mapRegisterCacheValue + .getMapRegisterCacheMetadata().getEidLispAddress()); + + final MapRegisterCacheValueBuilder newMapRegisterCacheValueBuilder = new MapRegisterCacheValueBuilder( + mapRegisterCacheValue); + final MapRegisterCacheMetadataBuilder newMapRegisterCacheMetadataBuilder = + new MapRegisterCacheMetadataBuilder(mapRegisterCacheValue.getMapRegisterCacheMetadata()); + + newMapRegisterCacheValueBuilder.setMappingAuthkey(mappingAuthkey); + newMapRegisterCacheValueBuilder.setMapRegisterCacheMetadata(newMapRegisterCacheMetadataBuilder.build()); + return newMapRegisterCacheValueBuilder.build(); + } + } + + return mapRegisterCacheValue; + + } + private MapRegisterCacheValue resolveCacheValue(Map.Entry entry) { if (entry != null) { final MapRegisterCacheValue mapRegisterCacheValue = mapRegisterCache.getEntry(entry.getKey()); if (mapRegisterCacheValue != null) { final long creationTime = mapRegisterCacheValue.getMapRegisterCacheMetadata().getTimestamp(); final long currentTime = System.currentTimeMillis(); - if (currentTime - creationTime > CACHE_RECORD_TIMEOUT) { + if (currentTime - creationTime > mapRegisterCacheTimeout) { mapRegisterCache.removeEntry(entry.getKey()); return null; } else if (Arrays.equals(mapRegisterCacheValue.getPacketData(), entry.getValue())) { @@ -262,17 +320,62 @@ public class LispSouthboundHandler extends SimpleChannelInboundHandler eidLispAddresses) { + MappingAuthkey firstAuthKey = null; + for (int i = 0; i < eidLispAddresses.size(); i++) { + final Eid eid = eidLispAddresses.get(i).getEid(); + if (i == 0) { + firstAuthKey = smc.getAuthenticationKey(eid); + } else { + final MappingAuthkey authKey = smc.getAuthenticationKey(eid); + if (!Objects.equals(firstAuthKey, authKey)) { + return null; + } + } + } + return firstAuthKey; + + } + + private void sendMapNotifyMsg(final ByteBuffer inBuffer, final InetAddress inetAddress, int portNumber, + MapRegisterCacheValue mapRegisterValue) { + if (mapRegisterValue.getMappingAuthkey().getKeyType() != null) { + ByteBuffer outBuffer = transformMapRegisterToMapNotify(inBuffer); + if (mapRegisterValue.getMappingAuthkey().getKeyType() != 0) { + outBuffer = calculateAndSetNewMAC(outBuffer, mapRegisterValue.getMappingAuthkey().getKeyString()); + } + outBuffer.position(0); + lispSbPlugin.handleSerializedLispBuffer(inetAddress, outBuffer, MessageType.MapNotify, portNumber); + } else { + LOG.error("Map-Register Cache: authentication succeeded, but can't find auth key for sending Map-Notify"); + } + } + + /** + * Calculates new message authentication code (MAC) for notify message. + */ + private ByteBuffer calculateAndSetNewMAC(final ByteBuffer buffer, final String authKey) { + final byte[] authenticationData = LispAuthenticationUtil.createAuthenticationData(buffer, authKey); + buffer.position(ILispAuthentication.MAP_REGISTER_AND_NOTIFY_AUTHENTICATION_POSITION); + buffer.put(authenticationData); + return buffer; } private ByteBuffer transformMapRegisterToMapNotify(final ByteBuffer buffer) { buffer.position(0); - //TODO: also reset of authentication data is required. other trello card is opened for this task. - byte[] byteReplacement = new byte[] {0x04, 0x00, 0x00}; + byte typeAndFlags = buffer.get(0); + // Shift the xTR-ID present and built for an RTR bits to their correct position + byte flags = (byte) ((typeAndFlags << 2) & 0x0F); + // Set control message type to 4 (Map-Notify) + byte type = 0x40; + // Combine the nibbles + typeAndFlags = (byte) (type | flags); + byte[] byteReplacement = new byte[] {typeAndFlags, 0x00, 0x00}; buffer.put(byteReplacement); + return buffer; } @@ -288,6 +391,50 @@ public class LispSouthboundHandler extends SimpleChannelInboundHandlerMethods pass through all records from map register message. For the EID of the first record it gets + * authentication key and does validation of authentication data again this authentication key. If it pass + * it just checks for remaining records (and its EID) whether they have the same authenticatin key stored in + * simple map cache (smc). + * + * @return Returns authentication key if all of EIDs have the same authentication key or null otherwise + */ + private MappingAuthkey tryToAuthenticateMessage(final MapRegister mapRegister, final ByteBuffer byteBuffer) { + if (!authenticationEnabled) { + return null; + } + + if (smc == null) { + LOG.debug("Simple map cache wasn't instantieted and set."); + return null; + } + + MappingAuthkey firstAuthKey = null; + final List mappingRecords = mapRegister.getMappingRecordItem(); + for (int i = 0; i < mappingRecords.size(); i++) { + final MappingRecordItem recordItem = mappingRecords.get(i); + final MappingRecord mappingRecord = recordItem.getMappingRecord(); + if (i == 0) { + firstAuthKey = smc.getAuthenticationKey(mappingRecord.getEid()); + if (!LispAuthenticationUtil.validate(mapRegister, byteBuffer, mappingRecord.getEid(), firstAuthKey)) { + return null; + } + } else { + final Eid eid = mappingRecord.getEid(); + final MappingAuthkey authKey = smc.getAuthenticationKey(eid); + if (!firstAuthKey.equals(authKey)) { + LOG.debug("Map register packet contained several eids. Authentication keys for first one and for " + + "{} are different.",LispAddressStringifier.getString(eid)); + return null; + } + } + } + return firstAuthKey; + } + + @SuppressWarnings("checkstyle:IllegalCatch") private void handleMapNotify(ByteBuffer inBuffer, InetAddress sourceAddress, int port) { try { MapNotify mapNotify = MapNotifySerializer.getInstance().deserialize(inBuffer); @@ -312,6 +459,7 @@ public class LispSouthboundHandler extends SimpleChannelInboundHandler authKeys = dsbe.getAllAuthenticationKeys(); + LOG.info("Restoring {} keys from datastore into southbound DAO", authKeys.size()); + + for (AuthenticationKey authKey : authKeys) { + final Eid key = authKey.getEid(); + final MappingAuthkey mappingAuthkey = authKey.getMappingAuthkey(); + LOG.debug("Adding authentication key '{}' with key-ID {} for {}", mappingAuthkey.getKeyString(), + mappingAuthkey.getKeyType(), + LispAddressStringifier.getString(key)); + smc.addAuthenticationKey(key, mappingAuthkey); + } + } + + public void init() { + Preconditions.checkNotNull(dataBroker); + Preconditions.checkNotNull(smc); + this.authenticationKeyDataListener = new AuthenticationKeyDataListener(dataBroker, smc); + dsbe = new DataStoreBackEnd(dataBroker); + } + + public void setIsMaster(boolean isReadFromChannelEnabled) { + this.isReadFromChannelEnabled = isReadFromChannelEnabled; + } + + public void setMapRegisterCacheTimeout(long mapRegisterCacheTimeout) { + this.mapRegisterCacheTimeout = mapRegisterCacheTimeout; + } }