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=a8f5ba0ad80106f09c42f56119775b0463c8c101;hb=229e4c5da1caa0d7d9715feb9051f732b35c2da5;hp=356744a2cddf4f4550baed593c8af700d3bb02df;hpb=4bc1360e78f992f8d2ea77282bcae53804a3114c;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 356744a2c..a8f5ba0ad 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Contextream, Inc. and others. All rights reserved. + * Copyright (c) 2014 Contextream, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -8,164 +8,294 @@ package org.opendaylight.lispflowmapping.implementation.lisp; +import java.net.InetAddress; +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; -import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.opendaylight.controller.md.sal.binding.api.NotificationService; import org.opendaylight.lispflowmapping.implementation.authentication.LispAuthenticationUtil; -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.MappingServiceKeyUtil; -import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceRLOC; -import org.opendaylight.lispflowmapping.interfaces.dao.MappingServiceValue; -import org.opendaylight.lispflowmapping.interfaces.lisp.IMapServer; -import org.opendaylight.lispflowmapping.type.lisp.EidToLocatorRecord; -import org.opendaylight.lispflowmapping.type.lisp.LocatorRecord; -import org.opendaylight.lispflowmapping.type.lisp.MapNotify; -import org.opendaylight.lispflowmapping.type.lisp.MapRegister; -import org.opendaylight.lispflowmapping.type.lisp.address.IMaskable; -import org.opendaylight.lispflowmapping.type.lisp.address.LispAddress; +import org.opendaylight.lispflowmapping.implementation.config.ConfigIni; +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.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.IpAddress; +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.lisp.proto.rev151105.MapRegister; +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.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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MapServer implements IMapServer { - private ILispDAO dao; - private volatile boolean shouldAuthenticate; - private volatile boolean shouldIterateMask; - protected static final Logger logger = LoggerFactory.getLogger(MapServer.class); +import com.google.common.base.Preconditions; - public MapServer(ILispDAO dao) { - this(dao, true); +public class MapServer implements IMapServerAsync, OdlMappingserviceListener { + + protected static final Logger LOG = LoggerFactory.getLogger(MapServer.class); + private IMappingService mapService; + private boolean authenticate; + private boolean subscriptionService; + private IMapNotifyHandler notifyHandler; + private NotificationService notificationService; + + public MapServer(IMappingService mapService, boolean authenticate, boolean subscriptionService, + IMapNotifyHandler notifyHandler, NotificationService notificationService) { + Preconditions.checkNotNull(mapService); + this.mapService = mapService; + this.authenticate = authenticate; + this.subscriptionService = subscriptionService; + this.notifyHandler = notifyHandler; + this.notificationService = notificationService; + if (notificationService != null) { + notificationService.registerNotificationListener(this); + } } - public MapServer(ILispDAO dao, boolean authenticate) { - this(dao, authenticate, true); + @Override + public void setSubscriptionService(boolean subscriptionService) { + this.subscriptionService = subscriptionService; } - public MapServer(ILispDAO dao, boolean authenticate, boolean iterateAuthenticationMask) { - this.dao = dao; - this.shouldAuthenticate = authenticate; - this.shouldIterateMask = iterateAuthenticationMask; + @Override + public boolean shouldAuthenticate() { + return authenticate; } - public MapNotify handleMapRegister(MapRegister mapRegister) { - if (dao == null) { - logger.warn("handleMapRegister called while dao is uninitialized"); - return null; - } + @Override + public void setShouldAuthenticate(boolean shouldAuthenticate) { + authenticate = shouldAuthenticate; + } + + @SuppressWarnings("unchecked") + public void handleMapRegister(MapRegister mapRegister) { + boolean authFailed = false; String password = null; - EidToLocatorRecord eidRecord = mapRegister.getEidToLocatorRecords().get(0); - if (shouldAuthenticate) { - password = getPassword(eidRecord.getPrefix(), eidRecord.getMaskLength()); - if (!LispAuthenticationUtil.validate(mapRegister, password)) { - logger.debug("Authentication failed"); - return null; + Set subscribers = null; + MappingRecord oldMapping; + + for (MappingRecordItem record : mapRegister.getMappingRecordItem()) { + MappingRecord mapping = record.getMappingRecord(); + if (authenticate) { + MappingAuthkey authkey = mapService.getAuthenticationKey(mapping.getEid()); + if (authkey != null) { + password = authkey.getKeyString(); + } + if (!LispAuthenticationUtil.validate(mapRegister, password)) { + LOG.warn("Authentication failed"); + authFailed = true; + 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; + 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(mapping.getEid()); + sendSmrs(mapping, subscribers); + } } } - MappingServiceValue value = new MappingServiceValue(); - MappingEntry entry = new MappingEntry("value", value); - List rlocs = new ArrayList(); - for (LocatorRecord locatorRecord : eidRecord.getLocators()) { - rlocs.add(new MappingServiceRLOC(locatorRecord, eidRecord.getRecordTtl())); - } - value.setRlocs(rlocs); - IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(eidRecord.getPrefix(), eidRecord.getMaskLength()); - dao.put(key, entry); - - MapNotify mapNotify = null; - if (mapRegister.isWantMapNotify()) { - logger.trace("MapRegister wants MapNotify"); - mapNotify = new MapNotify(); - mapNotify.setFromMapRegister(mapRegister); - if (shouldAuthenticate) { - mapNotify.setAuthenticationData(LispAuthenticationUtil.createAuthenticationData(mapNotify, password)); + if (!authFailed && BooleanUtils.isTrue(mapRegister.isWantMapNotify())) { + LOG.trace("MapRegister wants MapNotify"); + MapNotifyBuilder builder = new MapNotifyBuilder(); + List rlocs = null; + if (ConfigIni.getInstance().mappingMergeIsSet()) { + 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); + } + } + MapNotifyBuilderHelper.setFromMapRegisterAndMappingRecordItems(builder, mapRegister, mergedMappings); + rlocs = getTransportAddresses(notifyRlocs); + } else { + MapNotifyBuilderHelper.setFromMapRegister(builder, mapRegister); + } + if (authenticate) { + builder.setAuthenticationData(LispAuthenticationUtil.createAuthenticationData(builder.build(), + password)); } + notifyHandler.handleMapNotify(builder.build(), rlocs); } - return mapNotify; } - private String getPassword(LispAddress prefix, int maskLength) { - if (prefix instanceof IMaskable) { - prefix = ((IMaskable) prefix).clone(); + private static List getTransportAddresses(Set addresses) { + List rlocs = new ArrayList(); + for (IpAddress address : addresses) { + TransportAddressBuilder tab = new TransportAddressBuilder(); + tab.setIpAddress(address); + tab.setPort(new PortNumber(LispMessage.PORT_NUM)); + rlocs.add(tab.build()); } - while (maskLength > 0) { - IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(prefix, maskLength); - Map daoMap = dao.get(key); - if (daoMap != null) { - MappingServiceValue value = (MappingServiceValue) daoMap.get("value"); - if (value != null && value.getKey() != null) { - return value.getKey(); - } else if (shouldIterateMask()) { - maskLength -= 1; - } else { - return null; - } - } else { - maskLength -= 1; + return rlocs; + } + + private SiteId getSiteId(MapRegister mapRegister) { + return (mapRegister.getSiteId() != null) ? new SiteId(mapRegister.getSiteId()) : null; + } + @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()); } } - return null; } - public String getAuthenticationKey(LispAddress address, int maskLen) { - return getPassword(address, maskLen); + 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 (!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; + } + return false; } - public boolean removeAuthenticationKey(LispAddress address, int maskLen) { - IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(address, maskLen); - Map daoMap = dao.get(key); - if (daoMap != null) { - MappingServiceValue value = (MappingServiceValue) daoMap.get("value"); - if (value != null) { - value.setKey(null); - if (value.isEmpty()) { - dao.remove(key); - } else { - dao.put(key, new MappingEntry("value", value)); - } - return true; - } else { - return false; - } - } else { - return false; + 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 SourceDestKey) { + Eid dstAddr = SourceDestKeyHelper.getDst(eid); + Set dstSubs = getSubscribers(dstAddr); + MappingRecord newRecord = new MappingRecordBuilder(record).setEid(dstAddr).build(); + handleSmr(newRecord.getEid(), dstSubs, notifyHandler); } } - public boolean addAuthenticationKey(LispAddress address, int maskLen, String key) { - IMappingServiceKey mappingServiceKey = MappingServiceKeyUtil.generateMappingServiceKey(address, maskLen); - Map daoMap = dao.get(mappingServiceKey); - MappingServiceValue value = null; - if (daoMap != null) { - value = (MappingServiceValue) daoMap.get("value"); - if (value == null) { - value = new MappingServiceValue(); + private void handleSmr(Eid eid, Set subscribers, IMapNotifyHandler callback) { + if (subscribers == null) { + return; + } + MapRequestBuilder mrb = MapRequestUtil.prepareSMR(eid, LispAddressUtil.toRloc(getLocalAddress())); + LOG.trace("Built SMR packet: " + mrb.build().toString()); + for (SubscriberRLOC subscriber : subscribers) { + if (subscriber.timedOut()) { + LOG.trace("Lazy removing expired subscriber entry " + subscriber.toString()); + subscribers.remove(subscriber); + } else { + try { + // 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)); + } } - } else { - value = new MappingServiceValue(); } - value.setKey(key); - MappingEntry entry = new MappingEntry("value", value); - dao.put(mappingServiceKey, entry); - return true; + addSubscribers(eid, subscribers); } - public boolean shouldAuthenticate() { - return shouldAuthenticate; + @SuppressWarnings("unchecked") + private Set getSubscribers(Eid address) { + return (Set) mapService.getData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS); } - public boolean shouldIterateMask() { - return shouldIterateMask; + private void removeSubscribers(Eid address) { + mapService.removeData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS); } - public void setShouldIterateMask(boolean shouldIterateMask) { - this.shouldIterateMask = shouldIterateMask; + private void addSubscribers(Eid address, Set subscribers) { + mapService.addData(MappingOrigin.Southbound, address, SubKeys.SUBSCRIBERS, subscribers); } - public void setShouldAuthenticate(boolean shouldAuthenticate) { - this.shouldAuthenticate = shouldAuthenticate; + 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; } - }