import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.SiteId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.authkey.container.MappingAuthkey;
/**
*/
void addMapping(MappingOrigin origin, Eid key, Object data);
- /**
- * Add mapping and persist to datastore
- *
- * @param origin
- * Table where mapping should be added
- * @param siteId
- * SiteID of SB device doing the registration
- * @param key
- * Key of the mapping
- * @param data
- * Value to be stored
- */
- void addMapping(MappingOrigin origin, SiteId siteId, Eid key, Object data);
-
/**
* Retrieves mapping for the provided src and dst key.
*
public void addMapping(MappingOrigin origin, Eid key, SiteId siteId, Object data) {
// SB registrations are first written to the MappingSystem and only afterwards are persisted to the datastore
if (origin.equals(MappingOrigin.Southbound)) {
- mappingSystem.addMapping(origin, siteId, key, data);
+ // Store data first in MapCache and only afterwards persist to datastore. This should be used only for SB
+ // registrations
+ mappingSystem.addMapping(origin, key, data);
+ dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, (MappingRecord) data));
} else {
dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, (MappingRecord) data));
}
import org.opendaylight.lispflowmapping.implementation.mapcache.MultiTableMapCache;
import org.opendaylight.lispflowmapping.implementation.mapcache.SimpleMapCache;
import org.opendaylight.lispflowmapping.implementation.mdsal.DataStoreBackEnd;
-import org.opendaylight.lispflowmapping.implementation.util.DSBEInputUtil;
import org.opendaylight.lispflowmapping.implementation.util.MappingMergeUtil;
import org.opendaylight.lispflowmapping.interfaces.dao.ILispDAO;
import org.opendaylight.lispflowmapping.interfaces.mapcache.IMapCache;
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.rloc.container.Rloc;
import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.SiteId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.Mapping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.authkey.container.MappingAuthkey;
tableMap.put(MappingOrigin.Southbound, smc);
}
- public void addMapping(MappingOrigin origin, SiteId siteId, Eid key, Object data) {
- // Store data first in MapCache and only afterwards persist to datastore. This should be used only for SB
- // registrations
- addMapping(origin, key, data);
- dsbe.addMapping(DSBEInputUtil.toMapping(origin, key, siteId, (MappingRecord) data));
- }
-
public void addMapping(MappingOrigin origin, Eid key, Object value) {
tableMap.get(origin).addMapping(key, value, origin == MappingOrigin.Southbound ? overwrite : true);
}
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
@SuppressWarnings("unchecked")
public void handleMapRegister(MapRegister mapRegister) {
boolean authFailed = false;
+ boolean mappingUpdated = false;
String password = null;
Set<SubscriberRLOC> subscribers = null;
MappingRecord oldMapping;
break;
}
}
+
oldMapping = (MappingRecord) mapService.getMapping(MappingOrigin.Southbound, mapping.getEid());
mapService.addMapping(MappingOrigin.Southbound, mapping.getEid(), getSiteId(mapRegister), mapping);
if (subscriptionService) {
- MappingRecord newMapping = ConfigIni.getInstance().mappingMergeIsSet()
- ? (MappingRecord) mapService.getMapping(MappingOrigin.Southbound, mapping.getEid()) : mapping;
+ MappingRecord newMapping = ConfigIni.getInstance().mappingMergeIsSet() ?
+ (MappingRecord) mapService.getMapping(MappingOrigin.Southbound, mapping.getEid()) : mapping;
+
if (mappingChanged(oldMapping, newMapping)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Mapping update occured for {} SMRs will be sent for its subscribers.",
}
subscribers = getSubscribers(mapping.getEid());
sendSmrs(mapping, subscribers);
+ mappingUpdated = true;
}
}
}
}
}
MapNotifyBuilderHelper.setFromMapRegisterAndMappingRecordItems(builder, mapRegister, mergedMappings);
- rlocs = getTransportAddresses(notifyRlocs);
+ // send map-notify to merge group only when mapping record is changed
+ if (mappingUpdated) {
+ rlocs = getTransportAddresses(notifyRlocs);
+ }
} else {
MapNotifyBuilderHelper.setFromMapRegister(builder, mapRegister);
}
} else if (!Objects.equals(oldMapping.getRecordTtl(), newMapping.getRecordTtl())) {
LOG.trace("mappingChanged(): TTL");
return true;
- } else if (!Arrays.equals(oldMapping.getXtrId(), newMapping.getXtrId())) {
- LOG.trace("mappingChanged(): xTR-ID");
- return true;
- } else if (!Arrays.equals(oldMapping.getSiteId(), newMapping.getSiteId())) {
- LOG.trace("mappingChanged(): site-ID");
- return true;
} else if (!Objects.equals(oldMapping.getMapVersion(), newMapping.getMapVersion())) {
LOG.trace("mappingChanged(): mapping version");
return true;
package org.opendaylight.lispflowmapping.implementation.mapcache;
import java.util.AbstractMap.SimpleImmutableEntry;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
return table;
}
+ public static Object deserializeBytes(byte[] data) {
+ return ByteBuffer.wrap(data);
+ }
+
private void removeExpiredXtrIdTableEntries(ILispDAO xtrIdDao, List<byte[]> expiredMappings) {
for (byte[] xtrId : expiredMappings) {
- xtrIdDao.removeSpecific(xtrId, SubKeys.RECORD);
+ xtrIdDao.removeSpecific(deserializeBytes(xtrId), SubKeys.RECORD);
}
}
ILispDAO xtrIdDao = null;
if (!shouldOverwrite) {
xtrIdDao = getOrInstantiateXtrIdTable(eid, table);
- xtrIdDao.put(record.getXtrId(), new MappingEntry<>(SubKeys.RECORD, value));
+ xtrIdDao.put(deserializeBytes(record.getXtrId()), new MappingEntry<>(SubKeys.RECORD, value));
}
if (ConfigIni.getInstance().mappingMergeIsSet()) {
*/
package org.opendaylight.lispflowmapping.implementation.util;
+import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
return newLocator;
}
+ private static int compareLocators(LocatorRecord a, LocatorRecord b) {
+ InetAddress aInet = LispAddressUtil.ipAddressToInet(a.getRloc().getAddress());
+ InetAddress bInet = LispAddressUtil.ipAddressToInet(b.getRloc().getAddress());
+ return LispAddressUtil.compareInetAddresses(aInet, bInet);
+ }
+
private static void mergeLocatorRecords(MappingRecordBuilder mrb, MappingRecord newRecord) {
List<LocatorRecord> locators = mrb.getLocatorRecord();
- // Optimization: unless we had to merge any of the locators due to differences in weights, etc, we return
- // the original 'locators' List with any new locators added
- boolean mergeHappened = false;
-
- // We assume locators are unique and don't show up several times (with different or identical p/w/mp/mw),
- // so we create a LinkedHashMap (which preserves order) of the locators from the existing merged record,
- // keyed by the Rloc
+ // We assume locators are unique and sorted and don't show up several times (with different or identical
+ // p/w/mp/mw), so we create a LinkedHashMap (which preserves order) of the locators from the existing merged
+ // record, keyed by the Rloc
Map<Rloc, LocatorRecord> locatorMap = new LinkedHashMap<Rloc, LocatorRecord>();
+
+ // All locators to be added to the merge set are first stored in this list
+ List<LocatorRecord> newLocatorList = new ArrayList<LocatorRecord>();
+
for (LocatorRecord locator : locators) {
locatorMap.put(locator.getRloc(), locator);
}
for (LocatorRecord newLocator : newRecord.getLocatorRecord()) {
Rloc newRloc = newLocator.getRloc();
if (locatorMap.containsKey(newRloc)) {
- // XXX LocatorRecord YANG generated class doesn't override equals() so I'm not sure of the behavior
- // here, need to verify if it works as expected
+ // overlapping locator
if (locatorMap.get(newRloc).equals(newLocator)) {
continue;
} else {
LocatorRecord mergedLocator = mergeLocators(locatorMap.get(newRloc), newLocator);
- locatorMap.put(newRloc, mergedLocator);
- mergeHappened = true;
+ newLocatorList.add(mergedLocator);
}
} else {
- // We add both the LinkedHanshMap and the List, in case we can return the original list plus new
- // elements and need not generate a new list with merged locators (which should be the most common
- // scenario).
- locatorMap.put(newRloc, newLocator);
- locators.add(newLocator);
+ // new locator
+ newLocatorList.add(newLocator);
}
}
- if (mergeHappened) {
+ // Build new merged and sorted locator set if need be
+ if (newLocatorList.size() != 0) {
List<LocatorRecord> mergedLocators = new ArrayList<LocatorRecord>();
- for (Map.Entry<Rloc, LocatorRecord> entry : locatorMap.entrySet()) {
- mergedLocators.add(entry.getValue());
+
+ int mlIt = 0, lIt = 0;
+ while (mlIt < newLocatorList.size() && lIt < locators.size()) {
+ int cmp = compareLocators(locators.get(lIt), newLocatorList.get(mlIt));
+ if (cmp < 0) {
+ mergedLocators.add(locators.get(lIt));
+ lIt++;
+ } else if (cmp > 0) {
+ mergedLocators.add(newLocatorList.get(mlIt));
+ mlIt++;
+ } else {
+ // when a locator appears in both lists, keep the new (merged) one and skip the old
+ mergedLocators.add(newLocatorList.get(mlIt));
+ mlIt++;
+ lIt++;
+ }
+ }
+ while (lIt < locators.size()) {
+ mergedLocators.add(locators.get(lIt));
+ lIt++;
+ }
+ while (mlIt < newLocatorList.size()) {
+ mergedLocators.add(newLocatorList.get(mlIt));
+ mlIt++;
}
mrb.setLocatorRecord(mergedLocators);
- } else {
- // TODO Check if this is necessary after and .add() was called on locators
- mrb.setLocatorRecord(locators);
}
}
public static MappingRecord mergeXtrIdMappings(List<Object> records, List<byte[]> expiredMappings,
Set<IpAddress> sourceRlocs) {
- MappingRecordBuilder mrb = new MappingRecordBuilder((MappingRecord) records.get(0));
- byte[] xtrId = mrb.getXtrId();
- Long timestamp = mrb.getTimestamp();
+ MappingRecordBuilder mrb = null;
+ byte[] xtrId = {};
+ Long timestamp = Long.MAX_VALUE;
- for (int i = 1; i < records.size(); i++) {
+ for (int i = 0; i < records.size(); i++) {
MappingRecord record = (MappingRecord) records.get(i);
// Skip expired mappings and add them to a list to be returned to the caller
continue;
}
+ if (mrb == null) {
+ mrb = new MappingRecordBuilder((MappingRecord) records.get(i));
+ }
+
// Save the oldest valid timestamp
if (record.getTimestamp() < timestamp) {
timestamp = record.getTimestamp();
// Save source locator for use in Map-Notify
sourceRlocs.add(record.getSourceRloc());
}
+
+ if (mrb == null) {
+ LOG.warn("All mappings expired when merging! Unexpected!");
+ }
mrb.setXtrId(xtrId);
mrb.setTimestamp(timestamp);
import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.lang3.BooleanUtils;
import org.opendaylight.lispflowmapping.lisp.serializer.exception.LispSerializationException;
import org.opendaylight.lispflowmapping.lisp.util.ByteUtil;
import org.opendaylight.lispflowmapping.lisp.util.NumberUtil;
ByteBuffer replyBuffer = ByteBuffer.allocate(size);
replyBuffer.put((byte) (MessageType.MapNotify.getIntValue() << 4));
replyBuffer.position(replyBuffer.position() + Length.RES);
+ replyBuffer.put(ByteUtil.boolToBit(BooleanUtils.isTrue(mapNotify.isMergeEnabled()), Flags.MERGE_ENABLED));
if (mapNotify.getMappingRecordItem() != null) {
replyBuffer.put((byte) mapNotify.getMappingRecordItem().size());
} else {
builder.setXtrSiteIdPresent(xtrSiteIdPresent);
notifyBuffer.position(notifyBuffer.position() + Length.RES);
+ builder.setMergeEnabled(ByteUtil.extractBit(notifyBuffer.get(), Flags.MERGE_ENABLED));
byte recordCount = (byte) ByteUtil.getUnsignedByte(notifyBuffer);
builder.setNonce(notifyBuffer.getLong());
private interface Flags {
byte XTRSITEID = 0x08;
+ byte MERGE_ENABLED = 0x04;
}
private interface Length {
int HEADER_SIZE = 16;
- int RES = 2;
+ int RES = 1;
}
}
ByteUtil.boolToBit(BooleanUtils.isTrue(mapRegister.isProxyMapReply()), Flags.PROXY) |
ByteUtil.boolToBit(BooleanUtils.isTrue(mapRegister.isXtrSiteIdPresent()), Flags.XTRSITEID)));
registerBuffer.position(registerBuffer.position() + Length.RES);
- registerBuffer.put(ByteUtil.boolToBit(BooleanUtils.isTrue(mapRegister.isWantMapNotify()), Flags.WANT_MAP_REPLY));
+ registerBuffer.put((byte)
+ (ByteUtil.boolToBit(BooleanUtils.isTrue(mapRegister.isMergeEnabled()), Flags.MERGE_ENABLED) |
+ ByteUtil.boolToBit(BooleanUtils.isTrue(mapRegister.isWantMapNotify()), Flags.WANT_MAP_NOTIFY)));
registerBuffer.put((byte) mapRegister.getMappingRecordItem().size());
registerBuffer.putLong(NumberUtil.asLong(mapRegister.getNonce()));
registerBuffer.putShort(NumberUtil.asShort(mapRegister.getKeyId()));
builder.setXtrSiteIdPresent(xtrSiteIdPresent);
registerBuffer.position(registerBuffer.position() + Length.RES);
- builder.setWantMapNotify(ByteUtil.extractBit(registerBuffer.get(), Flags.WANT_MAP_REPLY));
+ byte mergeAndMapReply = registerBuffer.get();
+ builder.setWantMapNotify(ByteUtil.extractBit(mergeAndMapReply, Flags.WANT_MAP_NOTIFY));
+ builder.setMergeEnabled(ByteUtil.extractBit(mergeAndMapReply, Flags.MERGE_ENABLED));
byte recordCount = (byte) ByteUtil.getUnsignedByte(registerBuffer);
builder.setNonce(registerBuffer.getLong());
builder.setKeyId(registerBuffer.getShort());
private interface Flags {
byte PROXY = 0x08;
byte XTRSITEID = 0x02;
- byte WANT_MAP_REPLY = 0x01;
+ byte MERGE_ENABLED = 0x04;
+ byte WANT_MAP_NOTIFY = 0x01;
}
public interface Length {
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.AsNumberBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.DistinguishedNameBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4Builder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4PrefixBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6Builder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6PrefixBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.KeyValueAddress;
builder.setAddress(new NoAddressBuilder().setNoAddress(true).build());
return builder.build();
}
+
+ public static InetAddress ipAddressToInet(Address addr) {
+ try {
+ if (addr instanceof Ipv4) {
+ return Inet4Address.getByName(((Ipv4) addr).getIpv4().getValue());
+ } else if (addr instanceof Ipv6) {
+ return Inet6Address.getByName(((Ipv6) addr).getIpv6().getValue());
+ }
+ } catch (java.net.UnknownHostException e) {
+ LOG.debug("Failed to build InetAddress: {}", e);
+ }
+ return null;
+ }
+
+ public static int compareInetAddresses(InetAddress a, InetAddress b) {
+ int i;
+ if (a instanceof Inet4Address && b instanceof Inet6Address) {
+ return -1;
+ } else if (a instanceof Inet6Address && b instanceof Inet4Address) {
+ return 1;
+ } else if (a instanceof Inet4Address && b instanceof Inet4Address) {
+ byte[] aBytes = ((Inet4Address) a).getAddress();
+ byte[] bBytes = ((Inet4Address) b).getAddress();
+ for (i = 0; i < 4; i++) {
+ if (aBytes[i] < bBytes[i]) {
+ return -1;
+ } else if (aBytes[i] > bBytes[i]) {
+ return 1;
+ }
+ }
+ return 0;
+ } else if (a instanceof Inet6Address && b instanceof Inet6Address) {
+ byte[] aBytes = ((Inet4Address) a).getAddress();
+ byte[] bBytes = ((Inet4Address) b).getAddress();
+ for (i = 0; i < 16; i++) {
+ if (aBytes[i] < bBytes[i]) {
+ return -1;
+ } else if (aBytes[i] > bBytes[i]) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+ return 0;
+ }
}
private static void setNonRecordFields(MapNotifyBuilder builder, MapRegister mapRegister) {
builder.setNonce(mapRegister.getNonce());
builder.setKeyId(mapRegister.getKeyId());
+ builder.setMergeEnabled(mapRegister.isMergeEnabled());
+
byte[] authenticationData = mapRegister.getAuthenticationData();
if (authenticationData != null) {
authenticationData = authenticationData.clone();
leaf authenticationData {
type binary;
}
+ leaf mergeEnabled {
+ type boolean;
+ }
uses mapping-record-list;
uses xtrSiteId;
}
leaf authenticationData {
type binary;
}
+ leaf mergeEnabled {
+ type boolean;
+ }
uses mapping-record-list;
uses xtrSiteId;
}
public static MapRegister convertMapRegister(
org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRegister mapRegister) {
- return new MapRegisterBuilder().setAuthenticationData(mapRegister.getAuthenticationData())
- .setMappingRecordItem(mapRegister.getMappingRecordItem()).setKeyId(mapRegister.getKeyId())
- .setNonce(mapRegister.getNonce()).setProxyMapReply(mapRegister.isProxyMapReply())
- .setWantMapNotify(mapRegister.isWantMapNotify()).setXtrSiteIdPresent(mapRegister.isXtrSiteIdPresent())
- .setXtrId(mapRegister.getXtrId()).setSiteId(mapRegister.getSiteId()).build();
+ return new MapRegisterBuilder(mapRegister).build();
}
public static MapNotify convertMapNotify(
org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapNotify mapNotify) {
- return new MapNotifyBuilder().setAuthenticationData(mapNotify.getAuthenticationData())
- .setMappingRecordItem(mapNotify.getMappingRecordItem()).setKeyId(mapNotify.getKeyId())
- .setNonce(mapNotify.getNonce()).setXtrSiteIdPresent(mapNotify.isXtrSiteIdPresent())
- .setXtrId(mapNotify.getXtrId()).setSiteId(mapNotify.getSiteId()).build();
+ return new MapNotifyBuilder(mapNotify).build();
}
public static MapRequest convertMapRequest(