blob: 81813f82ca35509a20ef3d4b364d97db8dc632f6 [file] [log] [blame]
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.incubator.net.l2monitoring.cfm.impl;
import com.google.common.net.InternetDomainName;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.MacAddress;
import org.onlab.util.Identifier;
import org.onlab.util.KryoNamespace;
import org.onosproject.incubator.net.l2monitoring.cfm.DefaultComponent;
import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
import org.onosproject.incubator.net.l2monitoring.cfm.service.MdEvent;
import org.onosproject.incubator.net.l2monitoring.cfm.service.MdStore;
import org.onosproject.incubator.net.l2monitoring.cfm.service.MdStoreDelegate;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.MapEvent;
import org.onosproject.store.service.MapEventListener;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Maintenance Domain Store implementation backed by consistent map.
*/
@Component(immediate = true)
@Service
public class DistributedMdStore extends AbstractStore<MdEvent, MdStoreDelegate>
implements MdStore {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
private ConsistentMap<MdId, MaintenanceDomain> maintenanceDomainConsistentMap;
private Map<MdId, MaintenanceDomain> maintenanceDomainMap;
private MapEventListener<MdId, MaintenanceDomain> mapListener = null;
@Activate
public void activate() {
maintenanceDomainConsistentMap = storageService
.<MdId, MaintenanceDomain>consistentMapBuilder()
.withName("onos-cfm-ma-map")
.withSerializer(Serializer.using(new KryoNamespace.Builder()
.register(KryoNamespaces.API)
.register(DefaultMaintenanceDomain.class)
.register(MdIdCharStr.class)
.register(MdIdDomainName.class)
.register(MdIdMacUint.class)
.register(MdIdNone.class)
.register(MaintenanceDomain.MdLevel.class)
.register(DefaultMaintenanceAssociation.class)
.register(MaIdCharStr.class)
.register(MaIdShort.class)
.register(MaId2Octet.class)
.register(MaIdIccY1731.class)
.register(MaIdPrimaryVid.class)
.register(MaIdRfc2685VpnId.class)
.register(MaintenanceAssociation.CcmInterval.class)
.register(DefaultComponent.class)
.register(MepId.class)
.register(Identifier.class)
.register(InternetDomainName.class)
.register(MacAddress.class)
.register(ImmutablePair.class)
.register(org.onosproject.incubator.net.l2monitoring.cfm.Component.MhfCreationType.class)
.register(org.onosproject.incubator.net.l2monitoring.cfm.Component.IdPermissionType.class)
.register(org.onosproject.incubator.net.l2monitoring.cfm.Component.TagType.class)
.build("md")))
.build();
mapListener = new InternalMdListener();
maintenanceDomainConsistentMap.addListener(mapListener);
maintenanceDomainMap = maintenanceDomainConsistentMap.asJavaMap();
log.info("MDStore started");
}
@Deactivate
public void deactivate() {
maintenanceDomainConsistentMap.removeListener(mapListener);
log.info("Stopped");
}
@Override
public Collection<MaintenanceDomain> getAllMaintenanceDomain() {
return maintenanceDomainMap.values();
}
@Override
public Optional<MaintenanceDomain> getMaintenanceDomain(MdId mdName) {
return Optional.ofNullable(
maintenanceDomainMap.get(mdName));
}
@Override
public boolean deleteMaintenanceDomain(MdId mdName) {
return maintenanceDomainMap.remove(mdName) == null ? false : true;
}
@Override
public boolean createUpdateMaintenanceDomain(MaintenanceDomain md) {
return maintenanceDomainMap.put(md.mdId(), md) == null ? false : true;
}
private class InternalMdListener implements MapEventListener<MdId, MaintenanceDomain> {
@Override
public void event(MapEvent<MdId, MaintenanceDomain> mapEvent) {
final MdEvent.Type type;
MaIdShort maId = null;
switch (mapEvent.type()) {
case INSERT:
type = MdEvent.Type.MD_ADDED;
break;
case UPDATE:
// Examine the diff to see if it was a removal or addition of an MA caused it
if (mapEvent.oldValue().value().maintenanceAssociationList().size() >
mapEvent.newValue().value().maintenanceAssociationList().size()) {
Set<MaIdShort> newMaIds = mapEvent.newValue().value().maintenanceAssociationList()
.stream()
.map(MaintenanceAssociation::maId)
.collect(Collectors.toSet());
Optional<MaintenanceAssociation> removedMa =
mapEvent.oldValue().value().maintenanceAssociationList()
.stream()
.filter(maOld -> !newMaIds.contains(maOld.maId())).findFirst();
if (removedMa.isPresent()) {
maId = removedMa.get().maId();
}
type = MdEvent.Type.MA_REMOVED;
} else if (mapEvent.oldValue().value().maintenanceAssociationList().size() <
mapEvent.newValue().value().maintenanceAssociationList().size()) {
Set<MaIdShort> oldMaIds = mapEvent.oldValue().value().maintenanceAssociationList()
.stream()
.map(MaintenanceAssociation::maId)
.collect(Collectors.toSet());
Optional<MaintenanceAssociation> addedMa =
mapEvent.newValue().value().maintenanceAssociationList()
.stream()
.filter(maNew -> !oldMaIds.contains(maNew.maId())).findFirst();
if (addedMa.isPresent()) {
maId = addedMa.get().maId();
}
type = MdEvent.Type.MA_ADDED;
} else {
type = MdEvent.Type.MD_UPDATED;
}
break;
case REMOVE:
default:
type = MdEvent.Type.MD_REMOVED;
break;
}
if (mapEvent.oldValue() != null && mapEvent.oldValue().value() != null) {
MaintenanceDomain oldMd = mapEvent.oldValue().value();
try {
if (maId != null) {
notifyDelegate(new MdEvent(type, mapEvent.key(), oldMd, maId));
} else {
notifyDelegate(new MdEvent(type, mapEvent.key(), oldMd));
}
} catch (CfmConfigException e) {
log.warn("Unable to copy MD {}", oldMd);
notifyDelegate(new MdEvent(type, mapEvent.key()));
}
} else {
notifyDelegate(new MdEvent(type, mapEvent.key()));
}
}
}
}