From caa282a7055d47cb66504781ac12d0eb575964af Mon Sep 17 00:00:00 2001 From: Diego Granados Date: Mon, 16 Jan 2017 11:58:39 +0100 Subject: [PATCH] Bug 3712: SFP validation of SF types at creation time This commit makes use of DOMDataTreeCommitCohorts (callbacks that can be registered in order to participate in commit validation) in order to make sure that newly-added datastore SFPs are consistent with previously defined SFCs and SFs. Specifically, it is checked that the types for the SFs the SFP references are consistent with the SF types that the SFC specifies. Since the datastore commit transaction is kept open during validation, this validation must be as fast as possible. Controller guidelines about not opening new datastore reads in order to validate a DS write have been followed to the maximum extent; for this reason, a datastore cache has been deployed to cover both SFs and SFCs. On systems with less than 500 SFs & SFCs deployed, caches will provide total coverage (i.e. validation will never need to access datastore) Testing: manually tested (complex interactions between controller-mdsal-scf are too hard to simulate). Proper CSIT tests will be delivered to the sfc suites in the integration project. Change-Id: I5886d0be9191043aa8227c242a1498e518b31a38 Signed-off-by: Diego Granados --- sfc-provider/pom.xml | 4 + .../ServiceFunctionChainListener.java | 90 +++++++++++ .../listeners/ServiceFunctionListener.java | 24 ++- .../validators/ServiceFunctionPathCohort.java | 110 +++++++++++++ .../ServiceFunctionPathValidator.java | 144 ++++++++++++++++++ ...aValidationFailedWithMessageException.java | 50 ++++++ .../validators/util/SfcDatastoreCache.java | 84 ++++++++++ .../validators/util/ValidationConstants.java | 63 ++++++++ .../opendaylight/blueprint/sfc-provider.xml | 16 ++ 9 files changed, 579 insertions(+), 6 deletions(-) create mode 100644 sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionChainListener.java create mode 100644 sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/ServiceFunctionPathCohort.java create mode 100644 sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/ServiceFunctionPathValidator.java create mode 100644 sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/DataValidationFailedWithMessageException.java create mode 100644 sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/SfcDatastoreCache.java create mode 100644 sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/ValidationConstants.java diff --git a/sfc-provider/pom.xml b/sfc-provider/pom.xml index a79daf7b2..a40afc94b 100644 --- a/sfc-provider/pom.xml +++ b/sfc-provider/pom.xml @@ -23,6 +23,10 @@ org.opendaylight.controller sal-binding-api + + org.opendaylight.mdsal + mdsal-dom-api + org.opendaylight.controller sal-common-util diff --git a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionChainListener.java b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionChainListener.java new file mode 100644 index 000000000..707bdca42 --- /dev/null +++ b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionChainListener.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017 Ericsson Spain 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.sfc.provider.listeners; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.sfc.provider.validators.util.SfcDatastoreCache; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.ServiceFunctionChains; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class listens to changes (addition, update, removal) in Service + * Functions chains taking the appropriate actions. + */ +public class ServiceFunctionChainListener extends AbstractDataTreeChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(ServiceFunctionChainListener.class); + + private final DataBroker dataBroker; + + private ListenerRegistration listenerRegistration; + + public ServiceFunctionChainListener(final DataBroker dataBroker) { + this.dataBroker = dataBroker; + } + + private void registerListeners() { + final DataTreeIdentifier treeId = new DataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, + InstanceIdentifier.create(ServiceFunctionChains.class).child(ServiceFunctionChain.class)); + listenerRegistration = dataBroker.registerDataTreeChangeListener(treeId, this); + + } + + public void init() { + LOG.debug("ServiceFunctionChainListener:Initializing..."); + registerListeners(); + } + + @Override + public void close() throws Exception { + LOG.debug("Closing listener..."); + if (listenerRegistration != null) { + listenerRegistration.close(); + } + } + + @Override + public void add(ServiceFunctionChain serviceFunctionChain) { + if (serviceFunctionChain != null) { + LOG.debug("add:starting..(new sfc name: {})", serviceFunctionChain.getName()); + List serviceFunctionTypesForChain = new ArrayList(); + for (SfcServiceFunction sfcSf: serviceFunctionChain.getSfcServiceFunction()) { + LOG.debug("add:new sfc sf found; name={}, type={})", sfcSf.getName(), sfcSf.getType().getValue()); + serviceFunctionTypesForChain.add(sfcSf.getType().getValue()); + } + SfcDatastoreCache.getSfChainToSfTypeList().put(serviceFunctionChain.getName(), serviceFunctionTypesForChain); + } + } + + @Override + public void remove(ServiceFunctionChain serviceFunctionChain) { + if (serviceFunctionChain != null) { + LOG.debug("remove: Deleting Service Function chain: {}", serviceFunctionChain.getName()); + SfcDatastoreCache.getSfChainToSfTypeList().invalidate(serviceFunctionChain.getName()); + } + } + + @Override + protected void update(ServiceFunctionChain originalServiceFunctionChain, ServiceFunctionChain updatedServiceFunctionChain) { + if (originalServiceFunctionChain != null && updatedServiceFunctionChain != null) { + LOG.debug("update:Updating Service Function chain: {}", originalServiceFunctionChain.getName()); + SfcDatastoreCache.getSfChainToSfTypeList().invalidate(originalServiceFunctionChain.getName()); + add(updatedServiceFunctionChain); + } + } +} diff --git a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionListener.java b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionListener.java index 6eafe0de0..8fdfabf3c 100644 --- a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionListener.java +++ b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/listeners/ServiceFunctionListener.java @@ -17,6 +17,7 @@ import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI; import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI; import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI; import org.opendaylight.sfc.provider.api.SfcProviderServiceTypeAPI; +import org.opendaylight.sfc.provider.validators.util.SfcDatastoreCache; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions; @@ -36,9 +37,11 @@ import org.slf4j.LoggerFactory; * */ public class ServiceFunctionListener extends AbstractDataTreeChangeListener { + private static final Logger LOG = LoggerFactory.getLogger(ServiceFunctionListener.class); private final DataBroker dataBroker; + private ListenerRegistration listenerRegistration; public ServiceFunctionListener(final DataBroker dataBroker) { @@ -52,6 +55,7 @@ public class ServiceFunctionListener extends AbstractDataTreeChangeListener treeId = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(ServiceFunctions.class).child(ServiceFunction.class)); + listenerRegistration = dataBroker.registerDataTreeChangeListener(treeId, this); } @Override public void add(ServiceFunction serviceFunction) { if (serviceFunction != null) { - LOG.debug("Adding Service Function: {}", serviceFunction.getName()); - + LOG.debug("add: storing name [{}] type [{}]", serviceFunction.getName().getValue(), + serviceFunction.getType().getValue()); + SfcDatastoreCache.getSfToSfTypeCache().put(serviceFunction.getName(), serviceFunction.getType().getValue()); if (!SfcProviderServiceTypeAPI.createServiceFunctionTypeEntry(serviceFunction)) { - LOG.error("Failed to create Service Function: ", serviceFunction.getName()); + LOG.error("add:Failed to create Service Function: ", serviceFunction.getName()); } } } @@ -78,10 +84,14 @@ public class ServiceFunctionListener extends AbstractDataTreeChangeListener infos = BindingReflections.loadModuleInfos(); + BindingRuntimeContext bindingContext; + BindingNormalizedNodeCodecRegistry codecRegistry = + new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator + .create(JavassistUtils.forClassPool(ClassPool.getDefault()))); + ServiceFunctionPathValidator sfpv; + + public ServiceFunctionPathCohort(ServiceFunctionPathValidator sfpv) { + this.sfpv = sfpv; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public CheckedFuture canCommit( + Object txId, DOMDataTreeCandidate candidate, + SchemaContext ctx) { + + LOG.debug("canCommit:called! txId={}, candidate={}, context={} ", txId, candidate, ctx); + + DataTreeCandidateNode candidateRoot = candidate.getRootNode(); + NormalizedNode nn = candidateRoot.getDataAfter().orNull(); + if (nn == null) { + LOG.debug("canCommit:no sfp after the change"); + return ValidationConstants.SUCCESS_CAN_COMMIT_FUTURE; + } + + LOG.debug("canCommit:updating codec contexts"); + moduleContext.addModuleInfos(infos); + bindingContext = BindingRuntimeContext.create(moduleContext, ctx); + codecRegistry.onBindingRuntimeContextUpdated(bindingContext); + + LOG.debug("canCommit:Mapping service ready"); + + LOG.debug("canCommit:before deserializing: {}", nn); + //(nn is an immutableMapNode). Contains an unmodifiable collection + // reference of all this thing + //https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Design:Normalized_DOM_Model + Collection c = (Collection) nn.getValue(); + LOG.debug("canCommit:collection containing the sfs: {}", c); + Iterator menIter = (Iterator)c.iterator(); + while (menIter.hasNext()) { + MapEntryNode meNode = menIter.next(); + LOG.debug("canCommit:sfp to process: {}", meNode); + NormalizedNode sfpAsNormalizedNode = meNode; + LOG.debug("canCommit:the first SF (as nn): {}", sfpAsNormalizedNode); + DataObject dobj = codecRegistry.fromNormalizedNode(ValidationConstants.SFP_PATH_YII, sfpAsNormalizedNode).getValue(); + LOG.debug("canCommit:registerValidationCohorts:the first SFP (as dataobject): {}", dobj); + ServiceFunctionPath sfp = (ServiceFunctionPath)dobj; + LOG.debug("canCommit:registerValidationCohorts:the implemented interface: {}", dobj.getImplementedInterface()); + LOG.debug("canCommit:the first SF (as binding representation): {}", sfp); + try { + if (!sfpv.validateServiceFunctionPath(sfp)) { + return ValidationConstants.FAILED_CAN_COMMIT_SFP_FUTURE; + } + } catch (DataValidationFailedException dvfe) { + return Futures.immediateFailedCheckedFuture(dvfe); + } + } + return ValidationConstants.SUCCESS_CAN_COMMIT_FUTURE; + }} diff --git a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/ServiceFunctionPathValidator.java b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/ServiceFunctionPathValidator.java new file mode 100644 index 000000000..aa7ccc9d5 --- /dev/null +++ b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/ServiceFunctionPathValidator.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 Ericsson Spain 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.sfc.provider.validators; + +import java.util.List; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry; +import org.opendaylight.sfc.provider.validators.util.ValidationConstants; +import org.opendaylight.sfc.provider.validators.util.DataValidationFailedWithMessageException; +import org.opendaylight.sfc.provider.validators.util.SfcDatastoreCache; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class performs pre-commit validation for new / modified SFPs in + * order to guarantee that the SFs it specifies are consistent with + * the types specified in the associated SF chain + * @author Diego Granados (diego.jesus.granados.lopez@ericsson.com) + */ +public class ServiceFunctionPathValidator { + private static final Logger LOG = LoggerFactory.getLogger(ServiceFunctionPathValidator.class); + + private final DOMDataTreeCommitCohortRegistry registry; + + public ServiceFunctionPathValidator(final DOMDataBroker domDataBroker) { + this.registry = (DOMDataTreeCommitCohortRegistry)domDataBroker + .getSupportedExtensions() + .get(org.opendaylight.controller.md.sal.dom.api.DOMDataTreeCommitCohortRegistry.class); + } + + public void init() { + LOG.debug("ServiceFunctionPathValidator:Initializing..."); + registerValidationCohorts(); + } + + private void registerValidationCohorts() { + + ServiceFunctionPathCohort myCohort = new ServiceFunctionPathCohort(this); + + LOG.debug("registerValidationCohorts: sfp cohort created"); + registry.registerCommitCohort(ValidationConstants.SFP_ID, myCohort); + LOG.info("registerValidationCohorts:initialized. registered cohort: {}", myCohort); + + } + + public void close() throws Exception { + LOG.debug("close(): closing sfp validator ..."); + } + + /** + * Performs validation of a service function path + * @param serviceFunctionPath a candidate SFP that is being added / updated in a currently open transaction + * @return true when validation is passed (i.e. when the SFs contained in the SFP are coherent (type-wise) + * with the type definitions in the associated SFC; false afterwards) + * @throws DataValidationFailedWithMessageException when validation cannot be performed because some of the + * referenced SFs / SFCs do not exist + */ + protected boolean validateServiceFunctionPath( + ServiceFunctionPath serviceFunctionPath) throws DataValidationFailedWithMessageException { + if (serviceFunctionPath != null) { + LOG.debug("ServiceFunctionPathListener:validateServiceFunctionPath:starting..(new sfc name: {})", + serviceFunctionPath.getName()); + + if (serviceFunctionPath.getServicePathHop() == null) { + // no hops defined in SFP -> nothing to validate + LOG.info("ServiceFunctionPathListener:validateServiceFunctionPath:" + + "SFP without explicit hop definition -> validation not required"); + return true; + } + + // 1. Get the size of the list of SF names in the SFP + int numberOfSpecifiedSFs = serviceFunctionPath.getServicePathHop().size(); + + // 2. Get the SF types referenced in the chain (fail if can't find the chain) + List sfChainTypes; + try { + sfChainTypes = SfcDatastoreCache.getSfChainToSfTypeList() + .get(serviceFunctionPath.getServiceChainName()); + } catch (Exception e) { + throw ValidationConstants.SFP_FAILED_CAN_COMMIT_EXCEPTION_SFC_MISSING; + } + + // 3. Referential integrity (SFC) + if (sfChainTypes == null || sfChainTypes.isEmpty()) { + LOG.error("validateServiceFunctionPath:: ERROR! (no sf chains defined!)"); + throw ValidationConstants.SFP_FAILED_CAN_COMMIT_EXCEPTION_SFC_MISSING; + } + + // 4. Correct number of values in SFC types, SFs in the SFP + LOG.debug("validateServiceFunctionPath:retrieved SFC {} for SFP {}); they have {}, {} elements respectively", + serviceFunctionPath.getServiceChainName().getValue(), + serviceFunctionPath.getName().getValue(), + sfChainTypes.size(), numberOfSpecifiedSFs); + + // A chain can have more elements than the list of service functions, but not the other way around + // (A SFP can choose to set all or only some of the SFs in the path) + if (sfChainTypes.size() < numberOfSpecifiedSFs) { + LOG.error( + "validateServiceFunctionPath: ERROR! (incorrect chain-path list sizes [chain={}, path={}])", + sfChainTypes.size(), + numberOfSpecifiedSFs); + return false; + } + + // 5. SF type matching + boolean errorFound = false; + for (int i = 0; i < numberOfSpecifiedSFs; i++) { + SfName sfName = serviceFunctionPath.getServicePathHop().get(i).getServiceFunctionName(); + if (sfName == null) { + continue; + } + String sfChainTypeName = sfChainTypes.get(serviceFunctionPath.getServicePathHop().get(i).getHopNumber()); + + String sfTypeNameFromSFP; + try { + sfTypeNameFromSFP = SfcDatastoreCache.getSfToSfTypeCache() + .get(sfName); + } catch (Exception e) { + throw ValidationConstants.SFP_FAILED_CAN_COMMIT_EXCEPTION_SF_MISSING; + } + + if (!sfChainTypeName.equals(sfTypeNameFromSFP)) { + LOG.error( + "validateServiceFunctionPath: error on SFP validation! element with index {} is not of the correct type [{}/{}]", + i, sfChainTypeName, sfTypeNameFromSFP); + errorFound = true; + break; + } + } + if (!errorFound) { + LOG.info("validateServiceFunctionPath:SFP validation passed!"); + return true; + } + } + return false; + } +} diff --git a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/DataValidationFailedWithMessageException.java b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/DataValidationFailedWithMessageException.java new file mode 100644 index 000000000..f2fc886e0 --- /dev/null +++ b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/DataValidationFailedWithMessageException.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 Ericsson Spain 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.sfc.provider.validators.util; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.mdsal.common.api.DataValidationFailedException; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import com.google.common.base.MoreObjects; + +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; + +@SuppressWarnings("serial") +/** + * Specific data validation exception for SFP validation. Not working + * yet (pending custom error message support on other projects) + */ +public class DataValidationFailedWithMessageException extends DataValidationFailedException { + + private List myErrorList = new ArrayList(); + + public

> DataValidationFailedWithMessageException(final Class

pathType,final P path, + final String message, final String appTag) { + super(pathType, path, message); + myErrorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION, "invalid-value", message, appTag, + path != null ? path.toString() : null, null)); + } + + @Override + public List getErrorList() { + return myErrorList; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("message", getMessage()) + .add("errorList", this.myErrorList).toString(); + } +} + + diff --git a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/SfcDatastoreCache.java b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/SfcDatastoreCache.java new file mode 100644 index 000000000..ecfb593f4 --- /dev/null +++ b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/SfcDatastoreCache.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2017 Ericsson Spain 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.sfc.provider.validators.util; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI; +import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.service.function.chain.SfcServiceFunction; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +/** + * SFC caching layer for datastore access. Used for allowing creation-time validation + * of SF paths (during which the write transaction is kept open) to be performed + * without datastore accesses in most cases + * @author Diego Granados (diego.jesus.granados.lopez@ericsson.com) + */ +public class SfcDatastoreCache { + + /** + * This cache stores the relationship between SFs and SF types + */ + private static LoadingCache sfToSfTypeCache = CacheBuilder.newBuilder() + .maximumSize(500) + .build(new CacheLoader() { + @Override + public String load(SfName key) { + ServiceFunction sf = SfcProviderServiceFunctionAPI.readServiceFunction(key); + if (sf == null) { + return null; + } + return sf.getType().getValue().toString(); + } + }); + + /** + * This cache holds the relation between SF chains and the list of SF types for the chain + */ + private static LoadingCache> sfChainToSfTypeList = CacheBuilder.newBuilder() + .maximumSize(500) + .build(new CacheLoader>() { + @Override + public List load(SfcName key) { + ServiceFunctionChain serviceFunctionChain = SfcProviderServiceChainAPI.readServiceFunctionChain(key); + if (serviceFunctionChain == null) { + return null; + } + List serviceFunctionTypesForChain = new ArrayList(); + //SfcServiceFunction sfcSf = null; + for (SfcServiceFunction sfcSf: serviceFunctionChain.getSfcServiceFunction()) { + serviceFunctionTypesForChain.add(sfcSf.getType().getValue()); + } + return serviceFunctionTypesForChain; + } + }); + + /** + * @return the cache holding the association between SF names and SF types + */ + public static LoadingCache getSfToSfTypeCache() { + return sfToSfTypeCache; + } + + /** + * @return the cache holding the association between service function chains + * and SF types in that chain + */ + public static LoadingCache> getSfChainToSfTypeList() { + return sfChainToSfTypeList; + } +} diff --git a/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/ValidationConstants.java b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/ValidationConstants.java new file mode 100644 index 000000000..ecae8f865 --- /dev/null +++ b/sfc-provider/src/main/java/org/opendaylight/sfc/provider/validators/util/ValidationConstants.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 Ericsson Spain 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.sfc.provider.validators.util; + +import org.opendaylight.mdsal.common.api.DataValidationFailedException; +import org.opendaylight.mdsal.common.api.PostCanCommitStep; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; + +public class ValidationConstants { + + /** + * Yang instance identifiers + */ + public static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier SF_PATH_YII = + YangInstanceIdentifier.builder().node(ServiceFunctions.QNAME).node(ServiceFunction.QNAME).build(); + + public static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier SFP_PATH_YII = + YangInstanceIdentifier.builder().node(ServiceFunctionPaths.QNAME).node(ServiceFunctionPath.QNAME).build(); + + /** + * DOM data tree identifiers + */ + public static final DOMDataTreeIdentifier SF_ID = + new DOMDataTreeIdentifier(org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION, SF_PATH_YII); + + public static final DOMDataTreeIdentifier SFP_ID = + new DOMDataTreeIdentifier(org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION, SFP_PATH_YII); + + /** + * Exceptions + */ + public static final DataValidationFailedWithMessageException SFP_FAILED_CAN_COMMIT_EXCEPTION_SF_MISSING = + new DataValidationFailedWithMessageException(YangInstanceIdentifier.class, SFP_PATH_YII, + "The SF referenced in the SF Path does not exist", "SFC validation error"); + + public static final DataValidationFailedWithMessageException SFP_FAILED_CAN_COMMIT_EXCEPTION_SFC_MISSING = + new DataValidationFailedWithMessageException(YangInstanceIdentifier.class, SFP_PATH_YII, + "The SF chain referenced in the SF Path does not exist", "SFC validation error"); + + public static final DataValidationFailedWithMessageException SFP_FAILED_CAN_COMMIT_EXCEPTION_SF_CONSISTENCY = + new DataValidationFailedWithMessageException(YangInstanceIdentifier.class, SFP_PATH_YII, + "SF/ SF types are not consistent with those defined in the SFC", "SFC validation error"); + /** + * Futures + */ + public static final CheckedFuture FAILED_CAN_COMMIT_SFP_FUTURE = + Futures.immediateFailedCheckedFuture(SFP_FAILED_CAN_COMMIT_EXCEPTION_SF_CONSISTENCY); + public static final CheckedFuture SUCCESS_CAN_COMMIT_FUTURE = + Futures.immediateCheckedFuture(PostCanCommitStep.NOOP); +} diff --git a/sfc-provider/src/main/resources/org/opendaylight/blueprint/sfc-provider.xml b/sfc-provider/src/main/resources/org/opendaylight/blueprint/sfc-provider.xml index 125895c13..8a665cf88 100644 --- a/sfc-provider/src/main/resources/org/opendaylight/blueprint/sfc-provider.xml +++ b/sfc-provider/src/main/resources/org/opendaylight/blueprint/sfc-provider.xml @@ -7,6 +7,10 @@ interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" odl:type="default" /> + + @@ -20,6 +24,18 @@ + + + + + + + + -- 2.36.6