}
@Test
- public void testNegativePrefix_gapIntersection() throws UnknownHostException {
+ public void testNbAndSbNegativePrefix() throws UnknownHostException {
insertMappings();
testGapIntersection();
insertMappings();
testMultipleMappings();
+ }
+ @Test
+ public void testExplicitSbNegativePrefixes() {
// https://bugs.opendaylight.org/show_bug.cgi?id=8679
testNegativePrefix();
+
+ // https://bugs.opendaylight.org/show_bug.cgi?id=9023
+ testPositiveMappingRemoval();
}
private void testRepeatedSmr() throws SocketTimeoutException, UnknownHostException {
assertTrue(MappingRecordUtil.isNegativeMapping(mr));
}
+ private void testPositiveMappingRemoval() {
+ cleanUP();
+
+ insertNBMappings(1L, "192.167.0.0/16", "192.169.0.0/16");
+ insertSBMappings(1L, "192.168.32.0/19");
+
+ MapReply mapReply = lms.handleMapRequest(newMapRequest(1L, "192.168.0.1/32"));
+ Eid expectedNegativePrefix = LispAddressUtil.asIpv4PrefixBinaryEid(1L, "192.168.0.0/19");
+ MappingRecord mr = mapReply.getMappingRecordItem().get(0).getMappingRecord();
+ assertEquals(expectedNegativePrefix, mr.getEid());
+ assertTrue(MappingRecordUtil.isNegativeMapping(mr));
+
+ mapReply = lms.handleMapRequest(newMapRequest(1L, "192.168.64.1/32"));
+ expectedNegativePrefix = LispAddressUtil.asIpv4PrefixBinaryEid(1L, "192.168.64.0/18");
+ mr = mapReply.getMappingRecordItem().get(0).getMappingRecord();
+ assertEquals(expectedNegativePrefix, mr.getEid());
+ assertTrue(MappingRecordUtil.isNegativeMapping(mr));
+
+ mapReply = lms.handleMapRequest(newMapRequest(1L, "192.168.128.1/32"));
+ expectedNegativePrefix = LispAddressUtil.asIpv4PrefixBinaryEid(1L, "192.168.128.0/17");
+ mr = mapReply.getMappingRecordItem().get(0).getMappingRecord();
+ assertEquals(expectedNegativePrefix, mr.getEid());
+ assertTrue(MappingRecordUtil.isNegativeMapping(mr));
+
+ printMapCacheState();
+
+ mapService.removeMapping(MappingOrigin.Southbound, LispAddressUtil.asIpv4PrefixBinaryEid(
+ 1L, "192.168.32.0/19"));
+
+ printMapCacheState();
+
+ mapReply = lms.handleMapRequest(newMapRequest(1L, "192.168.32.1/32"));
+ expectedNegativePrefix = LispAddressUtil.asIpv4PrefixBinaryEid(1L, "192.168.0.0/16");
+ mr = mapReply.getMappingRecordItem().get(0).getMappingRecord();
+ assertEquals(expectedNegativePrefix, mr.getEid());
+ assertTrue(MappingRecordUtil.isNegativeMapping(mr));
+
+ printMapCacheState();
+ }
+
private void insertMappings() {
cleanUP();
mapService.setLookupPolicy(IMappingService.LookupPolicy.NB_AND_SB);
}
private void insertNBMappings(long iid, String ... prefixes) {
+ LOG.debug("Adding Northbound mappings for prefixes: {}", prefixes);
final InstanceIdType iiType = new InstanceIdType(iid);
for (String prefix : prefixes) {
MappingRecord record = newMappingRecord(prefix, iiType);
mapService.addMapping(MappingOrigin.Northbound, record.getEid(), null,
new MappingData(MappingOrigin.Northbound, record));
}
+ sleepForMilliseconds(25);
+ printMapCacheState();
}
private void insertSBMappings(long iid, String ... prefixes) {
+ LOG.debug("Adding Southbound mappings for prefixes: {}", prefixes);
final InstanceIdType iiType = new InstanceIdType(iid);
Eid eid = LispAddressUtil.asIpv4PrefixBinaryEid("0.0.0.0/0", iiType);
mapService.addAuthenticationKey(eid, NULL_AUTH_KEY);
mapService.addMapping(MappingOrigin.Southbound, record.getEid(), null,
new MappingData(MappingOrigin.Southbound, record, System.currentTimeMillis()));
}
+ printMapCacheState();
+ }
+
+ private void printMapCacheState() {
+ LOG.debug("Map-cache state:\n{}", mapService.prettyPrintMappings());
}
/**
.setLocatorRecord(Lists.newArrayList(new LocatorRecordBuilder()
.setRloc(LispAddressUtil.asIpv4Rloc("2.2.2.2"))
.setLocatorId("loc_id")
+ .setRouted(true)
.setPriority((short) 1)
.setWeight((short) 1).build()))
.setTimestamp(System.currentTimeMillis())
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumMap;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
public MappingData addNegativeMapping(Eid key) {
MappingRecord mapping = buildNegativeMapping(key);
MappingData mappingData = new MappingData(MappingOrigin.Southbound, mapping);
+ LOG.debug("Adding negative mapping for EID {}", LispAddressStringifier.getString(key));
+ LOG.trace(mappingData.getString());
smc.addMapping(mapping.getEid(), mappingData);
dsbe.addMapping(DSBEInputUtil.toMapping(MappingOrigin.Southbound, mapping.getEid(), null, mappingData));
return mappingData;
Set<Subscriber> dstSubscribers = null;
MappingData mapping = (MappingData) tableMap.get(origin).getMapping(null, key);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Removing mapping for EID {} from {}",
+ LispAddressStringifier.getString(key), origin);
+ }
+ if (LOG.isTraceEnabled()) {
+ LOG.trace(mapping.getString());
+ }
+
+ MappingData notificationMapping = mapping;
+
if (mapping != null) {
- MappingData notificationMapping = mapping;
subscribers = (Set<Subscriber>) getData(MappingOrigin.Southbound, key, SubKeys.SUBSCRIBERS);
// For SrcDst LCAF also send SMRs to Dst prefix
if (key.getAddress() instanceof SourceDestKey) {
new MappingRecordBuilder().setEid(key).build());
}
}
- notifyChange(notificationMapping, subscribers, dstSubscribers, MappingChange.Removed);
}
if (origin == MappingOrigin.Northbound) {
if (origin == MappingOrigin.Southbound) {
removeFromSbTimeoutService(key);
- if (mapping != null && mapping.isPositive().or(false)) {
- mergeNegativePrefixes(key);
- }
}
- tableMap.get(origin).removeMapping(key);
+
+ if (origin == MappingOrigin.Southbound && mapping != null && mapping.isPositive().or(false)) {
+ mergeNegativePrefixes(key);
+ } else {
+ // mergeNegativePrefixes() above removes the mapping, so addNegativeMapping() will work correctly
+ tableMap.get(origin).removeMapping(key);
+ }
+
+ if (notificationMapping != null) {
+ notifyChange(notificationMapping, subscribers, dstSubscribers, MappingChange.Removed);
+ }
}
private void notifyChange(MappingData mapping, Set<Subscriber> subscribers, Set<Subscriber> dstSubscribers,
* Merges adjacent negative prefixes and notifies their subscribers.
*/
private void mergeNegativePrefixes(Eid eid) {
- // If prefix sibling has a negative mapping, save its subscribers
- Eid sibling = smc.getSiblingPrefix(eid);
- MappingData mapping = (MappingData) smc.getMapping(null, sibling);
+ LOG.debug("Merging negative prefixes starting from EID {}", LispAddressStringifier.getString(eid));
+
+ // If we delete nodes while we walk up the radix trie the algorithm will give incorrect results, because
+ // removals rearrange relationships in the trie. So we save prefixes to be removed into a HashMap.
+ Map<Eid, MappingData> mergedMappings = new HashMap<>();
+
+ Eid currentNode = smc.getSiblingPrefix(eid);
+ MappingData mapping = (MappingData) smc.getMapping(null, currentNode);
if (mapping != null && mapping.isNegative().or(false)) {
- removeSbMapping(sibling, mapping);
+ mergedMappings.put(currentNode, mapping);
} else {
return;
}
- Eid currentNode = sibling;
- Eid previousNode = sibling;
- while ((currentNode = smc.getVirtualParentSiblingPrefix(currentNode)) != null) {
+ Eid previousNode = currentNode;
+ currentNode = smc.getVirtualParentSiblingPrefix(currentNode);
+ while (currentNode != null) {
mapping = (MappingData) smc.getMapping(null, currentNode);
if (mapping != null && mapping.isNegative().or(false)) {
- removeSbMapping(currentNode, mapping);
+ mergedMappings.put(currentNode, mapping);
} else {
break;
}
previousNode = currentNode;
+ currentNode = smc.getVirtualParentSiblingPrefix(previousNode);
+ }
+
+ for (Eid key : mergedMappings.keySet()) {
+ removeSbMapping(key, mergedMappings.get(key));
}
+ smc.removeMapping(eid);
+
addNegativeMapping(getVirtualParent(previousNode));
}