X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=mappingservice%2Fimplementation%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Flispflowmapping%2Fimplementation%2Flisp%2FMapServer.java;h=36f0a292a6db2688bdc183f4eeb15e9b1b3ada77;hb=6bbdfee05cc5e06801bee2e6634ef17de9ec41da;hp=a2fb2720d7d91d1d536c23421949bc9536f2e7bf;hpb=e2dba25d283216ec49c29b6adc2a63c68f5ecde9;p=lispflowmapping.git diff --git a/mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapServer.java b/mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapServer.java index a2fb2720d..36f0a292a 100644 --- a/mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapServer.java +++ b/mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapServer.java @@ -13,343 +13,264 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Enumeration; -import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.opendaylight.lispflowmapping.implementation.authentication.LispAuthenticationUtil; +import org.opendaylight.controller.md.sal.binding.api.NotificationService; import org.opendaylight.lispflowmapping.implementation.config.ConfigIni; -import org.opendaylight.lispflowmapping.implementation.dao.MappingServiceKeyUtil; -import org.opendaylight.lispflowmapping.implementation.util.DAOMappingUtil; -import org.opendaylight.lispflowmapping.implementation.util.LispAFIConvertor; -import org.opendaylight.lispflowmapping.implementation.util.MapNotifyBuilderHelper; -import org.opendaylight.lispflowmapping.inmemorydb.HashMapDb; -import org.opendaylight.lispflowmapping.implementation.util.MaskUtil; -import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO; -import org.opendaylight.lispflowmapping.interfaces.dao.IMappingServiceKey; -import org.opendaylight.lispflowmapping.interfaces.dao.MappingEntry; -import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceRLOCGroup; -import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceSubscriberRLOC; +import org.opendaylight.lispflowmapping.interfaces.dao.SubKeys; +import org.opendaylight.lispflowmapping.interfaces.dao.SubscriberRLOC; import org.opendaylight.lispflowmapping.interfaces.lisp.IMapNotifyHandler; import org.opendaylight.lispflowmapping.interfaces.lisp.IMapServerAsync; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.LispAFIAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.MapRegister; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.eidrecords.EidRecordBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.eidtolocatorrecords.EidToLocatorRecord; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.eidtolocatorrecords.EidToLocatorRecordBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispaddress.LispAddressContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispaddress.lispaddresscontainer.Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispaddress.lispaddresscontainer.address.LcafKeyValue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispaddress.lispaddresscontainer.address.LcafSourceDest; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.lispsimpleaddress.primitiveaddress.DistinguishedName; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.locatorrecords.LocatorRecord; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.mapnotifymessage.MapNotifyBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.maprequest.ItrRloc; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.maprequest.ItrRlocBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.maprequest.SourceEidBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.control.plane.rev150314.maprequestnotification.MapRequestBuilder; +import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService; +import org.opendaylight.lispflowmapping.lisp.type.LispMessage; +import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier; +import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil; +import org.opendaylight.lispflowmapping.lisp.util.MapNotifyBuilderHelper; +import org.opendaylight.lispflowmapping.lisp.util.MapRequestUtil; +import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper; +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.lisp.address.types.rev151105.lisp.address.address.SourceDestKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.IpAddressBinary; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRegister; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItem; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItemBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapnotifymessage.MapNotifyBuilder; +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.container.MappingRecordBuilder; +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.mapping.record.list.MappingRecordItemBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequestnotification.MapRequestBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.transport.address.TransportAddress; +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.MappingChange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingChanged; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.OdlMappingserviceListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MapServer extends AbstractLispComponent implements IMapServerAsync { +import com.google.common.base.Preconditions; - protected static final Logger LOG = LoggerFactory.getLogger(MapServer.class); - - private static final ConfigIni configIni = new ConfigIni(); - private static final boolean overwriteConfig = configIni.mappingOverwriteIsSet(); - private boolean overwrite; - - public MapServer(ILispDAO dao) { - this(dao, overwriteConfig); - } +public class MapServer implements IMapServerAsync, OdlMappingserviceListener { - public MapServer(ILispDAO dao, boolean overwrite) { - this(dao, overwrite, true); - } + protected static final Logger LOG = LoggerFactory.getLogger(MapServer.class); + private IMappingService mapService; + private boolean subscriptionService; + private IMapNotifyHandler notifyHandler; + private NotificationService notificationService; - public MapServer(ILispDAO dao, boolean overwrite, boolean authenticate) { - this(dao, overwrite, authenticate, true); + public MapServer(IMappingService mapService, boolean subscriptionService, + IMapNotifyHandler notifyHandler, NotificationService notificationService) { + Preconditions.checkNotNull(mapService); + this.mapService = mapService; + this.subscriptionService = subscriptionService; + this.notifyHandler = notifyHandler; + this.notificationService = notificationService; + if (notificationService != null) { + notificationService.registerNotificationListener(this); + } } - public MapServer(ILispDAO dao, boolean overwrite, boolean authenticate, boolean iterateAuthenticationMask) { - super(dao, authenticate, iterateAuthenticationMask); - this.overwrite = overwrite; + @Override + public void setSubscriptionService(boolean subscriptionService) { + this.subscriptionService = subscriptionService; } - private static InetAddress getLocalAddress() { - try { - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface current = interfaces.nextElement(); - LOG.debug("Interface " + current.toString()); - if (!current.isUp() || current.isLoopback() || current.isVirtual()) - continue; - Enumeration addresses = current.getInetAddresses(); - while (addresses.hasMoreElements()) { - InetAddress current_addr = addresses.nextElement(); - // Skip loopback and link local addresses - if (current_addr.isLoopbackAddress() || current_addr.isLinkLocalAddress()) - continue; - LOG.debug(current_addr.getHostAddress()); - return current_addr; - } - } - } catch (SocketException se) { - } - return null; - } + @SuppressWarnings("unchecked") + public void handleMapRegister(MapRegister mapRegister) { + boolean mappingUpdated = false; + boolean merge = ConfigIni.getInstance().mappingMergeIsSet() && mapRegister.isMergeEnabled(); + Set subscribers = null; + MappingRecord oldMapping; - private static MapRequestBuilder buildSMR(LispAddressContainer srcEid) { - MapRequestBuilder builder = new MapRequestBuilder(); - builder.setAuthoritative(false); - builder.setMapDataPresent(false); - builder.setPitr(false); - builder.setProbe(false); - builder.setSmr(true); - builder.setSmrInvoked(false); + for (MappingRecordItem record : mapRegister.getMappingRecordItem()) { + MappingRecord mapping = record.getMappingRecord(); - builder.setEidRecord(new ArrayList()); - // The address stored in the SMR's EID record is used as Source EID in the SMR-invoked Map-Request. To - // ensure consistent behavior it is set to the value used to originally request a given mapping - builder.getEidRecord().add(new EidRecordBuilder() - .setMask((short)MaskUtil.getMaxMask(LispAFIConvertor.toAFI(srcEid))) - .setLispAddressContainer(srcEid).build()); - builder.setItrRloc(new ArrayList()); - builder.getItrRloc().add(new ItrRlocBuilder().setLispAddressContainer(LispAFIConvertor.toContainer(getLocalAddress())).build()); - builder.setMapReply(null); - builder.setNonce(new Random().nextLong()); + oldMapping = (MappingRecord) mapService.getMapping(MappingOrigin.Southbound, mapping.getEid()); + mapService.addMapping(MappingOrigin.Southbound, mapping.getEid(), getSiteId(mapRegister), mapping, merge); - return builder; - } + if (subscriptionService) { + MappingRecord newMapping = merge ? + (MappingRecord) mapService.getMapping(MappingOrigin.Southbound, mapping.getEid()) : mapping; - public void handleMapRegister(MapRegister mapRegister, boolean smr, IMapNotifyHandler callback) { - if (dao == null) { - LOG.warn("handleMapRegister called while dao is uninitialized"); - } else { - boolean failed = false; - String password = null; - for (EidToLocatorRecord eidRecord : mapRegister.getEidToLocatorRecord()) { - if (shouldAuthenticate()) { - password = getPassword(eidRecord.getLispAddressContainer(), eidRecord.getMaskLength()); - if (!LispAuthenticationUtil.validate(mapRegister, password)) { - LOG.warn("Authentication failed"); - failed = true; - break; + if (mappingChanged(oldMapping, newMapping)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Mapping update occured for {} SMRs will be sent for its subscribers.", + LispAddressStringifier.getString(mapping.getEid())); } - } - boolean mappingChanged = saveRlocs(eidRecord, smr); - if (smr && mappingChanged) { - sendSmrs(eidRecord, callback); + subscribers = getSubscribers(mapping.getEid()); + sendSmrs(mapping, subscribers); + mappingUpdated = true; } } - if (!failed) { - MapNotifyBuilder builder = new MapNotifyBuilder(); - if (BooleanUtils.isTrue(mapRegister.isWantMapNotify())) { - LOG.trace("MapRegister wants MapNotify"); - MapNotifyBuilderHelper.setFromMapRegister(builder, mapRegister); - if (shouldAuthenticate()) { - builder.setAuthenticationData(LispAuthenticationUtil.createAuthenticationData(builder.build(), password)); + } + if (BooleanUtils.isTrue(mapRegister.isWantMapNotify())) { + LOG.trace("MapRegister wants MapNotify"); + MapNotifyBuilder builder = new MapNotifyBuilder(); + List rlocs = null; + if (merge) { + Set notifyRlocs = new HashSet(); + List mergedMappings = new ArrayList(); + for (MappingRecordItem record : mapRegister.getMappingRecordItem()) { + MappingRecord mapping = record.getMappingRecord(); + MappingRecord currentRecord = (MappingRecord) mapService.getMapping(MappingOrigin.Southbound, + mapping.getEid()); + mergedMappings.add(new MappingRecordItemBuilder().setMappingRecord(currentRecord).build()); + Set sourceRlocs = (Set) mapService.getData( + MappingOrigin.Southbound, mapping.getEid(), SubKeys.SRC_RLOCS); + if (sourceRlocs != null) { + notifyRlocs.addAll(sourceRlocs); } - callback.handleMapNotify(builder.build()); } - } - } - } - - public boolean saveRlocs(EidToLocatorRecord eidRecord, boolean checkForChanges) { - Map rlocGroups = new HashMap(); - if (eidRecord.getLocatorRecord() != null) { - for (LocatorRecord locatorRecord : eidRecord.getLocatorRecord()) { - String subkey = getAddressKey(locatorRecord.getLispAddressContainer().getAddress()); - if (!rlocGroups.containsKey(subkey)) { - rlocGroups.put(subkey, new MappingServiceRLOCGroup(eidRecord.getRecordTtl(), eidRecord.getAction(), eidRecord.isAuthoritative())); + MapNotifyBuilderHelper.setFromMapRegisterAndMappingRecordItems(builder, mapRegister, mergedMappings); + // send map-notify to merge group only when mapping record is changed + if (mappingUpdated) { + rlocs = getTransportAddresses(notifyRlocs); } - rlocGroups.get(subkey).addRecord(locatorRecord); - } - } else { - rlocGroups.put(ADDRESS_SUBKEY, new MappingServiceRLOCGroup(eidRecord.getRecordTtl(), eidRecord.getAction(), eidRecord.isAuthoritative())); - } - List> entries = new ArrayList<>(); - for (String subkey : rlocGroups.keySet()) { - entries.add(new MappingEntry<>(subkey, rlocGroups.get(subkey))); - } - - if (eidRecord.getLispAddressContainer().getAddress() instanceof LcafSourceDest) { - Entry> oldMapping= null, newMapping = null; - LispAFIAddress srcAddr = getSrcForLcafSrcDst(eidRecord.getLispAddressContainer()); - LispAFIAddress dstAddr = getDstForLcafSrcDst(eidRecord.getLispAddressContainer()); - short srcMask = getSrcMaskForLcafSrcDst(eidRecord.getLispAddressContainer()); - short dstMask = getDstMaskForLcafSrcDst(eidRecord.getLispAddressContainer()); - - if (checkForChanges) { - oldMapping = DAOMappingUtil.getMappingExact(srcAddr, dstAddr, srcMask, dstMask, dao); - } - IMappingServiceKey dstKey = MappingServiceKeyUtil.generateMappingServiceKey(dstAddr, dstMask); - ILispDAO srcDstDao = (ILispDAO) dao.getSpecific(dstKey, LCAF_SRCDST_SUBKEY); - if (srcDstDao == null) { - srcDstDao = new HashMapDb(); - dao.put(dstKey, new MappingEntry<>(LCAF_SRCDST_SUBKEY, srcDstDao)); - } - IMappingServiceKey srcKey = MappingServiceKeyUtil.generateMappingServiceKey(srcAddr, srcMask); - srcDstDao.put(srcKey, entries.toArray(new MappingEntry[entries.size()])); - if (checkForChanges) { - newMapping = DAOMappingUtil.getMappingExact(srcAddr, dstAddr, srcMask, dstMask, dao); - return (newMapping.getValue() == null) ? oldMapping.getValue() != null : - !newMapping.getValue().equals(oldMapping.getValue()); - } - } else { - List oldLocators = null, newLocators = null; - if (checkForChanges) { - oldLocators = DAOMappingUtil.getLocatorsByEidToLocatorRecord(eidRecord, dao, shouldIterateMask()); - } - IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(eidRecord.getLispAddressContainer(), - eidRecord.getMaskLength()); - dao.put(key, entries.toArray(new MappingEntry[entries.size()])); - if (checkForChanges) { - newLocators = DAOMappingUtil.getLocatorsByEidToLocatorRecord(eidRecord, dao, shouldIterateMask()); - return (newLocators == null) ? oldLocators != null : !newLocators.equals(oldLocators); + } else { + MapNotifyBuilderHelper.setFromMapRegister(builder, mapRegister); } + notifyHandler.handleMapNotify(builder.build(), rlocs); } - return false; } - private String getAddressKey(Address address) { - if (address instanceof LcafKeyValue) { - LcafKeyValue keyVal = (LcafKeyValue) address; - if (keyVal.getLcafKeyValueAddressAddr().getKey().getPrimitiveAddress() instanceof DistinguishedName) { - return ((DistinguishedName) keyVal.getLcafKeyValueAddressAddr().getKey().getPrimitiveAddress()).getDistinguishedNameAddress().getDistinguishedName(); - } - } - if (shouldOverwrite()) { - return ADDRESS_SUBKEY; - } else { - return String.valueOf(address.hashCode()); + private static List getTransportAddresses(Set addresses) { + List rlocs = new ArrayList(); + for (IpAddressBinary address : addresses) { + TransportAddressBuilder tab = new TransportAddressBuilder(); + tab.setIpAddress(address); + tab.setPort(new PortNumber(LispMessage.PORT_NUM)); + rlocs.add(tab.build()); } + return rlocs; } - public String getAuthenticationKey(LispAddressContainer address, int maskLen) { - return getPassword(address, maskLen); + private SiteId getSiteId(MapRegister mapRegister) { + return (mapRegister.getSiteId() != null) ? new SiteId(mapRegister.getSiteId()) : null; } - public void removeAuthenticationKey(LispAddressContainer address, int maskLen) { - if (address.getAddress() instanceof LcafSourceDest) { - ILispDAO srcDstDao = getSrcDstInnerDao(address, maskLen); - if (srcDstDao != null) { - IMappingServiceKey srcKey = MappingServiceKeyUtil.generateMappingServiceKey(getSrcForLcafSrcDst(address), - getSrcMaskForLcafSrcDst(address)); - srcDstDao.removeSpecific(srcKey, PASSWORD_SUBKEY); + @Override + public void onMappingChanged(MappingChanged notification) { + if (subscriptionService) { + sendSmrs(notification.getMappingRecord(), getSubscribers(notification.getMappingRecord().getEid())); + if (notification.getChangeType().equals(MappingChange.Removed)) { + removeSubscribers(notification.getMappingRecord().getEid()); } - } else { - IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(address, maskLen); - dao.removeSpecific(key, PASSWORD_SUBKEY); } } - public void addAuthenticationKey(LispAddressContainer address, int maskLen, String key) { - IMappingServiceKey mappingServiceKey = MappingServiceKeyUtil.generateMappingServiceKey(address, maskLen); - if (address.getAddress() instanceof LcafSourceDest) { - IMappingServiceKey srcKey = MappingServiceKeyUtil.generateMappingServiceKey(getSrcForLcafSrcDst(address), - getSrcMaskForLcafSrcDst(address)); - ILispDAO srcDstDao = getOrInstantiateSrcDstInnerDao(address, maskLen); - srcDstDao.put(srcKey, new MappingEntry(PASSWORD_SUBKEY, key)); - } else { - dao.put(mappingServiceKey, new MappingEntry(PASSWORD_SUBKEY, key)); - } - } - - public void removeMapping(LispAddressContainer address, int maskLen, boolean smr, IMapNotifyHandler callback) { - Entry> mapping; - ILispDAO db; - if (address.getAddress() instanceof LcafSourceDest) { - db = getSrcDstInnerDao(address, maskLen); - LispAFIAddress srcAddr = getSrcForLcafSrcDst(address); - short srcMask = getSrcMaskForLcafSrcDst(address); - mapping = DAOMappingUtil.getMappingForEid(srcAddr, srcMask, db); - } else { - db = dao; - mapping = DAOMappingUtil.getMappingForEid(LispAFIConvertor.toAFI(address), maskLen, db); - } - if (smr) { - HashSet subscribers = getSubscribers(address, maskLen); - // mapping is removed before first SMR is sent to avoid inconsistent replies - removeMappingRlocs(mapping, db); - handleSmr(new EidToLocatorRecordBuilder().setLispAddressContainer(address). - setMaskLength((short) maskLen).build(), subscribers, callback); - db.removeSpecific(mapping.getKey(), SUBSCRIBERS_SUBKEY); - } else { - removeMappingRlocs(mapping, db); - db.removeSpecific(mapping.getKey(), SUBSCRIBERS_SUBKEY); - } - } - - private void removeMappingRlocs(Entry> mapping, ILispDAO db) { - if (mapping == null || mapping.getValue() == null) { - return; - } - for (MappingServiceRLOCGroup group : mapping.getValue()) { - for (LocatorRecord record : group.getRecords()) { - db.removeSpecific(mapping.getKey(), getAddressKey(record.getLispAddressContainer().getAddress())); - } + private static boolean mappingChanged(MappingRecord oldMapping, MappingRecord newMapping) { + // We only check for fields we care about + // XXX: This code needs to be checked and updated when the YANG model is modified + Preconditions.checkNotNull(newMapping, "The new mapping should never be null"); + if (oldMapping == null) { + LOG.trace("mappingChanged(): old mapping is null"); + return true; + } else if (!Objects.equals(oldMapping.getEid(), newMapping.getEid())) { + LOG.trace("mappingChanged(): EID"); + return true; + } else if (!Objects.equals(oldMapping.getLocatorRecord(), newMapping.getLocatorRecord())) { + LOG.trace("mappingChanged(): RLOC"); + return true; + } else if (!Objects.equals(oldMapping.getAction(), newMapping.getAction())) { + LOG.trace("mappingChanged(): action"); + return true; + } else if (!Objects.equals(oldMapping.getRecordTtl(), newMapping.getRecordTtl())) { + LOG.trace("mappingChanged(): TTL"); + return true; + } else if (!Objects.equals(oldMapping.getMapVersion(), newMapping.getMapVersion())) { + LOG.trace("mappingChanged(): mapping version"); + return true; } + return false; } - private void sendSmrs(EidToLocatorRecord record, IMapNotifyHandler callback) { - LispAddressContainer eid = record.getLispAddressContainer(); - HashSet subscribers; - - subscribers = getSubscribers(eid, record.getMaskLength()); - handleSmr(record, subscribers, callback); + private void sendSmrs(MappingRecord record, Set subscribers) { + Eid eid = record.getEid(); + handleSmr(eid, subscribers, notifyHandler); // For SrcDst LCAF also send SMRs to Dst prefix - if (eid.getAddress() instanceof LcafSourceDest) { - LispAddressContainer dstAddr = LispAFIConvertor.toContainer(getDstForLcafSrcDst(eid)); - short dstMask = getDstMaskForLcafSrcDst(eid); - subscribers = getSubscribers(dstAddr, dstMask); - EidToLocatorRecord newRecord = new EidToLocatorRecordBuilder().setAction(record.getAction()). - setAuthoritative(record.isAuthoritative()).setLocatorRecord(record.getLocatorRecord()). - setMapVersion(record.getMapVersion()).setRecordTtl(record.getRecordTtl()). - setLispAddressContainer(dstAddr).setMaskLength(dstMask).build(); - handleSmr(newRecord, subscribers, callback); + if (eid.getAddress() instanceof SourceDestKey) { + Eid dstAddr = SourceDestKeyHelper.getDstBinary(eid); + Set dstSubs = getSubscribers(dstAddr); + MappingRecord newRecord = new MappingRecordBuilder(record).setEid(dstAddr).build(); + handleSmr(newRecord.getEid(), dstSubs, notifyHandler); } } - private void handleSmr(EidToLocatorRecord record, HashSet subscribers, - IMapNotifyHandler callback) { + private void handleSmr(Eid eid, Set subscribers, IMapNotifyHandler callback) { if (subscribers == null) { return; } - MapRequestBuilder mrb = buildSMR(subscribers.iterator().next().getSrcEid()); + MapRequestBuilder mrb = MapRequestUtil.prepareSMR(eid, LispAddressUtil.toRloc(getLocalAddress())); LOG.trace("Built SMR packet: " + mrb.build().toString()); - for (MappingServiceSubscriberRLOC subscriber : subscribers) { + // Using Iterator ensures that we don't get a ConcurrentModificationException when removing a SubscriberRLOC + // from a Set. + Iterator iterator = subscribers.iterator(); + while (iterator.hasNext()) { + SubscriberRLOC subscriber = iterator.next(); if (subscriber.timedOut()) { LOG.trace("Lazy removing expired subscriber entry " + subscriber.toString()); - subscribers.remove(subscriber); + iterator.remove(); } else { try { - // The Source EID in a SMR is used as EID record in the SMR-invoked Map-Request. - mrb.setSourceEid(new SourceEidBuilder().setLispAddressContainer(record.getLispAddressContainer()).build()); + // The address stored in the SMR's EID record is used as Source EID in the SMR-invoked Map-Request. + // To ensure consistent behavior it is set to the value used to originally request a given mapping + mrb.setEidItem(new ArrayList()); + mrb.getEidItem().add(new EidItemBuilder().setEid(subscriber.getSrcEid()).build()); callback.handleSMR(mrb.build(), subscriber.getSrcRloc()); } catch (Exception e) { LOG.error("Errors encountered while handling SMR:" + ExceptionUtils.getStackTrace(e)); } } } - IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(record.getLispAddressContainer(), - record.getMaskLength()); - dao.put(key, new MappingEntry>(SUBSCRIBERS_SUBKEY, subscribers)); + addSubscribers(eid, subscribers); + } + + @SuppressWarnings("unchecked") + private Set getSubscribers(Eid address) { + return (Set) mapService.getData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS); } - public boolean shouldOverwrite() { - return overwrite; + private void removeSubscribers(Eid address) { + mapService.removeData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS); } - public void setOverwrite(boolean overwrite) { - this.overwrite = overwrite; + private void addSubscribers(Eid address, Set subscribers) { + mapService.addData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS, subscribers); } + private static InetAddress getLocalAddress() { + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface current = interfaces.nextElement(); + LOG.debug("Interface " + current.toString()); + if (!current.isUp() || current.isLoopback() || current.isVirtual()) { + continue; + } + Enumeration addresses = current.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress current_addr = addresses.nextElement(); + // Skip loopback and link local addresses + if (current_addr.isLoopbackAddress() || current_addr.isLinkLocalAddress()) { + continue; + } + LOG.debug(current_addr.getHostAddress()); + return current_addr; + } + } + } catch (SocketException se) { + LOG.debug("Caught socket exceptio", se); + } + return null; + } }