From 308d77bccb620c7cf580e0bb983610070bf20150 Mon Sep 17 00:00:00 2001 From: Thomas Bachman Date: Sat, 11 Apr 2015 18:37:28 -0400 Subject: [PATCH] Implement SFC integration - Query based on Chainname - Validate Chain before moving from CONF to OPER - Added ChainAction - Added things in SwitchManager/EndpointManager to modify READY state so we don't write flows to switches with no endpoints Change-Id: I84d2549a444f10ddabed146f857af38d0e6369c0 Signed-off-by: Keith Burns (alagalah) --- commons/parent/pom.xml | 1 + distribution-karaf/pom.xml | 41 ++ features/pom.xml | 40 ++ features/src/main/resources/features.xml | 15 +- .../resolver/ActionInstanceValidator.java | 9 + .../resolver/PolicyResolver.java | 81 +++- renderers/ofoverlay/pom.xml | 12 +- .../renderer/ofoverlay/OFOverlayRenderer.java | 4 +- .../renderer/ofoverlay/PolicyManager.java | 6 + .../renderer/ofoverlay/SfcManager.java | 398 ++++++++++++++++++ .../ofoverlay/flow/DestinationMapper.java | 1 + .../renderer/ofoverlay/flow/FlowUtils.java | 160 +++++++ .../renderer/ofoverlay/flow/GroupTable.java | 7 +- .../ofoverlay/flow/PolicyEnforcer.java | 90 +++- .../renderer/ofoverlay/flow/SourceMapper.java | 1 + .../ofoverlay/node/SwitchManager.java | 3 + .../renderer/ofoverlay/sf/Action.java | 9 +- .../renderer/ofoverlay/sf/AllowAction.java | 13 +- .../renderer/ofoverlay/sf/ChainAction.java | 277 ++++++++++++ .../ofoverlay/sf/SubjectFeatures.java | 10 +- .../sfcutils/SfcDataStoreHelper.java | 68 +++ .../ofoverlay/sfcutils/SfcIidFactory.java | 40 ++ .../ofoverlay/flow/SourceMapperTest.java | 31 +- .../ofoverlay/node/MockSwitchManager.java | 1 + 24 files changed, 1272 insertions(+), 46 deletions(-) create mode 100644 groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java create mode 100644 renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java create mode 100644 renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java create mode 100644 renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java create mode 100644 renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java diff --git a/commons/parent/pom.xml b/commons/parent/pom.xml index fdfb3de03..79a878b85 100644 --- a/commons/parent/pom.xml +++ b/commons/parent/pom.xml @@ -30,6 +30,7 @@ ${project.build.directory}/site/models 0.3.0-SNAPSHOT 1.2.0-SNAPSHOT + 0.1.0-SNAPSHOT 1.2.0-SNAPSHOT 0.7.0-SNAPSHOT 0.1.0-SNAPSHOT diff --git a/distribution-karaf/pom.xml b/distribution-karaf/pom.xml index 47fd9c27b..744e69723 100644 --- a/distribution-karaf/pom.xml +++ b/distribution-karaf/pom.xml @@ -25,6 +25,7 @@ 0.2.0-SNAPSHOT + 0.1.0-SNAPSHOT @@ -45,6 +46,46 @@ xml runtime + + org.opendaylight.sfc + features-sfc + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfc-sb-rest + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfc-ovs + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfcofl2 + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfc-netconf + ${sfc.version} + features + xml + runtime + scm:git:ssh://git.opendaylight.org:29418/groupbasedpolicy.git diff --git a/features/pom.xml b/features/pom.xml index b203d0d6b..9bf94657e 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -56,6 +56,46 @@ features xml + + org.opendaylight.sfc + features-sfc + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfc-sb-rest + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfc-ovs + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfcofl2 + ${sfc.version} + features + xml + runtime + + + org.opendaylight.sfc + features-sfc-netconf + ${sfc.version} + features + xml + runtime + org.opendaylight.openflowplugin features-openflowplugin diff --git a/features/src/main/resources/features.xml b/features/src/main/resources/features.xml index e16767b8e..22d1beab7 100644 --- a/features/src/main/resources/features.xml +++ b/features/src/main/resources/features.xml @@ -20,12 +20,18 @@ mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/${openflowplugin.version}/xml/features mvn:org.opendaylight.ovsdb/southbound-features/${ovsdb.southbound.version}/xml/features + mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features - + + mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features + mvn:org.opendaylight.sfc/features-sfc-sb-rest/${sfc.version}/xml/features + mvn:org.opendaylight.sfc/features-sfc-netconf/${sfc.version}/xml/features mvn:org.opendaylight.controller/features-restconf/${restconf.version}/xml/features + mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features + mvn:org.opendaylight.sfc/features-sfcofl2/${sfc.version}/xml/features odl-mdsal-broker @@ -45,6 +51,13 @@ odl-openflowplugin-flow-services odl-openflowplugin-nxm-extensions odl-ovsdb-southbound-impl + odl-sfc-core + odl-sfc-test-consumer + odl-sfc-sb-rest + odl-sfcofl2 + odl-sfc-ovs + odl-sfc-netconf + odl-sfc-ui mvn:org.opendaylight.groupbasedpolicy/ofoverlay-renderer/${project.version} mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-ofoverlay-config/${project.version}/xml/config diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java new file mode 100644 index 000000000..10079b8f6 --- /dev/null +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/ActionInstanceValidator.java @@ -0,0 +1,9 @@ +package org.opendaylight.groupbasedpolicy.resolver; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance; + + +public interface ActionInstanceValidator { + + boolean isValid(ActionInstance actionInstance); +} diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java index 6afeb3ec8..94d51d567 100644 --- a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java @@ -29,8 +29,14 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -77,6 +83,7 @@ public class PolicyResolver implements AutoCloseable { protected ConcurrentMap resolvedTenants; + /** * Store a policy object for each endpoint group pair. The table is stored * with the key as (consumer, provider). Two endpoints could appear in both @@ -84,6 +91,13 @@ public class PolicyResolver implements AutoCloseable { */ AtomicReference policy = new AtomicReference<>(); + /* + * Store validators for ActionDefinitions from Renderers + * + */ + + protected ConcurrentMap registeredActions = new ConcurrentHashMap<>(); + public PolicyResolver(DataBroker dataProvider, ScheduledExecutorService executor) { super(); @@ -134,6 +148,9 @@ public class PolicyResolver implements AutoCloseable { return tc.tenant.get(); } + public void registerActionDefinitions(ActionDefinitionId actionDefinitionId, ActionInstanceValidator validator) { + registeredActions.putIfAbsent(actionDefinitionId, validator); + } /** * Register a listener to receive update events. * @@ -293,19 +310,25 @@ public class PolicyResolver implements AutoCloseable { } Tenant t = InheritanceUtils.resolveTenant(result.get()); - IndexedTenant it = new IndexedTenant(t); - if (!tenantRef.compareAndSet(ot, it)) { - // concurrent update of tenant policy. Retry - updateTenant(tenantId); - } else { - // Update the policy cache and notify listeners - WriteTransaction wt = dataProvider.newWriteOnlyTransaction(); - wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true); - wt.submit(); - updatePolicy(); + if (isValidTenant(t)) { + IndexedTenant it = new IndexedTenant(t); + if (!tenantRef.compareAndSet(ot, it)) { + // concurrent update of tenant policy. Retry + updateTenant(tenantId); + } else { + // Update the policy cache and notify listeners + WriteTransaction wt = dataProvider.newWriteOnlyTransaction(); + wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true); + wt.submit(); + updatePolicy(); + } } } + + + + @Override public void onFailure(Throwable t) { LOG.error("Count not get tenant {}", tenantId, t); @@ -362,4 +385,42 @@ public class PolicyResolver implements AutoCloseable { } } + + private boolean isValidTenant(Tenant t) { + if(validActionInstances(t.getSubjectFeatureInstances().getActionInstance())) { + return true; + } + return false; + } + + private boolean validActionInstances(List actionInstances) { + for(ActionInstance actionInstance : actionInstances) { + if(!(registeredActions.get(actionInstance.getActionDefinitionId()).isValid(actionInstance))) { + return false; + }; + } + return true; + } + + private boolean validContracts(List contracts) { + for (Contract contract: contracts) { + validateSubjects(contract.getSubject()); + } + return false; + } + + private void validateSubjects(List subjects) { + for(Subject subject: subjects) { + validateRules(subject.getRule()); + } + + } + + private void validateRules(List rules) { + + } + + private void validateActionRefs(List actionRefs) { + + } } diff --git a/renderers/ofoverlay/pom.xml b/renderers/ofoverlay/pom.xml index 1b7fee0af..c248471e0 100644 --- a/renderers/ofoverlay/pom.xml +++ b/renderers/ofoverlay/pom.xml @@ -33,7 +33,17 @@ org.opendaylight.openflowplugin openflowplugin-extension-nicira - + + + org.opendaylight.sfc + sfc-model + ${sfc.version} + + + org.opendaylight.sfc + sfc-provider + ${sfc.version} + junit diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java index 22763f06a..caa3cb56d 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java @@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -34,12 +35,13 @@ import com.google.common.util.concurrent.ListenableFuture; /** * Renderer that uses OpenFlow and OVSDB to implement an overlay network * using Open vSwitch. - * @author readams + */ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener { private static final Logger LOG = LoggerFactory.getLogger(OFOverlayRenderer.class); + private final Uuid ID = new Uuid("934cd993-7bcc-46cf-b150-64fabc92b4e0"); private final DataBroker dataBroker; private final PolicyResolver policyResolver; private final SwitchManager switchManager; diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java index beedc2a86..284028d0d 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java @@ -37,6 +37,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures; import org.opendaylight.groupbasedpolicy.resolver.EgKey; @@ -48,6 +49,7 @@ import org.opendaylight.groupbasedpolicy.util.SingletonTask; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.LearningMode; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; @@ -118,6 +120,10 @@ public class PolicyManager t.submit(); } + for(Entry entry : SubjectFeatures.getActions().entrySet()) { + policyResolver.registerActionDefinitions(entry.getKey(), entry.getValue()); + } + OfContext ctx = new OfContext(dataBroker, rpcRegistry, this, policyResolver, switchManager, endpointManager, executor); diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java new file mode 100644 index 000000000..ca90ef2fb --- /dev/null +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/SfcManager.java @@ -0,0 +1,398 @@ +package org.opendaylight.groupbasedpolicy.renderer.ofoverlay; + +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction; +import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver; +import org.opendaylight.sfc.provider.SfcProviderRpc; +import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI; +import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.ReadRenderedServicePathFirstHopInputBuilder; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.ReadRenderedServicePathFirstHopOutput; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop; +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.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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubjectFeatureInstances; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Manage the state exchanged with SFC + * + * For the Proof of Concept, this manages the + * RenderedServicePathFirstHop elements that + * are retrieved from SFC. + * + */ +public class SfcManager implements AutoCloseable, DataChangeListener { + private static final Logger LOG = + LoggerFactory.getLogger(SfcManager.class); + + private final DataBroker dataBroker; + private final ExecutorService executor; + private final InstanceIdentifier allActionInstancesIid; + private final ListenerRegistration actionListener; + + /* + * local cache of the RSP first hops that we've requested from SFC, + * keyed by RSP name + */ + private final ConcurrentMap rspMap; + + /* + * TODO: these two String defs should move to the common + * "chain" action, once we have it. + */ + // the chain action + public static final String SFC_CHAIN_ACTION = "chain"; + // the parameter used for storing the chain name + public static final String SFC_CHAIN_NAME = "sfc-chain-name"; + + private static enum ActionState { + ADD("add"), + CHANGE("change"), + DELETE("delete"); + + private String state; + + ActionState(String state) { + this.state = state; + } + + @Override + public String toString() { + return this.state; + } + } + + + public SfcManager(DataBroker dataBroker, + PolicyResolver policyResolver, + RpcProviderRegistry rpcRegistry, + ExecutorService executor) { + this.dataBroker = dataBroker; + this.executor = executor; + /* + * Use thread-safe type only because we use an executor + */ + this.rspMap = new ConcurrentHashMap(); + + /* + * For now, listen to all changes in rules + */ + allActionInstancesIid = + InstanceIdentifier.builder(Tenants.class) + .child(Tenant.class) + .child(SubjectFeatureInstances.class) + .child(ActionInstance.class) + .build(); + actionListener = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + allActionInstancesIid, this, DataChangeScope.ONE); + LOG.debug("SfcManager: Started"); + } + + public Set getSfcSourceIps() { + if (rspMap.isEmpty()) return null; + + Set ipAddresses = new HashSet(); + for (RenderedServicePathFirstHop rsp: rspMap.values()) { + if (rsp.getIp() != null) { + ipAddresses.add(rsp.getIp()); + } + } + if (ipAddresses.isEmpty()) return null; + return ipAddresses; + } + + @Override + public void onDataChanged( + AsyncDataChangeEvent, DataObject> actionInstanceNotification) { + + for (DataObject dao : actionInstanceNotification.getCreatedData().values()) { + if (dao instanceof ActionInstance) { + ActionInstance ai = (ActionInstance)dao; + LOG.debug("New ActionInstance created"); + executor.execute(new MatchActionDefTask(ai, null, + ActionState.ADD)); + } + } + + for (InstanceIdentifier iid : actionInstanceNotification.getRemovedPaths()) { + DataObject old = actionInstanceNotification.getOriginalData().get(iid); + if (old instanceof ActionInstance) { + ActionInstance ai = (ActionInstance)old; + executor.execute(new MatchActionDefTask(null, ai, + ActionState.DELETE)); + } + } + + for (Entry, DataObject> entry: + actionInstanceNotification.getUpdatedData().entrySet()) { + DataObject dao = entry.getValue(); + if (dao instanceof ActionInstance) { + ActionInstance nai = (ActionInstance)dao; + ActionInstance oai = null; + InstanceIdentifier iid = entry.getKey(); + DataObject orig = actionInstanceNotification.getOriginalData().get(iid); + if (orig != null) { + oai = (ActionInstance)orig; + /* + * We may have some cleanup here. If the reference to + * the Action Definition changed, or if the Action Instance's + * chain parameter then we're no longer + * an action, and we may need to remove the RSP. + */ + } + + executor.execute(new MatchActionDefTask(nai, oai, + ActionState.CHANGE)); + } + } + } + + /** + * Private internal class that gets the action definition + * referenced by the instance. If the definition has an + * action of "chain" (or whatever we decide to use + * here), then we need to invoke the SFC API to go + * get the chain information, which we'll eventually + * use during policy resolution. + * + */ + private class MatchActionDefTask implements Runnable, + FutureCallback> { + private final ActionState state; + private final ActionInstance actionInstance; + private final ActionInstance originalInstance; + private final InstanceIdentifier adIid; + private final ActionDefinitionId id; + + public MatchActionDefTask(ActionInstance actionInstance, + ActionInstance originalInstance, ActionState state) { + this.actionInstance = actionInstance; + this.originalInstance = originalInstance; + if (actionInstance != null) { + this.id = actionInstance.getActionDefinitionId(); + } else { + this.id = null; + } + this.state = state; + + adIid = InstanceIdentifier.builder(SubjectFeatureDefinitions.class) + .child(ActionDefinition.class, + new ActionDefinitionKey(this.id)) + .build(); + + } + + /** + * Create read transaction with callback to look up + * the Action Definition that the Action Instance + * references. + */ + @Override + public void run() { + ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction(); + ListenableFuture> dao = + rot.read(LogicalDatastoreType.OPERATIONAL, adIid); + Futures.addCallback(dao, this, executor); + + } + + @Override + public void onFailure(Throwable arg0) { + LOG.error("Failure reading ActionDefinition {}", id.getValue()); + } + + /** + * An Action Definition exists - now we need to see + * if the Action Definition is for a chain action, + * and implement the appropriate behavior. If it's + * not a chain action, then we can ignore it. + * + * @param dao + */ + @Override + public void onSuccess(Optional dao) { + LOG.debug("Found ActionDefinition {}", id.getValue()); + if (!dao.isPresent()) return; + + ActionDefinition ad = dao.get(); + if (ad.getId().getValue().equals(ChainAction.ID.getValue())) { + /* + * We have the state we need: + * 1) it's a "CHAIN" action + * 2) the name is defined in the ActionInstance + */ + switch (state) { + case ADD: + /* + * Go get the RSP First Hop + */ + getSfcChain(); + break; + case CHANGE: + /* + * We only care if the named chain changes + */ + changeSfcRsp(); + break; + case DELETE: + /* + * If the instance is deleted, we need to remove + * it from our map. + */ + deleteSfcRsp(); + break; + default: + break; + } + } + } + + private ParameterValue getChainNameParameter(List pvl) { + if (pvl == null) return null; + for (ParameterValue pv: actionInstance.getParameterValue()) { + if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) { + return pv; + } + } + return null; + } + + private void changeSfcRsp() { + ParameterValue newPv = + getChainNameParameter(actionInstance.getParameterValue()); + ParameterValue origPv = + getChainNameParameter(originalInstance.getParameterValue()); + if (!newPv.getStringValue().equals(origPv.getStringValue())) { + if (rspMap.containsKey(origPv.getStringValue())) { + /* + * Flow cleanup will happen as part of the + * resolved policy + * + * TODO: can we guarantee that this + * happens after we remove the RSP?). + */ + rspMap.remove(origPv.getStringValue()); + } + addSfcRsp(); + } + } + + private void deleteSfcRsp() { + ParameterValue pv = + getChainNameParameter(originalInstance.getParameterValue()); + if (pv == null) return; + rspMap.remove(pv.getStringValue()); + } + + /** + * Get the RenderedServicePathFirstHop from SFC + * + * TODO: what if SFC state isn't available at the time of + * this call, but becomes available later? Do we want + * or need some sort of notification handler for this? + */ + private void addSfcRsp() { + ParameterValue pv = + getChainNameParameter(actionInstance.getParameterValue()); + if (pv == null) return; + + LOG.trace("Invoking RPC for chain {}", pv.getStringValue()); + ReadRenderedServicePathFirstHopInputBuilder builder = + new ReadRenderedServicePathFirstHopInputBuilder() + .setName(pv.getStringValue()); + // TODO: make async + Future> result = + SfcProviderRpc.getSfcProviderRpc() + .readRenderedServicePathFirstHop(builder.build()); + + try { + RpcResult output = + result.get(); + if (output.isSuccessful()) { + LOG.trace("RPC for chain {} succeeded!", pv.getStringValue()); + RenderedServicePathFirstHop rspFirstHop = + output.getResult().getRenderedServicePathFirstHop(); + /* + * We won't retry installation in the map + * because the presumption is it's either + * the same object or contain the same + * state. + */ + rspMap.putIfAbsent(pv.getStringValue(), rspFirstHop); + } + } catch (Exception e) { + LOG.warn("Failed ReadRenderedServicePathFirstHop RPC: {}", e); + // TODO: proper exception handling + } + } + + private void getSfcChain() { + ParameterValue pv = + getChainNameParameter(actionInstance.getParameterValue()); + if (pv == null) return; + + LOG.trace("Invoking RPC for chain {}", pv.getStringValue()); + String chainName=pv.getStringValue(); + ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue()); + ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths(); + for(ServiceFunctionPath path: paths.getServiceFunctionPath()) { + if(path.getServiceChainName().equals(chainName)) { + LOG.info("Found path {} for chain {}",path.getName(),path.getServiceChainName()); + } + } + } + } + + /** + * Return the first hop information for the Rendered Service Path + * + * @param rspName + * @return + */ + public RenderedServicePathFirstHop getRspFirstHop(String rspName) { + return rspMap.get(rspName); + } + + @Override + public void close() throws Exception { + if (actionListener != null) actionListener.close(); + + } +} + diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java index 376126b34..dc8e608c1 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/DestinationMapper.java @@ -234,6 +234,7 @@ public class DestinationMapper extends FlowTable { .setInstructions( instructions(applyActionIns(nxLoadTunIdAction(BigInteger.valueOf(epOrd.getFdId()), false), groupAction(Long.valueOf(epOrd.getFdId()))))); + return flowb.build(); } diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java index 8b9a3fbea..2b756eabc 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/FlowUtils.java @@ -78,6 +78,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ge import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.DstChoice; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpShaCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxArpThaCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc1CaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxNshc2CaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIdCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxTunIpv4DstCaseBuilder; @@ -90,6 +92,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionOutputRegNodesNodeTableFlowApplyActionsCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegMoveNodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNsiNodesNodeTableFlowApplyActionsCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionSetNspNodesNodeTableFlowApplyActionsCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.output.reg.grouping.NxOutputReg; @@ -100,6 +106,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMove; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.NxRegMoveBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.move.grouping.nx.reg.move.SrcBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._1.grouping.NxSetNshc1Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._2.grouping.NxSetNshc2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._3.grouping.NxSetNshc3Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nshc._4.grouping.NxSetNshc4Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsi; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsi.grouping.NxSetNsiBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.set.nsp.grouping.NxSetNsp; @@ -107,10 +121,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.SrcChoice; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxArpShaCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxRegCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIdCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcNxTunIpv4DstCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfArpSpaCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.src.choice.grouping.src.choice.SrcOfEthSrcCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlow; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxAugMatchNodesNodeTableFlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc1Key; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc2Key; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc3Key; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNshc4Key; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNsiKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxNspKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg0Key; @@ -122,6 +142,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.ni import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg6Key; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxReg7Key; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.NxmNxTunIdKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._1.grouping.NxmNxNshc1Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._2.grouping.NxmNxNshc2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._3.grouping.NxmNxNshc3Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nshc._4.grouping.NxmNxNshc4Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsi.grouping.NxmNxNsiBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.nsp.grouping.NxmNxNspBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.match.rev140714.nxm.nx.reg.grouping.NxmNxRegBuilder; @@ -343,6 +367,29 @@ public final class FlowUtils { return nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(reg).build(), value); } + // TODO: alagalah Li Need to address nicira yang model to make this extend an NxmNxNshFoo case + // class + + public static Action nxLoadNshc1RegAction(Long value) { + NxSetNshc1 newNshc1 = new NxSetNshc1Builder().setNshc(value).build(); + return new NxActionSetNshc1NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc1(newNshc1).build(); + } + + public static Action nxLoadNshc2RegAction(Long value) { + NxSetNshc2 newNshc2 = new NxSetNshc2Builder().setNshc(value).build(); + return new NxActionSetNshc2NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc2(newNshc2).build(); + } + + public static Action nxLoadNshc3RegAction(Long value) { + NxSetNshc3 newNshc3 = new NxSetNshc3Builder().setNshc(value).build(); + return new NxActionSetNshc3NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc3(newNshc3).build(); + } + + public static Action nxLoadNshc4RegAction(Long value) { + NxSetNshc4 newNshc4 = new NxSetNshc4Builder().setNshc(value).build(); + return new NxActionSetNshc4NodesNodeTableFlowApplyActionsCaseBuilder().setNxSetNshc4(newNshc4).build(); + } + public static Action nxLoadTunIPv4Action(String ipAddress, boolean groupBucket) { int ip = InetAddresses.coerceToInteger(InetAddresses.forString(ipAddress)); long ipl = ip & 0xffffffffL; @@ -391,6 +438,13 @@ public final class FlowUtils { return nxMoveRegAction(srcChoice, dstChoice, 31, false); } + public static Action nxMoveRegTunDstToNshc1() { + return nxMoveRegAction(new SrcNxTunIpv4DstCaseBuilder().setNxTunIpv4Dst(Boolean.TRUE).build(),new DstNxNshc1CaseBuilder().setNxNshc1Dst(Boolean.TRUE).build(),31,false); + } + + public static Action nxMoveTunIdtoNshc2() { + return nxMoveRegAction(new SrcNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), new DstNxNshc2CaseBuilder().setNxNshc2Dst(Boolean.TRUE).build(),31,false); + } public static Action nxMoveRegTunIdAction(Class src, boolean groupBucket) { return nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(src).build(), new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), 31, groupBucket); @@ -478,6 +532,112 @@ public final class FlowUtils { match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m); } + // TODO alagalah Be/Li: Once OFP yang refactored to support container/grouping similar to nxreg + // we can follow same pattern. For now its match/set per nsh header + public static void addNxNshc1RegMatch(MatchBuilder match, Long value) { + List existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList(); + ArrayList extensions = new ArrayList<>(); + if(existingExtensions != null && !existingExtensions.isEmpty()) { + extensions.addAll(existingExtensions); + } + NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc1( + new NxmNxNshc1Builder().setValue(value).build()).build(); + + extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc1Key.class) + .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build()) + .build()); + + GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList( + extensions).build(); + match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m); + } + + public static void addNxNshc2RegMatch(MatchBuilder match, Long value) { + List existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList(); + ArrayList extensions = new ArrayList<>(); + if(existingExtensions != null && !existingExtensions.isEmpty()) { + extensions.addAll(existingExtensions); + } + NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc2( + new NxmNxNshc2Builder().setValue(value).build()).build(); + + extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc2Key.class) + .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build()) + .build()); + + GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList( + extensions).build(); + match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m); + } + + public static void addNxNshc3RegMatch(MatchBuilder match, Long value) { + List existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList(); + ArrayList extensions = new ArrayList<>(); + if(existingExtensions != null && !existingExtensions.isEmpty()) { + extensions.addAll(existingExtensions); + } + NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc3( + new NxmNxNshc3Builder().setValue(value).build()).build(); + + extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc3Key.class) + .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build()) + .build()); + + GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList( + extensions).build(); + match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m); + } + + public static void addNxNshc4RegMatch(MatchBuilder match, Long value) { + List existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList(); + ArrayList extensions = new ArrayList<>(); + if(existingExtensions != null && !existingExtensions.isEmpty()) { + extensions.addAll(existingExtensions); + } + NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxNshc4( + new NxmNxNshc4Builder().setValue(value).build()).build(); + + extensions.add(new ExtensionListBuilder().setExtensionKey(NxmNxNshc4Key.class) + .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build()) + .build()); + + GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList( + extensions).build(); + match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m); + } + + public static void addNxNshcMatch(MatchBuilder match, RegMatch... matches) { + ArrayList extensions = new ArrayList<>(); + for (RegMatch rm : matches) { + Class key; + if (NxmNxReg0.class.equals(rm.reg)) { + key = NxmNxReg0Key.class; + } else if (NxmNxReg1.class.equals(rm.reg)) { + key = NxmNxReg1Key.class; + } else if (NxmNxReg2.class.equals(rm.reg)) { + key = NxmNxReg2Key.class; + } else if (NxmNxReg3.class.equals(rm.reg)) { + key = NxmNxReg3Key.class; + } else if (NxmNxReg4.class.equals(rm.reg)) { + key = NxmNxReg4Key.class; + } else if (NxmNxReg5.class.equals(rm.reg)) { + key = NxmNxReg5Key.class; + } else if (NxmNxReg6.class.equals(rm.reg)) { + key = NxmNxReg6Key.class; + } else { + key = NxmNxReg7Key.class; + } + NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxReg( + new NxmNxRegBuilder().setReg(rm.reg).setValue(rm.value).build()).build(); + extensions.add(new ExtensionListBuilder().setExtensionKey(key) + .setExtension(new ExtensionBuilder().addAugmentation(NxAugMatchNodesNodeTableFlow.class, am).build()) + .build()); + } + GeneralAugMatchNodesNodeTableFlow m = new GeneralAugMatchNodesNodeTableFlowBuilder().setExtensionList( + extensions).build(); + match.addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, m); + } + public static void addNxTunIdMatch(MatchBuilder match, int tunId) { NxAugMatchNodesNodeTableFlow am = new NxAugMatchNodesNodeTableFlowBuilder().setNxmNxTunId( new NxmNxTunIdBuilder().setValue(BigInteger.valueOf(tunId)).build()).build(); diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java index f6fdca252..3c7ab98a7 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java @@ -205,11 +205,10 @@ public class GroupTable extends OfTable { destNode); continue; } + BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId))).setAction(actionList(tundstAction, outputAction(tunPort))); + + - BucketBuilder bb = new BucketBuilder() - .setBucketId(new BucketId(Long.valueOf(bucketId))) - .setAction(actionList(tundstAction, - outputAction(tunPort))); updateBucket(gctx, bb); } OfOverlayContext ofc = diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java index 212130fc8..87a31eaf2 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/PolicyEnforcer.java @@ -28,6 +28,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassificationResult; @@ -98,7 +99,7 @@ public class PolicyEnforcer extends FlowTable { flowMap.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null)); - NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class); + NodeConnectorId tunPort = SwitchManager.getTunnelPort(nodeId, TunnelTypeVxlan.class); if (tunPort != null) { flowMap.writeFlow(nodeId, TABLE_ID, allowFromTunnel(tunPort)); } @@ -122,7 +123,7 @@ public class PolicyEnforcer extends FlowTable { int depgId = dstEpFwdCxtOrds.getEpgId(); int scgId = srcEpFwdCxtOrds.getCgId(); int sepgId = srcEpFwdCxtOrds.getEpgId(); - + NetworkElements netElements = new NetworkElements(srcEp, dstEp, nodeId, ctx, policyInfo); fdIds.add(srcEpFwdCxtOrds.getFdId()); List conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp); @@ -136,7 +137,7 @@ public class PolicyEnforcer extends FlowTable { if (visitedPairs.contains(p)) continue; visitedPairs.add(p); - syncPolicy(flowMap, nodeId, rgs, p); + syncPolicy(flowMap, netElements, rgs, p); // Reverse policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey); @@ -145,7 +146,7 @@ public class PolicyEnforcer extends FlowTable { if (visitedPairs.contains(p)) continue; visitedPairs.add(p); - syncPolicy(flowMap, nodeId, rgs, p); + syncPolicy(flowMap, netElements, rgs, p); } } } @@ -237,14 +238,14 @@ public class PolicyEnforcer extends FlowTable { } - private void syncPolicy(FlowMap flowMap, NodeId nodeId, List rgs, CgPair p) { + private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List rgs, CgPair p) { int priority = 65000; for (RuleGroup rg : rgs) { TenantId tenantId = rg.getContractTenant().getId(); IndexedTenant tenant = ctx.getPolicyResolver().getTenant(tenantId); for (Rule r : rg.getRules()) { - syncDirection(flowMap, nodeId, tenant, p, r, Direction.In, priority); - syncDirection(flowMap, nodeId, tenant, p, r, Direction.Out, priority); + syncDirection(flowMap, netElements, tenant, p, r, Direction.In, priority); + syncDirection(flowMap, netElements, tenant, p, r, Direction.Out, priority); priority -= 1; } @@ -271,7 +272,7 @@ public class PolicyEnforcer extends FlowTable { } - private void syncDirection(FlowMap flowMap, NodeId nodeId, IndexedTenant contractTenant, CgPair cgPair, Rule rule, + private void syncDirection(FlowMap flowMap, NetworkElements netElements, IndexedTenant contractTenant, CgPair cgPair, Rule rule, Direction direction, int priority) { /* * Create the ordered action list. The implicit action is "allow", and @@ -283,7 +284,7 @@ public class PolicyEnforcer extends FlowTable { // TODO: can pass Comparator ActionRefComparator to List constructor, rather than // referencing in sort - List abl = new ArrayList(); + List actionBuilderList = new ArrayList(); if (rule.getActionRef() != null) { /* * Pre-sort by references using order, then name @@ -291,23 +292,23 @@ public class PolicyEnforcer extends FlowTable { List arl = new ArrayList(rule.getActionRef()); Collections.sort(arl, ActionRefComparator.INSTANCE); - for (ActionRef ar : arl) { - ActionInstance ai = contractTenant.getAction(ar.getName()); - if (ai == null) { + for (ActionRef actionRule : arl) { + ActionInstance actionInstance = contractTenant.getAction(actionRule.getName()); + if (actionInstance == null) { // XXX TODO fail the match and raise an exception - LOG.warn("Action instance {} not found", ar.getName().getValue()); + LOG.warn("Action instance {} not found", actionRule.getName().getValue()); return; } - Action act = SubjectFeatures.getAction(ai.getActionDefinitionId()); - if (act == null) { + Action action = SubjectFeatures.getAction(actionInstance.getActionDefinitionId()); + if (action == null) { // XXX TODO fail the match and raise an exception - LOG.warn("Action definition {} not found", ai.getActionDefinitionId().getValue()); + LOG.warn("Action definition {} not found", actionInstance.getActionDefinitionId().getValue()); return; } Map params = new HashMap<>(); - if (ai.getParameterValue() != null) { - for (ParameterValue v : ai.getParameterValue()) { + if (actionInstance.getParameterValue() != null) { + for (ParameterValue v : actionInstance.getParameterValue()) { if (v.getName() == null) continue; if (v.getIntValue() != null) { @@ -320,11 +321,11 @@ public class PolicyEnforcer extends FlowTable { /* * Convert the GBP Action to one or more OpenFlow Actions */ - abl = act.updateAction(abl, params, ar.getOrder()); + actionBuilderList = action.updateAction(actionBuilderList, params, actionRule.getOrder(),netElements); } } else { Action act = SubjectFeatures.getAction(AllowAction.DEFINITION.getId()); - abl = act.updateAction(abl, new HashMap(), 0); + actionBuilderList = act.updateAction(actionBuilderList, new HashMap(), 0, netElements); } Map paramsFromClassifier = new HashMap<>(); @@ -420,8 +421,8 @@ public class PolicyEnforcer extends FlowTable { flow.setMatch(m) .setId(flowId) .setPriority(Integer.valueOf(priority)) - .setInstructions(instructions(applyActionIns(abl))); - flowMap.writeFlow(nodeId, TABLE_ID, flow.build()); + .setInstructions(instructions(applyActionIns(actionBuilderList))); + flowMap.writeFlow(netElements.getNodeId(), TABLE_ID, flow.build()); } } } @@ -474,4 +475,49 @@ public class PolicyEnforcer extends FlowTable { return true; } } + + public class NetworkElements { + Endpoint src; + Endpoint dst; + NodeId nodeId; + EndpointFwdCtxOrdinals srcOrds; + EndpointFwdCtxOrdinals dstOrds; + + public NetworkElements(Endpoint src, Endpoint dst, NodeId nodeId, OfContext ctx, PolicyInfo policyInfo) throws Exception { + this.src=src; + this.dst=dst; + this.nodeId = nodeId; + this.srcOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, src); + this.dstOrds=OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, policyInfo, dst); + } + + + + public EndpointFwdCtxOrdinals getSrcOrds() { + return srcOrds; + } + + + + public EndpointFwdCtxOrdinals getDstOrds() { + return dstOrds; + } + + + public Endpoint getSrc() { + return src; + } + + + public Endpoint getDst() { + return dst; + } + + + public NodeId getNodeId() { + return nodeId; + } + + + } } diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java index 9972a9d73..e5e297e3f 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapper.java @@ -190,6 +190,7 @@ public class SourceMapper extends FlowTable { MatchBuilder mb = new MatchBuilder().setInPort(tunPort); addNxTunIdMatch(mb, tunnelId); + Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId)); // set condition group register to all ones to // bypass diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/SwitchManager.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/SwitchManager.java index 3b9126526..8b4c8b597 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/SwitchManager.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/SwitchManager.java @@ -22,6 +22,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import javax.annotation.Nullable; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; @@ -428,4 +429,6 @@ public class SwitchManager implements AutoCloseable { READY } + + } diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Action.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Action.java index c7ee7727d..bb0641eeb 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Action.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/Action.java @@ -11,16 +11,20 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf; import java.util.List; import java.util.Map; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements; +import org.opendaylight.groupbasedpolicy.resolver.ActionInstanceValidator; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; /** * Represent an action definition, and provide tools for generating * flow instructions based on the action * @author tbachman */ -public abstract class Action { +public abstract class Action implements ActionInstanceValidator{ /** * Get the action definition for this action * @return the {@link ActionDefinition} for this action @@ -43,5 +47,6 @@ public abstract class Action { */ public abstract List updateAction(List actions, Map params, - Integer i); + Integer order, + NetworkElements netElements); } diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/AllowAction.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/AllowAction.java index 8a2cc7de4..4b75328bd 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/AllowAction.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/AllowAction.java @@ -13,12 +13,16 @@ import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtil import java.util.List; import java.util.Map; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7; @@ -52,7 +56,8 @@ public class AllowAction extends Action { @Override public List updateAction(List actions, Map params, - Integer order) { + Integer order, + NetworkElements netElements) { /* * Allow action doesn't use parameters * TODO: check to make sure ActionBuilder w/allow isn't already present @@ -64,4 +69,10 @@ public class AllowAction extends Action { return actions; } + @Override + public boolean isValid(ActionInstance actionInstance) { + // TODO Auto-generated method stub + return true; + } + } diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java new file mode 100644 index 000000000..44f6511b8 --- /dev/null +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/ChainAction.java @@ -0,0 +1,277 @@ +package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf; + +/* + * Copyright (c) 2014 Cisco Systems, 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNsiAction; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNspAction; +import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction; + +import java.math.BigInteger; +import java.util.List; +import java.util.Map; + +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements; +import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager; +import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI; +import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI; +import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop; +import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath; +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.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.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.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableList; +import com.google.common.net.InetAddresses; + +/** + * Chain action for the OpenFlow Overlay renderer + * TODO: separate the generic definition from the concrete + * implementation for the OpenFlow Ovelray renderer + */ +public class ChainAction extends Action { + + private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class); + + public static final ActionDefinitionId ID = new ActionDefinitionId("3d886be7-059f-4c4f-bbef-0356bea40933"); + + public static final Integer CHAIN_CONDITION_GROUP = 0xfffffe; + + protected static final String TYPE = "type"; + + // the chain action + public static final String SFC_CHAIN_ACTION = "chain"; + // the parameter used for storing the chain name + public static final String SFC_CHAIN_NAME = "sfc-chain-name"; + + protected static final ActionDefinition DEF = new ActionDefinitionBuilder().setId(ID) + .setName(new ActionName(SFC_CHAIN_ACTION)) + .setDescription(new Description("Send the traffic through a Service Function Chain")) + .setParameter( + (ImmutableList.of(new ParameterBuilder().setName(new ParameterName(SFC_CHAIN_NAME)) + .setDescription(new Description("The named chain to match against")) + .setIsRequired(IsRequired.Required) + .setType(Type.String) + .build()))) + .build(); + + @Override + public ActionDefinitionId getId() { + return ID; + } + + @Override + public ActionDefinition getActionDef() { + return DEF; + } + + @Override + public List updateAction(List actions, + Map params, + Integer order, + NetworkElements netElements) { + /* + * Get the named chain + */ + ServiceFunctionPath sfcPath = null; + String chainName = null; + if (params != null) { + LOG.debug("Searching for named chain"); + for (String name : params.keySet()) { + if (name instanceof String) { + if (name.equals(SFC_CHAIN_NAME)) { + chainName = (String) params.get(name); + if (chainName == null) { + LOG.error("ChainAction: Chain name was null"); + return null; + } + sfcPath = getSfcPath(chainName); + } + } + } + } else { + LOG.error("ChainAction: Parameters null for chain action"); + return null; + } + + if (sfcPath == null) { + LOG.error("ChainAction: SFC Path null for chain {}", chainName); + return null; + } + String rspName = sfcPath.getName() + "-gbp-rsp"; + RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName); + if (rspFirstHop == null) { + LOG.info("ChainAction: Could not find RSP {} for Chain {}", rspName, chainName); + + CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath( + sfcPath.getName()) + .setName(rspName) + .setSymmetric(Boolean.FALSE) + .build(); + RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState( + sfcPath, rspInput); + if (renderedServicePath == null) { + LOG.error("Could not find or create RSP for chain {}", chainName); + return null; + } + rspFirstHop=SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(renderedServicePath.getName()); + } + + IpAddress sfcTunIpDst = rspFirstHop.getIp(); + sfcTunIpDst.getIpv4Address(); + if (sfcTunIpDst == null || sfcTunIpDst.getIpv4Address() == null || sfcTunIpDst.getIpv6Address() != null) { + LOG.error("Invalid IP Tunnel destination for SFC RSP First Hop {}", rspName); + return null; + } + PortNumber sfcTunUdpPort = rspFirstHop.getPort(); + if (sfcTunUdpPort == null) { + LOG.error("Invalid UDP Port Number for SFC RSP {}", rspName); + return null; + } + Long sfcNsp = rspFirstHop.getPathId(); + if (sfcNsp == null) { + LOG.error("Invalid NSP for SFC RSP {}", rspName); + return null; + } + Short sfcNsi = rspFirstHop.getStartingIndex(); + if (sfcNsi == null) { + LOG.error("Invalid NSI for SFC RSP {}", rspName); + return null; + } + + NodeConnectorId tunOpenFlowPort = SwitchManager.getTunnelPort(netElements.getNodeId(), TunnelTypeVxlan.class); + + /* + * Setting NSH Network Context Headers for post-SFC encapsulation + * VXLAN header encap: + * - TunnelDestination IP: NSH C1 + * - Tunnel ID (VNID) NSH C2 + */ + long postSfcTunnelDst = 999L; + IpAddress tunnelDest; + + if (netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId().equals(netElements.getNodeId())) { + // Return destination is here + tunnelDest=SwitchManager.getTunnelIP(netElements.getNodeId(), TunnelTypeVxlan.class); + } else { + tunnelDest=SwitchManager.getTunnelIP(netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId(), TunnelTypeVxlan.class); + } + postSfcTunnelDst = (InetAddresses.coerceToInteger(InetAddresses.forString(tunnelDest.getIpv4Address().getValue()))) & 0xFFFFFFFFL; + + // TunnelDestination after Chain + actions = addActionBuilder(actions, nxLoadNshc1RegAction(postSfcTunnelDst), order++); + // VNID after Chain + actions = addActionBuilder(actions, nxLoadNshc2RegAction((long) netElements.getSrcOrds().getTunnelId()), order++); + + /* + * Set the tunnel destination IP + */ + if (sfcTunIpDst.getIpv4Address() != null) { + String nextHop = sfcTunIpDst.getIpv4Address().getValue(); + actions = addActionBuilder(actions, nxLoadTunIPv4Action(nextHop, false), order); + } else if (sfcTunIpDst.getIpv6Address() != null) { + LOG.error("IPv6 tunnel destination {} not supported", sfcTunIpDst.getIpv6Address().getValue()); + return actions; + } else { + // this shouldn't happen + LOG.error("Tunnel IP is invalid"); + return actions; + } + + /* + * Put TunID - with NSH we don't really care about this. + */ + actions = addActionBuilder(actions, + nxLoadTunIdAction(BigInteger.valueOf(netElements.getSrcOrds().getTunnelId()), false), order); + + /* + * Set the NSH header fields, based on RSP + */ + actions = addActionBuilder(actions,nxSetNsiAction(sfcNsi),order); + actions = addActionBuilder(actions,nxSetNspAction(sfcNsp),order); + /* + * Set up the actions to send to the destination port + */ + actions = addActionBuilder(actions,outputAction(tunOpenFlowPort), order); + + return actions; + } + + private List addActionBuilder(List actions, + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action, Integer order) { + ActionBuilder ab = new ActionBuilder(); + ab.setAction(action); + ab.setOrder(order); + actions.add(ab); + return actions; + } + + @Override + public boolean isValid(ActionInstance actionInstance) { + return validChain(actionInstance.getParameterValue()); + } + + private boolean validChain(List paramValue) { + ParameterValue pv = getChainNameParameter(paramValue); + if (pv == null) { + return false; + } + LOG.trace("Invoking RPC for chain {}", pv.getStringValue()); + ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue()); + return chain != null; + } + + public ServiceFunctionPath getSfcPath(String chainName) { + + ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths(); + for (ServiceFunctionPath path : paths.getServiceFunctionPath()) { + if (path.getServiceChainName().equals(chainName)) { + return path; + } + } + return null; + } + + private ParameterValue getChainNameParameter(List paramValueList) { + if (paramValueList == null) + return null; + for (ParameterValue pv : paramValueList) { + if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) { + return pv; + } + } + return null; + } + +} diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java index 64822f1ca..025d9887d 100644 --- a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sf/SubjectFeatures.java @@ -1,3 +1,4 @@ +package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf; /* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * @@ -6,7 +7,7 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf; + import java.util.List; import java.util.Map; @@ -45,7 +46,8 @@ public class SubjectFeatures { private static final Map actions = ImmutableMap. - of(AllowAction.ID, new AllowAction()); + of(AllowAction.ID, new AllowAction(), + ChainAction.ID, new ChainAction()); private static final List actionDefs = ImmutableList.copyOf(Collections2.transform(actions.values(), @@ -74,6 +76,10 @@ public class SubjectFeatures { return classifiers.get(id); } + public static Map getActions() { + return actions; + } + /** * Get the {@link Action} associated with the given * {@link ActionDefinitionId} diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java new file mode 100644 index 000000000..4b6b2df1b --- /dev/null +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcDataStoreHelper.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014 Cisco Systems, 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils; + +import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; + +/** + * @author Martin Sunal + */ +public class SfcDataStoreHelper { + + private static final Logger LOG = LoggerFactory.getLogger(SfcDataStoreHelper.class); + + /** + * Reads data from datastore as synchrone call. + * @return {@link Optional#isPresent()} is {@code true} if reading was successful and data exists in datastore; {@link Optional#isPresent()} is {@code false} otherwise + */ + public static U readFromDs(LogicalDatastoreType store,InstanceIdentifier iid, ReadTransaction rTx) { + U ret = null; + Optional optionalDataObject; + CheckedFuture, ReadFailedException> submitFuture = rTx.read(store, iid); + try { + optionalDataObject = submitFuture.checkedGet(); + if (optionalDataObject != null && optionalDataObject.isPresent()) { + ret = optionalDataObject.get(); + } else { + LOG.debug("{}: Failed to read", Thread.currentThread().getStackTrace()[1]); + } + } catch (ReadFailedException e) { + LOG.warn("failed to ....", e); + } + return ret; + } + + /** + * Calls {@link WriteTransaction#submit()} on write transaction. + * @param wTx write transaction + * @return {@code true} if transaction commit was successful; {@code false} otherwise + */ + public static boolean submitToDs(WriteTransaction wTx) { + CheckedFuture submitFuture = wTx.submit(); + try { + submitFuture.checkedGet(); + return true; + } catch (TransactionCommitFailedException e) { + LOG.warn("Transaction commit failed to DS.", e); + return false; + } + } + +} diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java new file mode 100644 index 000000000..3d9bffeea --- /dev/null +++ b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/sfcutils/SfcIidFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014 Cisco Systems, 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, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils; + +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.ServiceFunctionChainKey; +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.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SfcIidFactory { + + private SfcIidFactory() { + throw new UnsupportedOperationException(); + } + + public static InstanceIdentifier sfcIid(String sfcName) { + + ServiceFunctionChainKey serviceFunctionChainKey = + new ServiceFunctionChainKey(sfcName); + return InstanceIdentifier.builder(ServiceFunctionChains.class) + .child(ServiceFunctionChain.class, serviceFunctionChainKey).build(); + } + + public static InstanceIdentifier sfpIid(String sfpName) { + + ServiceFunctionPathKey serviceFunctionPathKey = new ServiceFunctionPathKey(sfpName); + return InstanceIdentifier.builder(ServiceFunctionPaths.class) + .child(ServiceFunctionPath.class, serviceFunctionPathKey).build(); + + } +} diff --git a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java index bf74b6b12..9b352c17c 100755 --- a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java +++ b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/SourceMapperTest.java @@ -49,6 +49,9 @@ public class SourceMapperTest extends FlowTableTest { protected static final Logger LOG = LoggerFactory.getLogger(SourceMapperTest.class); + NodeConnectorId remoteTunnelId = + new NodeConnectorId(remoteNodeId.getValue() + ":101"); + @Override @Before public void setup() throws Exception { @@ -57,6 +60,27 @@ public class SourceMapperTest extends FlowTableTest { super.setup(); } + private void addSwitches() { + switchManager.addSwitch( + nodeId, + tunnelId, + Collections.emptySet(), + new OfOverlayNodeConfigBuilder().setTunnel( + ImmutableList.of(new TunnelBuilder().setIp(new IpAddress(new Ipv4Address("1.2.3.4"))) + .setTunnelType(TunnelTypeVxlan.class) + .setNodeConnectorId(tunnelId) + .build())).build()); + switchManager.addSwitch( + remoteNodeId, + remoteTunnelId, + Collections.emptySet(), + new OfOverlayNodeConfigBuilder().setTunnel( + ImmutableList.of(new TunnelBuilder().setIp(new IpAddress(new Ipv4Address("1.2.3.5"))) + .setTunnelType(TunnelTypeVxlan.class) + .setNodeConnectorId(tunnelId) + .build())).build()); + } + @Test public void testNoPolicy() throws Exception { endpointManager.addEndpoint(localEP().build()); @@ -76,17 +100,20 @@ public class SourceMapperTest extends FlowTableTest { .setNodeConnectorId(tunnelId) .build())).build()); Endpoint ep = localEP().build(); + switchManager.addSwitch(nodeId, null, + Collections. emptySet(), + null); endpointManager.addEndpoint(ep); policyResolver.addTenant(baseTenant().build()); FlowMap fm = dosync(null); - assertEquals(4, fm.getTableForNode(nodeId, (short) 1).getFlow().size()); + assertEquals(2, fm.getTableForNode(nodeId, (short) 1).getFlow().size()); int count = 0; HashMap flowMap = new HashMap<>(); for (Flow f : fm.getTableForNode(nodeId, (short) 1).getFlow()) { flowMap.put(f.getId().getValue(), f); - if (f.getMatch() == null) { + if (f.getMatch() == null || f.getMatch().getEthernetMatch() == null) { assertEquals(FlowUtils.dropInstructions(), f.getInstructions()); count += 1; } else if ((f.getMatch() !=null && f.getMatch().getEthernetMatch() != null) diff --git a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/MockSwitchManager.java b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/MockSwitchManager.java index 6dbc6458c..a1c9810fe 100644 --- a/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/MockSwitchManager.java +++ b/renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/node/MockSwitchManager.java @@ -32,6 +32,7 @@ public class MockSwitchManager extends SwitchManager { SwitchState state = new SwitchState(node, tunnelPort, externalPorts, nodeConfig); state.status = SwitchStatus.READY; + state.setHasEndpoints(true); switches.put(node, state); for (SwitchListener listener : listeners) { listener.switchReady(node); -- 2.36.6