2 * Copyright (c) 2016 Cisco Systems, Inc. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.lispflowmapping.mapcache;
10 import com.google.common.base.Preconditions;
11 import java.util.ArrayList;
12 import java.util.Date;
13 import java.util.LinkedHashMap;
14 import java.util.List;
17 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.inet.binary.types.rev160303.IpAddressBinary;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecord;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rloc.container.Rloc;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Utility class to implement merging of locator sets.
30 * @author Lorand Jakab
33 public final class MappingMergeUtil {
34 protected static final Logger LOG = LoggerFactory.getLogger(MappingMergeUtil.class);
36 // SB Map Register validity period in milliseconds. Default is 3.3 minutes.
37 // TODO Added temporarily, until we get a proper configuration infra
38 public static final long MIN_REGISTRATION_VALIDITY_SB = 200000L;
40 // Utility class, should not be instantiated
41 private MappingMergeUtil() {
44 private static void mergeCommonMappingRecordFields(MappingRecordBuilder mrb, MappingRecord record) {
45 // Set xTR-ID and site-ID from the current mapping, it help with determining the timestamp
46 mrb.setXtrId(record.getXtrId());
47 mrb.setSiteId(record.getSiteId());
48 // For the TTL value we take the minimum of all records
49 mrb.setRecordTtl(Math.min(mrb.getRecordTtl(), record.getRecordTtl()));
50 if (!mrb.getAction().equals(record.getAction())) {
51 LOG.warn("Mapping merge operation: actions are different, which one is used is undefined");
53 if (mrb.isAuthoritative() != record.isAuthoritative()) {
54 LOG.warn("Mapping merge operation: authoritative status is different, which one is used is undefined");
56 if (!mrb.getEid().equals(record.getEid())) {
57 LOG.warn("Mapping merge operation: EID records are different, which one is used is undefined");
61 private static LocatorRecord mergeLocators(LocatorRecord existingLocator, LocatorRecord newLocator) {
62 if (existingLocator.isLocalLocator()) {
63 return existingLocator;
68 private static int compareLocators(LocatorRecord one, LocatorRecord two) {
69 byte[] oneIp = LispAddressUtil.ipAddressToByteArray(one.getRloc().getAddress());
70 byte[] twoIp = LispAddressUtil.ipAddressToByteArray(two.getRloc().getAddress());
71 return LispAddressUtil.compareIpAddressByteArrays(oneIp, twoIp);
74 private static void mergeLocatorRecords(MappingRecordBuilder mrb, MappingRecord newRecord) {
75 List<LocatorRecord> locators = mrb.getLocatorRecord();
77 // We assume locators are unique and sorted and don't show up several times (with different or identical
78 // p/w/mp/mw), so we create a LinkedHashMap (which preserves order) of the locators from the existing merged
79 // record, keyed by the Rloc
80 Map<Rloc, LocatorRecord> locatorMap = new LinkedHashMap<Rloc, LocatorRecord>();
82 // All locators to be added to the merge set are first stored in this list
83 List<LocatorRecord> newLocatorList = new ArrayList<LocatorRecord>();
85 for (LocatorRecord locator : locators) {
86 locatorMap.put(locator.getRloc(), locator);
88 for (LocatorRecord newLocator : newRecord.getLocatorRecord()) {
89 Rloc newRloc = newLocator.getRloc();
90 if (locatorMap.containsKey(newRloc)) {
91 // overlapping locator
92 if (locatorMap.get(newRloc).equals(newLocator)) {
95 LocatorRecord mergedLocator = mergeLocators(locatorMap.get(newRloc), newLocator);
96 newLocatorList.add(mergedLocator);
100 newLocatorList.add(newLocator);
104 // Build new merged and sorted locator set if need be
105 if (newLocatorList.size() != 0) {
106 List<LocatorRecord> mergedLocators = new ArrayList<LocatorRecord>();
110 while (mlocIt < newLocatorList.size() && locIt < locators.size()) {
111 int cmp = compareLocators(locators.get(locIt), newLocatorList.get(mlocIt));
113 mergedLocators.add(locators.get(locIt));
115 } else if (cmp > 0) {
116 mergedLocators.add(newLocatorList.get(mlocIt));
119 // when a locator appears in both lists, keep the new (merged) one and skip the old
120 mergedLocators.add(newLocatorList.get(mlocIt));
125 while (locIt < locators.size()) {
126 mergedLocators.add(locators.get(locIt));
129 while (mlocIt < newLocatorList.size()) {
130 mergedLocators.add(newLocatorList.get(mlocIt));
133 mrb.setLocatorRecord(mergedLocators);
137 public static MappingRecord mergeMappings(MappingRecord currentMergedMapping, MappingRecord newMapping,
138 XtrId xtrId, Date regdate) {
139 if (currentMergedMapping == null) {
143 MappingRecordBuilder mrb = new MappingRecordBuilder(currentMergedMapping);
144 mergeCommonMappingRecordFields(mrb, newMapping);
145 mergeLocatorRecords(mrb, newMapping);
149 mrb.setTimestamp(regdate.getTime());
155 public static ExtendedMappingRecord mergeXtrIdMappings(List<Object> extendedRecords, List<XtrId> expiredMappings,
156 Set<IpAddressBinary> sourceRlocs) {
157 MappingRecordBuilder mrb = null;
159 Long timestamp = Long.MAX_VALUE;
161 for (int i = 0; i < extendedRecords.size(); i++) {
162 ExtendedMappingRecord extendedRecord = (ExtendedMappingRecord) extendedRecords.get(i);
163 MappingRecord record = extendedRecord.getRecord();
165 // Skip expired mappings and add them to a list to be returned to the caller
166 if (timestampIsExpired(extendedRecord.getTimestamp())) {
167 expiredMappings.add(record.getXtrId());
172 mrb = new MappingRecordBuilder(record);
175 // Save the oldest valid timestamp
176 if (extendedRecord.getTimestamp().getTime() < timestamp) {
177 timestamp = extendedRecord.getTimestamp().getTime();
178 xtrId = record.getXtrId();
181 // Merge record fields and locators
182 mergeCommonMappingRecordFields(mrb, record);
183 mergeLocatorRecords(mrb, record);
185 // Save source locator for use in Map-Notify
186 sourceRlocs.add(record.getSourceRloc());
190 LOG.warn("All mappings expired when merging! Unexpected!");
195 return new ExtendedMappingRecord(mrb.build(), new Date(timestamp));
198 public static boolean mappingIsExpired(ExtendedMappingRecord mapping) {
199 Preconditions.checkNotNull(mapping, "mapping should not be null!");
200 if (mapping.getTimestamp() != null) {
201 return timestampIsExpired(mapping.getTimestamp());
206 public static boolean timestampIsExpired(Date timestamp) {
207 Preconditions.checkNotNull(timestamp, "timestamp should not be null!");
208 return timestampIsExpired(timestamp.getTime());
211 public static boolean timestampIsExpired(Long timestamp) {
212 Preconditions.checkNotNull(timestamp, "timestamp should not be null!");
213 if ((System.currentTimeMillis() - timestamp) > MIN_REGISTRATION_VALIDITY_SB ) {