<generated.yang.docs>${project.build.directory}/site/models</generated.yang.docs>
<config.version>0.3.0-SNAPSHOT</config.version>
<mdsal.version>1.2.0-SNAPSHOT</mdsal.version>
+ <sfc.version>0.1.0-SNAPSHOT</sfc.version>
<restconf.version>1.2.0-SNAPSHOT</restconf.version>
<yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
<openflowplugin.version>0.1.0-SNAPSHOT</openflowplugin.version>
<properties>
<groupbasedpolicy.project.version>0.2.0-SNAPSHOT</groupbasedpolicy.project.version>
+ <sfc.version>0.1.0-SNAPSHOT</sfc.version>
</properties>
<dependencies>
<type>xml</type>
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-sb-rest</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-ovs</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfcofl2</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-netconf</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
</dependencies>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/groupbasedpolicy.git</connection>
<classifier>features</classifier>
<type>xml</type>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-sb-rest</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-ovs</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfcofl2</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>features-sfc-netconf</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.openflowplugin</groupId>
<artifactId>features-openflowplugin</artifactId>
<repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/${openflowplugin.version}/xml/features</repository>
<repository>mvn:org.opendaylight.ovsdb/southbound-features/${ovsdb.southbound.version}/xml/features</repository>
+
<!-- Repos needed by the Neutron Mapper -->
<repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
-
+ <!-- Repos needed by ofoverlay for SFC -->
+ <repository>mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc-sb-rest/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc-netconf/${sfc.version}/xml/features</repository>
<!-- Repos needed by the UI Backend -->
<repository>mvn:org.opendaylight.controller/features-restconf/${restconf.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfcofl2/${sfc.version}/xml/features</repository>
<!-- The common GBP components -->
<feature name='odl-groupbasedpolicy-base' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: Base Copmonents'>
<feature version="${mdsal.version}">odl-mdsal-broker</feature>
<feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
<feature version='${openflowplugin.version}'>odl-openflowplugin-nxm-extensions</feature>
<feature version='${ovsdb.southbound.version}'>odl-ovsdb-southbound-impl</feature>
+ <feature version='${sfc.version}'>odl-sfc-core</feature>
+ <feature version='${sfc.version}'>odl-sfc-test-consumer</feature>
+ <feature version='${sfc.version}'>odl-sfc-sb-rest</feature>
+ <feature version='${sfc.version}'>odl-sfcofl2</feature>
+ <feature version='${sfc.version}'>odl-sfc-ovs</feature>
+ <feature version='${sfc.version}'>odl-sfc-netconf</feature>
+ <feature version='${sfc.version}'>odl-sfc-ui</feature>
<bundle>mvn:org.opendaylight.groupbasedpolicy/ofoverlay-renderer/${project.version}</bundle>
<configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.ofoverlayconfigfile}">mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-ofoverlay-config/${project.version}/xml/config</configfile>
</feature>
--- /dev/null
+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);
+}
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;
protected ConcurrentMap<TenantId, TenantContext> 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
*/
AtomicReference<PolicyInfo> policy = new AtomicReference<>();
+ /*
+ * Store validators for ActionDefinitions from Renderers
+ *
+ */
+
+ protected ConcurrentMap<ActionDefinitionId, ActionInstanceValidator> registeredActions = new ConcurrentHashMap<>();
+
public PolicyResolver(DataBroker dataProvider,
ScheduledExecutorService executor) {
super();
return tc.tenant.get();
}
+ public void registerActionDefinitions(ActionDefinitionId actionDefinitionId, ActionInstanceValidator validator) {
+ registeredActions.putIfAbsent(actionDefinitionId, validator);
+ }
/**
* Register a listener to receive update events.
*
}
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);
}
}
+
+ private boolean isValidTenant(Tenant t) {
+ if(validActionInstances(t.getSubjectFeatureInstances().getActionInstance())) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean validActionInstances(List<ActionInstance> actionInstances) {
+ for(ActionInstance actionInstance : actionInstances) {
+ if(!(registeredActions.get(actionInstance.getActionDefinitionId()).isValid(actionInstance))) {
+ return false;
+ };
+ }
+ return true;
+ }
+
+ private boolean validContracts(List<Contract> contracts) {
+ for (Contract contract: contracts) {
+ validateSubjects(contract.getSubject());
+ }
+ return false;
+ }
+
+ private void validateSubjects(List<Subject> subjects) {
+ for(Subject subject: subjects) {
+ validateRules(subject.getRule());
+ }
+
+ }
+
+ private void validateRules(List<Rule> rules) {
+
+ }
+
+ private void validateActionRefs(List<ActionRef> actionRefs) {
+
+ }
}
<groupId>org.opendaylight.openflowplugin</groupId>
<artifactId>openflowplugin-extension-nicira</artifactId>
</dependency>
-
+ <!-- SFC -->
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-model</artifactId>
+ <version>${sfc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-provider</artifactId>
+ <version>${sfc.version}</version>
+ </dependency>
<!-- testing dependencies -->
<dependency>
<groupId>junit</groupId>
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;
/**
* 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;
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;
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;
t.submit();
}
+ for(Entry<ActionDefinitionId, Action> entry : SubjectFeatures.getActions().entrySet()) {
+ policyResolver.registerActionDefinitions(entry.getKey(), entry.getValue());
+ }
+
OfContext ctx = new OfContext(dataBroker, rpcRegistry,
this, policyResolver, switchManager,
endpointManager, executor);
--- /dev/null
+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<ActionInstance> allActionInstancesIid;
+ private final ListenerRegistration<DataChangeListener> actionListener;
+
+ /*
+ * local cache of the RSP first hops that we've requested from SFC,
+ * keyed by RSP name
+ */
+ private final ConcurrentMap<String, RenderedServicePathFirstHop> 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<String, RenderedServicePathFirstHop>();
+
+ /*
+ * 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<IpAddress> getSfcSourceIps() {
+ if (rspMap.isEmpty()) return null;
+
+ Set<IpAddress> ipAddresses = new HashSet<IpAddress>();
+ 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<InstanceIdentifier<?>, 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<InstanceIdentifier<?>, 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<Optional<ActionDefinition>> {
+ private final ActionState state;
+ private final ActionInstance actionInstance;
+ private final ActionInstance originalInstance;
+ private final InstanceIdentifier<ActionDefinition> 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<Optional<ActionDefinition>> 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<ActionDefinition> 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<ParameterValue> 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<RpcResult<ReadRenderedServicePathFirstHopOutput>> result =
+ SfcProviderRpc.getSfcProviderRpc()
+ .readRenderedServicePathFirstHop(builder.build());
+
+ try {
+ RpcResult<ReadRenderedServicePathFirstHopOutput> 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();
+
+ }
+}
+
.setInstructions(
instructions(applyActionIns(nxLoadTunIdAction(BigInteger.valueOf(epOrd.getFdId()), false),
groupAction(Long.valueOf(epOrd.getFdId())))));
+
return flowb.build();
}
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;
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;
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;
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;
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;
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;
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<? extends NxmNxReg> src, boolean groupBucket) {
return nxMoveRegAction(new SrcNxRegCaseBuilder().setNxReg(src).build(),
new DstNxTunIdCaseBuilder().setNxTunId(Boolean.TRUE).build(), 31, groupBucket);
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<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+ ArrayList<ExtensionList> 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<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+ ArrayList<ExtensionList> 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<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+ ArrayList<ExtensionList> 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<ExtensionList> existingExtensions = match.getAugmentation(GeneralAugMatchNodesNodeTableFlow.class).getExtensionList();
+ ArrayList<ExtensionList> 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<ExtensionList> extensions = new ArrayList<>();
+ for (RegMatch rm : matches) {
+ Class<? extends ExtensionKey> 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();
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 =
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;
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));
}
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<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(srcEp);
if (visitedPairs.contains(p))
continue;
visitedPairs.add(p);
- syncPolicy(flowMap, nodeId, rgs, p);
+ syncPolicy(flowMap, netElements, rgs, p);
// Reverse
policy = policyInfo.getPolicy(srcEpgKey, dstEpgKey);
if (visitedPairs.contains(p))
continue;
visitedPairs.add(p);
- syncPolicy(flowMap, nodeId, rgs, p);
+ syncPolicy(flowMap, netElements, rgs, p);
}
}
}
}
- private void syncPolicy(FlowMap flowMap, NodeId nodeId, List<RuleGroup> rgs, CgPair p) {
+ private void syncPolicy(FlowMap flowMap, NetworkElements netElements, List<RuleGroup> 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;
}
}
- 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
// TODO: can pass Comparator ActionRefComparator to List constructor, rather than
// referencing in sort
- List<ActionBuilder> abl = new ArrayList<ActionBuilder>();
+ List<ActionBuilder> actionBuilderList = new ArrayList<ActionBuilder>();
if (rule.getActionRef() != null) {
/*
* Pre-sort by references using order, then name
List<ActionRef> arl = new ArrayList<ActionRef>(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<String, Object> 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) {
/*
* 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<String, Object>(), 0);
+ actionBuilderList = act.updateAction(actionBuilderList, new HashMap<String, Object>(), 0, netElements);
}
Map<String, ParameterValue> paramsFromClassifier = new HashMap<>();
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());
}
}
}
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;
+ }
+
+
+ }
}
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
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;
READY
}
+
+
}
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
*/
public abstract List<ActionBuilder> updateAction(List<ActionBuilder> actions,
Map<String, Object> params,
- Integer i);
+ Integer order,
+ NetworkElements netElements);
}
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;
@Override
public List<ActionBuilder> updateAction(List<ActionBuilder> actions,
Map<String, Object> 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
return actions;
}
+ @Override
+ public boolean isValid(ActionInstance actionInstance) {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
}
--- /dev/null
+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<ActionBuilder> updateAction(List<ActionBuilder> actions,
+ Map<String, Object> 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<ActionBuilder> addActionBuilder(List<ActionBuilder> 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<ParameterValue> 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<ParameterValue> paramValueList) {
+ if (paramValueList == null)
+ return null;
+ for (ParameterValue pv : paramValueList) {
+ if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {
+ return pv;
+ }
+ }
+ return null;
+ }
+
+}
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
/*
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* 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;
private static final Map<ActionDefinitionId, Action> actions =
ImmutableMap.<ActionDefinitionId, Action>
- of(AllowAction.ID, new AllowAction());
+ of(AllowAction.ID, new AllowAction(),
+ ChainAction.ID, new ChainAction());
private static final List<ActionDefinition> actionDefs =
ImmutableList.copyOf(Collections2.transform(actions.values(),
return classifiers.get(id);
}
+ public static Map<ActionDefinitionId, Action> getActions() {
+ return actions;
+ }
+
/**
* Get the {@link Action} associated with the given
* {@link ActionDefinitionId}
--- /dev/null
+/*
+ * 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 extends DataObject> U readFromDs(LogicalDatastoreType store,InstanceIdentifier<U> iid, ReadTransaction rTx) {
+ U ret = null;
+ Optional<U> optionalDataObject;
+ CheckedFuture<Optional<U>, 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<Void, TransactionCommitFailedException> submitFuture = wTx.submit();
+ try {
+ submitFuture.checkedGet();
+ return true;
+ } catch (TransactionCommitFailedException e) {
+ LOG.warn("Transaction commit failed to DS.", e);
+ return false;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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<ServiceFunctionChain> sfcIid(String sfcName) {
+
+ ServiceFunctionChainKey serviceFunctionChainKey =
+ new ServiceFunctionChainKey(sfcName);
+ return InstanceIdentifier.builder(ServiceFunctionChains.class)
+ .child(ServiceFunctionChain.class, serviceFunctionChainKey).build();
+ }
+
+ public static InstanceIdentifier<ServiceFunctionPath> sfpIid(String sfpName) {
+
+ ServiceFunctionPathKey serviceFunctionPathKey = new ServiceFunctionPathKey(sfpName);
+ return InstanceIdentifier.builder(ServiceFunctionPaths.class)
+ .child(ServiceFunctionPath.class, serviceFunctionPathKey).build();
+
+ }
+}
\r
protected static final Logger LOG = LoggerFactory.getLogger(SourceMapperTest.class);\r
\r
+ NodeConnectorId remoteTunnelId =\r
+ new NodeConnectorId(remoteNodeId.getValue() + ":101");\r
+\r
@Override\r
@Before\r
public void setup() throws Exception {\r
super.setup();\r
}\r
\r
+ private void addSwitches() {\r
+ switchManager.addSwitch(\r
+ nodeId,\r
+ tunnelId,\r
+ Collections.<NodeConnectorId>emptySet(),\r
+ new OfOverlayNodeConfigBuilder().setTunnel(\r
+ ImmutableList.of(new TunnelBuilder().setIp(new IpAddress(new Ipv4Address("1.2.3.4")))\r
+ .setTunnelType(TunnelTypeVxlan.class)\r
+ .setNodeConnectorId(tunnelId)\r
+ .build())).build());\r
+ switchManager.addSwitch(\r
+ remoteNodeId,\r
+ remoteTunnelId,\r
+ Collections.<NodeConnectorId>emptySet(),\r
+ new OfOverlayNodeConfigBuilder().setTunnel(\r
+ ImmutableList.of(new TunnelBuilder().setIp(new IpAddress(new Ipv4Address("1.2.3.5")))\r
+ .setTunnelType(TunnelTypeVxlan.class)\r
+ .setNodeConnectorId(tunnelId)\r
+ .build())).build());\r
+ }\r
+\r
@Test\r
public void testNoPolicy() throws Exception {\r
endpointManager.addEndpoint(localEP().build());\r
.setNodeConnectorId(tunnelId)\r
.build())).build());\r
Endpoint ep = localEP().build();\r
+ switchManager.addSwitch(nodeId, null,\r
+ Collections.<NodeConnectorId> emptySet(),\r
+ null);\r
endpointManager.addEndpoint(ep);\r
policyResolver.addTenant(baseTenant().build());\r
\r
FlowMap fm = dosync(null);\r
- assertEquals(4, fm.getTableForNode(nodeId, (short) 1).getFlow().size());\r
+ assertEquals(2, fm.getTableForNode(nodeId, (short) 1).getFlow().size());\r
\r
int count = 0;\r
HashMap<String, Flow> flowMap = new HashMap<>();\r
for (Flow f : fm.getTableForNode(nodeId, (short) 1).getFlow()) {\r
flowMap.put(f.getId().getValue(), f);\r
- if (f.getMatch() == null) {\r
+ if (f.getMatch() == null || f.getMatch().getEthernetMatch() == null) {\r
assertEquals(FlowUtils.dropInstructions(), f.getInstructions());\r
count += 1;\r
} else if ((f.getMatch() !=null && f.getMatch().getEthernetMatch() != null)\r
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);