<instructions>
<Embed-Dependency>utils.config,utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
+ <Export-Package>
+ org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.*
+ </Export-Package>
</instructions>
</configuration>
</plugin>
<artifactId>yang-ext</artifactId>
</dependency>
</dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.yang.gen.v1.*;
+ </Export-Package>
+ <!--<Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>-->
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
<maven>3.1.1</maven>
</prerequisites>
<properties>
+ <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+ <dlux.version>0.3.0-SNAPSHOT</dlux.version>
<mdsal.model.version>0.8.0-SNAPSHOT</mdsal.model.version>
<mdsal.version>1.3.0-SNAPSHOT</mdsal.version>
+ <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
<restconf.version>1.3.0-SNAPSHOT</restconf.version>
+ <sfc.version>0.2.0-SNAPSHOT</sfc.version>
<yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
- <dlux.version>0.3.0-SNAPSHOT</dlux.version>
- <configfile.directory>etc/opendaylight/karaf</configfile.directory>
</properties>
<dependencyManagement>
<dependencies>
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>ovsdb-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<type>xml</type>
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>features-ovsdb</artifactId>
+ <classifier>features</classifier>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>features-openflowplugin</artifactId>
+ <version>${openflowplugin.version}</version>
+ <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-ovs</artifactId>
+ <version>${sfc.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>openstack.net-virt-sfc-impl</artifactId>
<artifactId>utils.mdsal-utils</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>utils.servicehelper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
<features name="odl-ovsdb-sfc-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
- <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
<repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
<repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/${mdsal.model.version}/xml/features</repository>
<repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
- <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
- <repository>mvn:org.opendaylight.ovsdb/southbound-features/1.2.1-SNAPSHOT/xml/features</repository>
+ <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${project.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.ovsdb/southbound-features/${project.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.sfc/features-sfc-ovs/${sfc.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
<feature name='odl-ovsdb-sfc-api' version='${project.version}' description='OpenDaylight :: ovsdb-sfc :: api'>
<feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
<bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-api/${project.version}</bundle>
</feature>
<feature name='odl-ovsdb-sfc' version='${project.version}' description='OpenDaylight :: ovsdb-sfc'>
<feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+ <feature version="${openflowplugin.version}">odl-openflowplugin-nsf-model</feature>
<feature version='${project.version}'>odl-ovsdb-southbound-impl</feature>
- <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
+ <feature version='${project.version}'>odl-ovsdb-openstack</feature>
+ <feature version='${sfc.version}'>odl-sfc-core</feature>
+ <feature version='${sfc.version}'>odl-sfc-ovs</feature>
+ <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
<feature version='${project.version}'>odl-ovsdb-sfc-api</feature>
+ <bundle>mvn:org.opendaylight.ovsdb/utils.mdsal-utils/${project.version}</bundle>
+ <bundle>mvn:org.opendaylight.ovsdb/utils.servicehelper/${project.version}</bundle>
<bundle>mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}</bundle>
<configfile finalname="${configfile.directory}/openstack.net-virt-sfc.xml">mvn:org.opendaylight.ovsdb/openstack.net-virt-sfc-impl/${project.version}/xml/config</configfile>
</feature>
<packaging>bundle</packaging>
<properties>
+ <networkconfig.neutron.version>0.6.0-SNAPSHOT</networkconfig.neutron.version>
+ <openflowplugin.version>0.2.0-SNAPSHOT</openflowplugin.version>
<sonar.jacoco.itReportPath>../it/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+ <sfc.project.version>0.2.0-SNAPSHOT</sfc.project.version>
</properties>
<dependencies>
<artifactId>openstack.net-virt-sfc-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openstack.net-virt</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openstack.net-virt-providers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>utils.mdsal-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>utils.mdsal-openflow</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>utils.servicehelper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<artifactId>sal-common-api</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.ovsdb</groupId>
- <artifactId>utils.mdsal-utils</artifactId>
- <version>${project.version}</version>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-base</artifactId>
+ <version>${openflowplugin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ <version>${openflowplugin.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-topology</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-model</artifactId>
+ <version>${sfc.project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-ovs</artifactId>
+ <version>${sfc.project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sfc</groupId>
+ <artifactId>sfc-provider</artifactId>
+ <version>${sfc.project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Embed-Dependency>utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
+ <Embed-Transitive>true</Embed-Transitive>
+ </instructions>
+ </configuration>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<required-capabilities>
<capability>urn:opendaylight:params:xml:ns:yang:netvirt:sfc?module=netvirt-sfc&revision=2014-12-10</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:southbound:impl?module=southbound-impl&revision=2014-12-10</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:netvirt:impl?module=netvirt-impl&revision=2015-05-13</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:netvirt:providers:impl?module=netvirt-providers-impl&revision=2015-05-13</capability>
</required-capabilities>
<configuration>
package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
+import java.util.Iterator;
+import java.util.List;
+
import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
+import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
+import org.opendaylight.sfc.sfc_ovs.provider.SfcOvsUtil;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.AccessList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.AccessListEntry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.Actions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.actions.packet.handling.Deny;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.actions.packet.handling.Permit;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.matches.ace.type.AceEth;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.matches.ace.type.AceIp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev141010.access.lists.access.list.access.list.entries.access.list.entry.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+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.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
* @author Arun Yerra
*/
public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
+ private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcOF13Provider.class);
+ private static final int DEFAULT_FLOW_PRIORITY = 32768;
+ private volatile NodeCacheManager nodeCacheManager;
+ private volatile Southbound southbound;
+ private MdsalUtils dbutils;
+ private PipelineOrchestrator orchestrator;
- private final DataBroker dataService;
-
+ /**
+ * {@link NetvirtSfcOF13Provider} constructor.
+ * @param dataBroker MdSal {@link DataBroker}
+ */
public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
- this.dataService = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
+ Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
+
+ //this.dataService = dataBroker;
+ dbutils = new MdsalUtils(dataBroker);
+
+ this.setDependencies(null);
}
@Override
public void addClassifierRules(Sff sff, AccessList acl) {
- // TODO Auto-generated method stub
+ Preconditions.checkNotNull(sff, "Input service function forwarder cannot be NULL!");
+ Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
+
+ // Validate if any service function forwarder exists by the name, using SFC provider APIs.
+ ServiceFunctionForwarder serviceForwarder =
+ SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sff.getName());
+ if (serviceForwarder == null) {
+ LOG.debug("Service Function Forwarder = {} not yet configured. Skip processing !!", sff.getName());
+ return;
+ }
+
+ // If a service function forwarder exists, then get the corresponding OVS Bridge details and Openflow NodeId.
+ // If OVS Bridge augmentation is configured, the following API returns NULL.
+ String datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder);
+ if (datapathId == null) {
+ LOG.debug("Service Function Forwarder = {} is not augemented with "
+ + "OVS Bridge Information. Skip processing!!", sff.getName());
+ }
+ // If openflow Node Id is NULL, get all the bridge nodes using southbound apis and fetch
+ // SFF with matching name. From this bridge name, get the openflow data path ID.
+ if (datapathId == null) {
+ Node node = null;
+ final List<Node> nodes = nodeCacheManager.getBridgeNodes();
+ if (nodes.isEmpty()) {
+ LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", sff.getName());
+ } else {
+ for (Node dstNode : nodes) {
+ LOG.debug("Processing Node={}, sff={}", dstNode.getNodeId().getValue(), sff.getName());
+ if (dstNode.getNodeId().getValue().equalsIgnoreCase(sff.getName())) {
+ LOG.debug("Found matching OVSDB Bridge Name!!= {}", dstNode.getNodeId().getValue());
+ node = dstNode;
+ break;
+ }
+ }
+ }
+ }
+
+ LOG.debug("Processing the Classifier rules on Node={}", datapathId);
+ if (datapathId != null) {
+ // Program the OF flow on the corresponding open flow node.
+ Iterator<AccessListEntry> itr = acl.getAccessListEntries().getAccessListEntry().iterator();
+ while (itr.hasNext()) {
+ AccessListEntry entry = itr.next();
+ programOFRules(entry, datapathId, true);
+ }
+ }
+ }
+
+ private void programOFRules(AccessListEntry entry, String datapathId, boolean write) {
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + datapathId));
+ nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
+
+ //Create the match using match builder, by parsing the Accesslist Entry Match.
+ MatchBuilder matchBuilder = null;
+ matchBuilder = buildMatch(entry.getRuleName(), entry.getMatches(), datapathId);
+
+ InstructionsBuilder isb = null;
+ isb = buildActions(entry.getRuleName(), entry.getActions(), datapathId);
+
+ String flowId = "NETVIRT_SFC_FLOW" + "_" + entry.getRuleName();
+
+ FlowBuilder flowBuilder = new FlowBuilder();
+ flowBuilder.setId(new FlowId(flowId));
+ FlowKey key = new FlowKey(new FlowId(flowId));
+ flowBuilder.setMatch(matchBuilder.build());
+ flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
+ flowBuilder.setBarrier(true);
+ flowBuilder.setTableId(this.getTable());
+ flowBuilder.setKey(key);
+ flowBuilder.setFlowName(flowId);
+ flowBuilder.setHardTimeout(0);
+ flowBuilder.setIdleTimeout(0);
+
+ flowBuilder.setInstructions(isb.build());
+
+ if (write) {
+ writeFlow(flowBuilder, nodeBuilder);
+ } else {
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+ }
+
+ private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
+ InstructionBuilder ib = new InstructionBuilder();
+
+ if (actions.getPacketHandling() instanceof Deny) {
+ InstructionUtils.createDropInstructions(ib);
+ } else if (actions.getPacketHandling() instanceof Permit) {
+ //Permit actPermit = (Permit) actions.getPacketHandling();
+ } else {
+ InstructionUtils.createDropInstructions(ib);
+ }
+
+ ib.setOrder(0);
+ ib.setKey(new InstructionKey(0));
+ // Instructions List Stores Individual Instructions
+ List<Instruction> instructions = Lists.newArrayList();
+ instructions.add(ib.build());
+
+ // Call the InstructionBuilder Methods Containing Actions
+ ib = this.getMutablePipelineInstructionBuilder();
+ ib.setOrder(1);
+ ib.setKey(new InstructionKey(1));
+ instructions.add(ib.build());
+ // Add InstructionBuilder to the Instruction(s)Builder List
+ InstructionsBuilder isb = new InstructionsBuilder();
+ isb.setInstruction(instructions);
+ return isb;
+ }
+
+ private MatchBuilder buildMatch(String ruleName, Matches matches, String dpId) {
+ MatchBuilder matchBuilder = new MatchBuilder();
+
+ if (matches.getAceType() instanceof AceIp) {
+ AceIp aceIp = (AceIp)matches.getAceType();
+ if (aceIp.getAceIpVersion() instanceof AceIpv4) {
+ AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
+ MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Address());
+ MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Address());
+ MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getIpProtocol());
+ MatchUtils.addLayer4Match(matchBuilder, aceIp.getIpProtocol().intValue(),
+ aceIp.getSourcePortRange().getLowerPort().getValue().intValue(),
+ aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
+ }
+ } else if (matches.getAceType() instanceof AceEth) {
+ AceEth aceEth = (AceEth) matches.getAceType();
+ MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
+ MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
+ new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
+ }
+
+ //MatchUtils.createInPortMatch(matchBuilder, Long.getLong(dpId), Long.getLong(matches.getInputInterface()));
+ return matchBuilder;
}
@Override
// TODO Auto-generated method stub
}
+
+
+ protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+ LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
+ flowBuilder.build(), nodeBuilder.build());
+ dbutils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build());
+ dbutils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build());
+ }
+
+ protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+ dbutils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
+ }
+
+ private String getDpid(Node node) {
+ long dpid = southbound.getDataPathId(node);
+ if (dpid == 0) {
+ LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
+ }
+ return String.valueOf(dpid);
+ }
+
+ private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+ nodeBuilder.getKey())
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(flowBuilder.getTableId()))
+ .child(Flow.class, flowBuilder.getKey()).build();
+ }
+
+ private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
+ createNodePath(NodeBuilder nodeBuilder) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+ nodeBuilder.getKey()).build();
+ }
+
+ private short getTable() {
+ return Service.INGRESS_ACL.getTable();
+ }
+
+ private final InstructionBuilder getMutablePipelineInstructionBuilder() {
+ Service nextService = orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL);
+ if (nextService != null) {
+ return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
+ } else {
+ return InstructionUtils.createDropInstructions(new InstructionBuilder());
+ }
+ }
+
+ private void setDependencies(ServiceReference serviceReference) {
+ nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
+ southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
+ orchestrator = (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
+ }
}
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.NetvirtSfcProvider;
+import org.osgi.framework.BundleContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import javax.management.ObjectName;
// create instance of module with injected mocks
NetvirtSfcModule module = new NetvirtSfcModule(mock(ModuleIdentifier.class), dependencyResolver);
- //module.setDataBroker(mock(ObjectName.class));
// getInstance calls resolveInstance to get the broker dependency and then calls createInstance
AutoCloseable closeable = module.getInstance();
((NetvirtSfcProvider)closeable).onSessionInitiated(session);
package org.opendaylight.ovsdb.openstack.netvirt.sfc;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.AclUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ClassifierUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.concepts.Builder;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption;
import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
import org.ops4j.pax.exam.options.MavenUrlReference;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
public static final String CONNECTION_TYPE_ACTIVE = "active";
public static final String CONNECTION_TYPE_PASSIVE = "passive";
public static final String DEFAULT_SERVER_PORT = "6640";
- public static final String BRIDGE_NAME = "brtest";
+ public static final String INTEGRATION_BRIDGE_NAME = "br-int";
+ private static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
@Override
public String getModuleName() {
@Override
public Option getLoggingOption() {
- Option option = editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
- logConfiguration(NetvirtSfcIT.class),
- LogLevel.INFO.name());
- option = composite(option, super.getLoggingOption());
- return option;
+ return composite(
+ editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ logConfiguration(NetvirtSfcIT.class),
+ LogLevel.INFO.name()),
+ editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ "log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.sfc",
+ LogLevel.INFO.name()),
+ /*editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ "log4j.logger.org.opendaylight.ovsdb",
+ LogLevelOption.LogLevel.TRACE.name()),*/
+ super.getLoggingOption());
}
protected String usage() {
e.printStackTrace();
}
+ getProperties();
+
DataBroker dataBroker = getDatabroker(getProviderContext());
mdsalUtils = new MdsalUtils(dataBroker);
assertNotNull("mdsalUtils should not be null", mdsalUtils);
southboundUtils = new SouthboundUtils(mdsalUtils);
- getProperties();
+ assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
setup.set(true);
}
return dataBroker;
}
+ private Boolean getNetvirtTopology() {
+ LOG.info("getNetvirtTopology: looking for {}...", NETVIRT_TOPOLOGY_ID);
+ Boolean found = false;
+ final TopologyId topologyId = new TopologyId(new Uri(NETVIRT_TOPOLOGY_ID));
+ InstanceIdentifier<Topology> path =
+ InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+ for (int i = 0; i < 60; i++) {
+ Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+ if (topology != null) {
+ LOG.info("getNetvirtTopology: found {}...", NETVIRT_TOPOLOGY_ID);
+ found = true;
+ break;
+ } else {
+ LOG.info("getNetvirtTopology: still looking ({})...", i);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return found;
+ }
+
@Test
public void testNetvirtSfcFeatureLoad() {
assertTrue(true);
assertNull(clazz.getSimpleName() + " should be null", result);
}
+ /*
+ * Connect to an ovsdb node. Netvirt should add br-int, add the controller address
+ * and program the pipeline flows.
+ */
@Test
public void testDoIt() throws InterruptedException {
ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
- Node ovsdbNode = southboundUtils.connectOvsdbNode(connectionInfo);
-
- String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
- assertNotNull("Failed to get controller target", controllerTarget);
- List<ControllerEntry> setControllerEntry = southboundUtils.createControllerEntry(controllerTarget);
- Uri setUri = new Uri(controllerTarget);
- Assert.assertTrue(southboundUtils.addBridge(connectionInfo, null, BRIDGE_NAME, null, true,
- SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
- setControllerEntry, null));
- OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, BRIDGE_NAME);
- Assert.assertNotNull("bridge was not found: " + BRIDGE_NAME, bridge);
- Assert.assertNotNull("ControllerEntry was not found: " + setControllerEntry.iterator().next(),
- bridge.getControllerEntry());
- List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
- for (ControllerEntry entry : getControllerEntries) {
- if (entry.getTarget() != null) {
- Assert.assertEquals(setUri.toString(), entry.getTarget().toString());
+ assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+ assertNotNull("node is not connected", southboundUtils.getOvsdbNode(connectionInfo));
+ ControllerEntry controllerEntry;
+ // Loop 10s checking if the controller was added
+ for (int i = 0; i < 10; i++) {
+ Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
+ assertNotNull("ovsdb node not found", ovsdbNode);
+ String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
+ assertNotNull("Failed to get controller target", controllerTarget);
+ OvsdbBridgeAugmentation bridge = southboundUtils.getBridge(connectionInfo, INTEGRATION_BRIDGE_NAME);
+ assertNotNull(bridge);
+ assertNotNull(bridge.getControllerEntry());
+ controllerEntry = bridge.getControllerEntry().iterator().next();
+ assertEquals(controllerTarget, controllerEntry.getTarget().getValue());
+ if (controllerEntry.isIsConnected()) {
+ Assert.assertTrue(controllerEntry.isIsConnected());
+ break;
}
+ Thread.sleep(1000);
}
/* TODO: add code to write to mdsal to exercise the sfc dataChangeListener */
/* allow some time to let the impl code do it's work to push flows */
/* or just comment out below lines and just manually verify on the bridges and reset them */
- Thread.sleep(10000);
+ //Thread.sleep(10000);
- Assert.assertTrue(southboundUtils.deleteBridge(connectionInfo, BRIDGE_NAME));
- southboundUtils.disconnectOvsdbNode(connectionInfo);
+ assertTrue(southboundUtils.deleteBridge(connectionInfo, INTEGRATION_BRIDGE_NAME));
+ Thread.sleep(1000);
+ assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
}
}
<properties>
<karaf.localFeature>odl-ovsdb-sfc-test</karaf.localFeature>
</properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openstack.net-virt-sfc-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
<dependencies>
<dependency>
<!-- scope is compile so all features (there is only one) are installed