X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=mappingservice%2Fimplementation%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Flispflowmapping%2Fimplementation%2Flisp%2FMapServer.java;h=f17ad7ec7f25519f5c789fd47e247f8a4f921373;hb=19face1c20178f24fbe9caa81bac69938e853ab4;hp=eb6d666159213fcc3a46063a4d9ad089a21c79f3;hpb=eaf13961ddcc1e7b52f5c23c143535e8bd838884;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 eb6d66615..f17ad7ec7 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 @@ -8,8 +8,8 @@ package org.opendaylight.lispflowmapping.implementation.lisp; -import com.google.common.base.Preconditions; -import com.google.common.collect.Maps; +import static java.util.Objects.requireNonNull; + import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.net.InetAddress; import java.net.NetworkInterface; @@ -17,19 +17,18 @@ import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; -import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.BooleanUtils; -import org.opendaylight.controller.md.sal.binding.api.NotificationService; import org.opendaylight.lispflowmapping.config.ConfigIni; import org.opendaylight.lispflowmapping.implementation.util.LoggingUtil; import org.opendaylight.lispflowmapping.implementation.util.MSNotificationInputUtil; @@ -48,20 +47,29 @@ 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.MappingRecordUtil; +import org.opendaylight.lispflowmapping.lisp.util.MaskUtil; import org.opendaylight.lispflowmapping.lisp.util.SourceDestKeyHelper; +import org.opendaylight.mdsal.binding.api.NotificationService; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.Address; 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.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinaryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary; +import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinaryBuilder; 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.container.EidBuilder; 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.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.mapping._record.list.MappingRecordItemKey; 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.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; @@ -74,19 +82,18 @@ import org.slf4j.LoggerFactory; public class MapServer implements IMapServerAsync, OdlMappingserviceListener, ISmrNotificationListener { - protected static final Logger LOG = LoggerFactory.getLogger(MapServer.class); + private static final Logger LOG = LoggerFactory.getLogger(MapServer.class); private static final byte[] ALL_ZEROES_XTR_ID = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0}; - private IMappingService mapService; + private final IMappingService mapService; private boolean subscriptionService; - private IMapNotifyHandler notifyHandler; - private NotificationService notificationService; + private final IMapNotifyHandler notifyHandler; + private final NotificationService notificationService; private ListenerRegistration mapServerListenerRegistration; - private SmrScheduler scheduler; + private final SmrScheduler scheduler; public MapServer(IMappingService mapService, boolean subscriptionService, IMapNotifyHandler notifyHandler, NotificationService notificationService) { - Preconditions.checkNotNull(mapService); - this.mapService = mapService; + this.mapService = requireNonNull(mapService); this.subscriptionService = subscriptionService; this.notifyHandler = notifyHandler; this.notificationService = notificationService; @@ -101,16 +108,15 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS this.subscriptionService = subscriptionService; } + @Override @SuppressWarnings("unchecked") public void handleMapRegister(MapRegister mapRegister) { boolean mappingUpdated = false; - boolean oldMappingRemoved = false; - boolean merge = ConfigIni.getInstance().mappingMergeIsSet() && mapRegister.isMergeEnabled(); - Set subscribers = null; + boolean merge = ConfigIni.getInstance().mappingMergeIsSet() && mapRegister.getMergeEnabled(); MappingRecord oldMapping; if (merge) { - if (!mapRegister.isXtrSiteIdPresent() || mapRegister.getXtrId() == null) { + if (!mapRegister.getXtrSiteIdPresent() || mapRegister.getXtrId() == null) { LOG.error("Merge bit is set in Map-Register, but xTR-ID is not present. Will not merge."); merge = false; } else if (Arrays.equals(mapRegister.getXtrId().getValue(), ALL_ZEROES_XTR_ID)) { @@ -127,47 +133,29 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS oldMapping = getMappingRecord(mapService.getMapping(MappingOrigin.Southbound, eid)); mapService.addMapping(MappingOrigin.Southbound, eid, getSiteId(mapRegister), mappingData); - if (oldMapping != null && MappingRecordUtil.isNegativeMapping(oldMapping)) { - mapService.removeMapping(MappingOrigin.Southbound, oldMapping.getEid()); - oldMappingRemoved = true; - } - - if (subscriptionService) { - MappingRecord newMapping = merge - ? getMappingRecord(mapService.getMapping(MappingOrigin.Southbound, eid)) : mapping; - - if (mappingChanged(oldMapping, newMapping)) { - if (LOG.isDebugEnabled()) { - LOG.debug("Mapping update occured for {} SMRs will be sent for its subscribers.", - LispAddressStringifier.getString(mapping.getEid())); - } - subscribers = getSubscribers(eid); - if (oldMapping != null && !oldMapping.getEid().equals(eid)) { - subscribers = addParentSubscribers(eid, subscribers); - } - LoggingUtil.logSubscribers(LOG, eid, subscribers); - handleSmr(eid, subscribers); - if (oldMapping != null && oldMappingRemoved && !oldMapping.getEid().equals(eid)) { - subscribers = getSubscribers(oldMapping.getEid()); - LoggingUtil.logSubscribers(LOG, oldMapping.getEid(), subscribers); - handleSmr(oldMapping.getEid(), subscribers); - } + if (merge) { + MappingRecord newMapping = getMappingRecord(mapService.getMapping(MappingOrigin.Southbound, eid)); + if (MappingRecordUtil.mappingChanged(oldMapping, newMapping)) { + // If there is a SB mapping change with merge on, Map-Notify will be sent to ALL xTRs, not jus the + // one registering (merging is done in the MappingSystem code) mappingUpdated = true; } } } - if (BooleanUtils.isTrue(mapRegister.isWantMapNotify())) { + if (BooleanUtils.isTrue(mapRegister.getWantMapNotify())) { LOG.trace("MapRegister wants MapNotify"); MapNotifyBuilder builder = new MapNotifyBuilder(); List rlocs = null; if (merge) { - Set notifyRlocs = new HashSet(); - List mergedMappings = new ArrayList(); + Set notifyRlocs = new LinkedHashSet<>(); + List mergedMappings = new ArrayList<>(); for (MappingRecordItem record : mapRegister.getMappingRecordItem()) { MappingRecord mapping = record.getMappingRecord(); MappingRecord currentRecord = getMappingRecord(mapService.getMapping(MappingOrigin.Southbound, mapping.getEid())); - mergedMappings.add(new MappingRecordItemBuilder().setMappingRecord(currentRecord).build()); + mergedMappings.add(new MappingRecordItemBuilder() + .withKey(new MappingRecordItemKey(LispAddressStringifier.getString(mapping.getEid()))) + .setMappingRecord(currentRecord).build()); Set sourceRlocs = (Set) mapService.getData( MappingOrigin.Southbound, mapping.getEid(), SubKeys.SRC_RLOCS); if (sourceRlocs != null) { @@ -196,29 +184,33 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS } private static List getTransportAddresses(Set addresses) { - List rlocs = new ArrayList(); + List rlocs = new ArrayList<>(); for (IpAddressBinary address : addresses) { TransportAddressBuilder tab = new TransportAddressBuilder(); tab.setIpAddress(address); - tab.setPort(new PortNumber(LispMessage.PORT_NUM)); + tab.setPort(new PortNumber(LispMessage.PORT_NUMBER)); rlocs.add(tab.build()); } return rlocs; } private static SiteId getSiteId(MapRegister mapRegister) { - return (mapRegister.getSiteId() != null) ? new SiteId(mapRegister.getSiteId()) : null; + return mapRegister.getSiteId() != null ? new SiteId(mapRegister.getSiteId()) : null; } private static MappingRecord getMappingRecord(MappingData mappingData) { - return (mappingData != null) ? mappingData.getRecord() : null; + return mappingData != null ? mappingData.getRecord() : null; } @Override public void onMappingChanged(MappingChanged notification) { - LOG.trace("MappingChanged event of type: `{}'", notification.getChangeType()); if (subscriptionService) { - Eid eid = notification.getMappingRecord().getEid(); + Eid eid = notification.getEid(); + if (eid == null) { + eid = notification.getMappingRecord().getEid(); + } + LOG.trace("MappingChanged event for {} of type: `{}'", LispAddressStringifier.getString(eid), + notification.getChangeType()); Set subscribers = MSNotificationInputUtil.toSubscriberSet(notification.getSubscriberItem()); LoggingUtil.logSubscribers(LOG, eid, subscribers); if (mapService.isMaster()) { @@ -233,39 +225,13 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS } } - 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 for MappingRecord 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 handleSmr(Eid eid, Set subscribers) { sendSmrs(eid, subscribers); // For SrcDst LCAF also send SMRs to Dst prefix if (eid.getAddress() instanceof SourceDestKey) { Eid dstAddr = SourceDestKeyHelper.getDstBinary(eid); - Set dstSubs = getSubscribers(dstAddr); + Set dstSubs = mapService.getSubscribers(dstAddr); sendSmrs(dstAddr, dstSubs); } } @@ -275,43 +241,17 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS return; } final MapRequestBuilder mrb = MapRequestUtil.prepareSMR(eid, LispAddressUtil.toRloc(getLocalAddress())); - LOG.trace("Built SMR packet: " + mrb.build().toString()); + LOG.trace("Built SMR packet template (EID field will be set later): {}", mrb.build()); scheduler.scheduleSmrs(mrb, subscribers.iterator()); } - @SuppressWarnings("unchecked") - private Set getSubscribers(Eid address) { - return (Set) mapService.getData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS); - } - - private Set addParentSubscribers(Eid eid, Set subscribers) { - Eid parentPrefix = mapService.getParentPrefix(eid); - if (parentPrefix == null) { - return subscribers; - } - - Set parentSubscribers = getSubscribers(parentPrefix); - if (parentSubscribers != null) { - if (subscribers != null) { - subscribers.addAll(parentSubscribers); - } else { - subscribers = parentSubscribers; - } - } - return subscribers; - } - - 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.trace("Interface " + current.toString()); + LOG.trace("Interface {}", current); if (!current.isUp() || current.isLoopback() || current.isVirtual()) { continue; } @@ -347,20 +287,20 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS private final ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat("smr-executor-%d").build(); private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(cpuCores * 2, threadFactory); - private final Map>> eidFutureMap = Maps.newConcurrentMap(); + private final Map>> eidFutureMap = new ConcurrentHashMap<>(); void scheduleSmrs(MapRequestBuilder mrb, Iterator subscribers) { - final Eid srcEid = mrb.getSourceEid().getEid(); + final Eid srcEid = fixSrcEidMask(mrb.getSourceEid().getEid()); cancelExistingFuturesForEid(srcEid); - final Map> subscriberFutureMap = Maps.newConcurrentMap(); + final Map> subscriberFutureMap = new ConcurrentHashMap<>(); // Using Iterator ensures that we don't get a ConcurrentModificationException when removing a Subscriber // from a Set. while (subscribers.hasNext()) { Subscriber subscriber = subscribers.next(); if (subscriber.timedOut()) { - LOG.debug("Lazy removing expired subscriber entry " + subscriber.getString()); + LOG.debug("Lazy removing expired subscriber entry {}", subscriber.getString()); subscribers.remove(); } else { final ScheduledFuture future = executor.scheduleAtFixedRate(new CancellableRunnable( @@ -378,21 +318,39 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS void smrReceived(SmrEvent event) { final List subscriberList = event.getSubscriberList(); for (Subscriber subscriber : subscriberList) { - LOG.trace("SMR-invoked event, EID {}, subscriber {}", LispAddressStringifier.getString(event.getEid()), - subscriber.getString()); + if (LOG.isTraceEnabled()) { + LOG.trace("SMR-invoked event, EID {}, subscriber {}", + LispAddressStringifier.getString(event.getEid()), + subscriber.getString()); + LOG.trace("eidFutureMap: {}", eidFutureMap); + } final Map> subscriberFutureMap = eidFutureMap.get(event.getEid()); if (subscriberFutureMap != null) { final ScheduledFuture future = subscriberFutureMap.get(subscriber); if (future != null && !future.isCancelled()) { future.cancel(true); - LOG.debug("SMR-invoked MapRequest received, scheduled task for subscriber {}, EID {} with" - + " nonce {} has been cancelled", subscriber.getString(), - LispAddressStringifier.getString(event.getEid()), event.getNonce()); + if (LOG.isDebugEnabled()) { + LOG.debug("SMR-invoked MapRequest received, scheduled task for subscriber {}, EID {} with" + + " nonce {} has been cancelled", subscriber.getString(), + LispAddressStringifier.getString(event.getEid()), event.getNonce()); + } subscriberFutureMap.remove(subscriber); + } else { + if (future == null) { + LOG.trace("No outstanding SMR tasks for EID {}, subscriber {}", + LispAddressStringifier.getString(event.getEid()), subscriber.getString()); + } else { + LOG.trace("Future {} is cancelled", future); + } } if (subscriberFutureMap.isEmpty()) { eidFutureMap.remove(event.getEid()); } + } else { + if (LOG.isTraceEnabled()) { + LOG.trace("No outstanding SMR tasks for EID {}", + LispAddressStringifier.getString(event.getEid())); + } } } } @@ -412,9 +370,29 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS } } + /* + * See https://bugs.opendaylight.org/show_bug.cgi?id=8469#c1 why this is necessary. + * + * TL;DR The sourceEid field in the MapRequestBuilder object will be serialized to a packet on the wire, and + * a Map-Request can't store the prefix length in the source EID. + * + * Since we store all prefixes as binary internally, we only care about and fix those address types. + */ + private Eid fixSrcEidMask(Eid eid) { + Address address = eid.getAddress(); + if (address instanceof Ipv4PrefixBinary) { + return new EidBuilder(eid).setAddress(new Ipv4PrefixBinaryBuilder((Ipv4PrefixBinary) address) + .setIpv4MaskLength(MaskUtil.IPV4_MAX_MASK_UINT).build()).build(); + } else if (address instanceof Ipv6PrefixBinary) { + return new EidBuilder(eid).setAddress(new Ipv6PrefixBinaryBuilder((Ipv6PrefixBinary) address) + .setIpv6MaskLength(MaskUtil.IPV6_MAX_MASK_UINT).build()).build(); + } + return eid; + } + private final class CancellableRunnable implements Runnable { - private MapRequestBuilder mrb; - private Subscriber subscriber; + private final MapRequestBuilder mrb; + private final Subscriber subscriber; private int executionCount = 1; CancellableRunnable(MapRequestBuilder mrb, Subscriber subscriber) { @@ -434,7 +412,9 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS if (executionCount <= ConfigIni.getInstance().getSmrRetryCount()) { synchronized (mrb) { mrb.setEidItem(new ArrayList()); - mrb.getEidItem().add(new EidItemBuilder().setEid(subscriber.getSrcEid()).build()); + mrb.getEidItem().add(new EidItemBuilder() + .setEidItemId(LispAddressStringifier.getString(subscriber.getSrcEid())) + .setEid(subscriber.getSrcEid()).build()); notifyHandler.handleSMR(mrb.build(), subscriber.getSrcRloc()); if (LOG.isTraceEnabled()) { LOG.trace("Attempt #{} to send SMR to subscriber {} for EID {}", @@ -457,16 +437,16 @@ public class MapServer implements IMapServerAsync, OdlMappingserviceListener, IS executionCount++; } - private void cancelAndRemove(Subscriber subscriber, Eid eid) { + private void cancelAndRemove(Subscriber sub, Eid eid) { final Map> subscriberFutureMap = eidFutureMap.get(eid); if (subscriberFutureMap == null) { - LOG.warn("Couldn't find subscriber {} in SMR scheduler internal list", subscriber); + LOG.warn("Couldn't find subscriber {} in SMR scheduler internal list", sub); return; } - if (subscriberFutureMap.containsKey(subscriber)) { - ScheduledFuture eidFuture = subscriberFutureMap.get(subscriber); - subscriberFutureMap.remove(subscriber); + if (subscriberFutureMap.containsKey(sub)) { + ScheduledFuture eidFuture = subscriberFutureMap.get(sub); + subscriberFutureMap.remove(sub); eidFuture.cancel(false); } if (subscriberFutureMap.isEmpty()) {