@Override
public void addClassifierRules(Acl acl) {
- String aclName = acl.getAclName();
- Classifiers classifiers = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, sfcUtils.getClassifierIid());
- if (classifiers == null) {
- LOG.debug("addClassifierRules: No Classifiers found");
- return;
- }
-
- LOG.debug("addClassifierRules: Classifiers: {}", classifiers);
- for (Classifier classifier : classifiers.getClassifier()) {
- if (classifier.getAcl().equals(aclName)) {
- for (Ace ace : acl.getAccessListEntries().getAce()) {
- processAclEntry(ace);
- }
- }
+ for (Ace ace : acl.getAccessListEntries().getAce()) {
+ processAclEntry(ace);
}
}
@Override
public void removeClassifierRules(Acl acl) {
-
+ for (Ace ace : acl.getAccessListEntries().getAce()) {
+ RenderedServicePath rsp = getRenderedServicePath(ace);
+ if (rsp == null) {
+ LOG.warn("Failed to get renderedServicePatch for entry: {}", ace);
+ return;
+ }
+ sfcClassifierService.clearFlows(dataBroker, rsp.getName().getValue());
+ }
}
@Override
public void removeRsp(RenderedServicePath change) {
- LOG.info("removeRsp not implemented yet");
sfcClassifierService.clearFlows(dataBroker, change.getName().getValue());
}
+ @Override
+ public void addRsp(RenderedServicePath change) {
+ handleRenderedServicePath(change);
+ }
+
@Override
public void updateRsp(RenderedServicePath change) {
LOG.info("updateRsp not implemented yet");
private Ace getAceFromRenderedServicePath(RenderedServicePath rsp) {
Preconditions.checkNotNull(rsp, "RSP cannot be null");
- Ace ace = null;
- String rspName = rsp.getName().getValue();
- String rspNameSuffix = "_rsp";
- String sfcName = rspName.substring(0, rspName.length() - rspNameSuffix.length());
- LOG.info("getAceFromRenderedServicePath: rsp: {}, sfcName: {}", rsp, sfcName);
- ace = sfcUtils.getAce(sfcName);
+ Ace ace;
+ //String rspName = rsp.getName().getValue();
+ //String rspNameSuffix = "_rsp";
+ //String sfcName = rspName.substring(0, rspName.length() - rspNameSuffix.length());
+ //String sfcName = rsp.getServiceChainName().getValue()
+ //LOG.info("getAceFromRenderedServicePath: rsp: {}, sfcName: {}", rsp, sfcName);
+ ace = sfcUtils.getAce(rsp);
return ace;
}
private RenderedServicePath getRenderedServicePath (Ace entry) {
RenderedServicePath rsp = null;
RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
- LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+ LOG.debug("getRenderedServicePath: Processing ACL entry = {} sfcRedirect = {}",
+ entry.getRuleName(), sfcRedirect);
if (sfcRedirect == null) {
- LOG.warn("processAClEntry: sfcRedirect is null");
+ LOG.warn("getRenderedServicePath: sfcRedirect is null");
return null;
}
if (sfcRedirect.getRspName() != null) {
rsp = getRenderedServicePathFromRsp(sfcRedirect.getRspName());
} else if (sfcRedirect.getSfpName() != null) {
- LOG.warn("getRenderedServicePath: sfp not handled yet");
+ LOG.warn("getRenderedServicePath: by sfp not handled yet");
} else {
rsp = getRenderedServicePathFromSfc(entry);
}
private RenderedServicePath getRenderedServicePathFromSfc (Ace entry) {
RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
- LOG.debug("Processing ACL entry = {} sfcRedirect = {}", entry.getRuleName(), sfcRedirect);
+ LOG.debug("getRenderedServicePathFromSfc: Processing ACL entry = {} sfcRedirect = {}",
+ entry.getRuleName(), sfcRedirect);
if (sfcRedirect == null) {
- LOG.warn("processAClEntry: sfcRedirect is null");
+ LOG.warn("getRenderedServicePathFromSfc: sfcRedirect is null");
return null;
}
return null;
}
- LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
+ LOG.debug("getRenderedServicePathFromSfc: Processing Redirect to SFC = {}, SFP = {}", sfcName, sfp);
// If RSP doesn't exist, create an RSP.
String sfpName = sfp.getName().getValue();
RenderedServicePath rsp = sfcUtils.getRspforSfp(sfpName);
String rspName = sfp.getName().getValue() + "_rsp";
if (rsp == null) {
- LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}", sfpName, rspName);
+ if (!sfcRedirect.isRenderRsp()) {
+ LOG.info("getRenderedServicePathFromSfc: will not create RSP");
+ return null;
+ }
+ LOG.info("getRenderedServicePathFromSfc: No configured RSP corresponding to SFP = {}, "
+ + "Creating new RSP = {}", sfpName, rspName);
CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
.setParentServiceFunctionPath(sfpName)
.setName(rspName)
.build();
rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
if (rsp == null) {
- LOG.warn("failed to add RSP");
+ LOG.warn("getRenderedServicePathFromSfc: failed to add RSP");
return null;
}
// If SFP is symmetric, create RSP in the reverse direction.
if (sfp.isSymmetric()) {
- LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
+ LOG.warn("getRenderedServicePathFromSfc: symmetric RSP is not supported yet");
+ /*LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
String rspNameRev = rspName + "-Reverse";
RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
sfcUtils.getRspId(rspNameRev));
LOG.warn("failed to add reverse RSP");
return null;
}
- }
+ }*/
}
}
return rsp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.SfcUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.RenderedServicePathUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.standalone.openflow13.SfcClassifier;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.AclUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.it.utils.ClassifierUtils;
import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SftType;
+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.RenderedServicePaths;
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.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.ops4j.pax.exam.Configuration;
private static ServiceFunctionForwarderUtils serviceFunctionForwarderUtils = new ServiceFunctionForwarderUtils();
private static ServiceFunctionChainUtils serviceFunctionChainUtils = new ServiceFunctionChainUtils();
private static ServiceFunctionPathUtils serviceFunctionPathUtils = new ServiceFunctionPathUtils();
+ private static RenderedServicePathUtils renderedServicePathUtils = new RenderedServicePathUtils();
private static SfcConfigUtils sfcConfigUtils = new SfcConfigUtils();
private static NetvirtConfigUtils netvirtConfigUtils = new NetvirtConfigUtils();
private static MdsalUtils mdsalUtils;
setup.set(true);
}
+ @After
+ public void teardown() {
+ closeWaitFors();
+ }
+
private ProviderContext getProviderContext() {
ProviderContext providerContext = null;
for (int i=0; i < 60; i++) {
}
private AccessListsBuilder accessListsBuilder() {
+ return accessListsBuilder(false);
+ }
+
+ private AccessListsBuilder accessListsBuilder(boolean renderRsp) {
String ruleName = RULENAME;
String sfcName = SFCNAME;
MatchesBuilder matchesBuilder = aclUtils.matchesBuilder(new MatchesBuilder(), 80);
LOG.info("Matches: {}", matchesBuilder.build());
- ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), sfcName);
+ ActionsBuilder actionsBuilder = aclUtils.actionsBuilder(new ActionsBuilder(), sfcName, renderRsp);
AceBuilder accessListEntryBuilder =
aclUtils.aceBuilder(new AceBuilder(), ruleName, matchesBuilder, actionsBuilder);
AccessListEntriesBuilder accessListEntriesBuilder =
bridgeOperationalListener.registerDataChangeListener();
assertNotNull("connection failed", southboundUtils.addOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
- ovsdbOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+ ovsdbOperationalListener.waitForCreation();
ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
assertNotNull("node is not connected", ovsdbNode);
- bridgeOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+ bridgeOperationalListener.waitForCreation();
assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+ " is not connected", isControllerConnected(connectionInfo));
void disconnect() throws InterruptedException {
assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName, NO_MDSAL_TIMEOUT));
- bridgeOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ bridgeOperationalListener.waitForDeletion();
Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
assertNull("Bridge should not be found", bridgeNode);
assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
- ovsdbOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ ovsdbOperationalListener.waitForDeletion();
Node ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
assertNull("Ovsdb node should not be found", ovsdbNode);
}
/**
* Test that the NetvirtSfc SfcClassifierService is added to the Netvirt pipeline. The test
* sets the table offset and verifies the correct flow is programmed with the offset.
- * @throws InterruptedException
*/
@Test
public void testNetvirtSfcPipeline() throws InterruptedException {
* @throws InterruptedException
*/
@Test
- public void testNetvirtSfcAll() throws InterruptedException {
+ public void testNetvirtSfcAll() throws Exception {
if (userSpaceEnabled.equals("yes")) {
LOG.info("testNetvirtSfcAll: skipping test because userSpaceEnabled {}", userSpaceEnabled);
return;
}
+ String sfpName = SFCPATH;
+ String sfcName = SFCNAME;
+ short startingIndex = 255;
+
short netvirtTableOffset = 1;
testModelPut(netvirtProvidersConfigBuilder(netvirtTableOffset), NetvirtProvidersConfig.class);
short sfcTableoffset = 150;
testModelPut(serviceFunctionChainsBuilder(), ServiceFunctionChains.class);
testModelPut(serviceFunctionPathsBuilder(), ServiceFunctionPaths.class);
- testModelPut(accessListsBuilder(), AccessLists.class);
+ testModelPut(accessListsBuilder(false), AccessLists.class);
testModelPut(classifiersBuilder(), Classifiers.class);
+ ServiceFunctionPathBuilder serviceFunctionPathBuilder =
+ serviceFunctionPathUtils.serviceFunctionPathBuilder(
+ new ServiceFunctionPathBuilder(), sfpName, sfcName, startingIndex, false);
+ SfcProviderRenderedPathAPI.createRenderedServicePathAndState(serviceFunctionPathBuilder.build(),
+ renderedServicePathUtils.createRenderedPathInputBuilder(new CreateRenderedPathInputBuilder(),
+ SFCPATH, RSPNAME).build());
- portOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+ portOperationalListener.waitForCreation();
long vxGpeOfPort = southbound.getOFPort(nodeInfo.bridgeNode, SFFDPL1NAME);
assertNotEquals("vxGpePort was not found", 0, vxGpeOfPort);
- rspOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+ rspOperationalListener.waitForCreation();
RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
assertNotNull("RSP was not found", rsp);
flowId = FlowNames.getSfcIngressClass(RULENAME, rsp.getPathId(), rsp.getStartingIndex());
verifyFlow(nodeInfo.datapathId, flowId, Service.SFC_CLASSIFIER);
- flowId = FlowNames.getArpResponder(SF1IP);
- verifyFlow(nodeInfo.datapathId, flowId, Service.ARP_RESPONDER);
RenderedServicePathHop lastHop = sfcUtils.getLastHop(rsp);
short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
flowId = FlowNames.getSfcEgressClass(vxGpeOfPort, rsp.getPathId(), lastServiceindex);
verifyFlow(nodeInfo.datapathId, flowId, Service.SFC_CLASSIFIER);
flowId = FlowNames.getSfcEgressClassBypass(rsp.getPathId(), lastServiceindex, 1);
verifyFlow(nodeInfo.datapathId, flowId, Service.CLASSIFIER);
+ flowId = FlowNames.getArpResponder(SF1IP);
+ verifyFlow(nodeInfo.datapathId, flowId, Service.ARP_RESPONDER);
+
+ InstanceIdentifier<Flow> flowIid = createFlowIid(nodeInfo.datapathId, flowId,
+ pipelineOrchestrator.getTable(Service.CLASSIFIER));
+
+ final NotifyingDataChangeListener flowConfigurationListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.CONFIGURATION, flowIid);
+ flowConfigurationListener.registerDataChangeListener();
+ final NotifyingDataChangeListener flowOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, flowIid);
+ flowOperationalListener.registerDataChangeListener();
deleteRsp(RSPNAME);
- rspOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ rspOperationalListener.waitForDeletion();
rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
assertNull("RSP should not be found", rsp);
+ flowConfigurationListener.waitForDeletion();
+ Flow flow = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, flowIid);
+ assertNull("Flow should not be found in CONFIGURATION " + flowIid, flow);
+
+ flowOperationalListener.waitForDeletion();
+ flow = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, flowIid);
+ assertNull("Flow should not be found in OPERATIONAL " + flowIid, flow);
+
nodeInfo.disconnect();
}
assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
}
+ private InstanceIdentifier<Flow> createFlowIid(long datapathId, String flowId, short table) {
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+ FlowUtils.createNodeBuilder(datapathId);
+ FlowBuilder flowBuilder =
+ FlowUtils.initFlowBuilder(new FlowBuilder(), flowId, table);
+ return FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
+ }
+
private Flow getFlow (
FlowBuilder flowBuilder,
org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder,
return connected;
}
- public class NotifyingDataChangeListener implements DataChangeListener {
- private final LogicalDatastoreType type;
+ private List<NotifyingDataChangeListener> waitList = new ArrayList<>();
+
+ private void closeWaitFors() {
+ for (Iterator<NotifyingDataChangeListener> iterator = waitList.iterator(); iterator.hasNext();) {
+ NotifyingDataChangeListener listener = iterator.next();
+ iterator.remove();
+ try {
+ listener.close();
+ } catch (Exception ex) {
+ LOG.warn("Failed to close registration {}, iid {}", listener, ex);
+ }
+ }
+ LOG.info("waitList size {}", waitList.size());
+ }
+
+ public class NotifyingDataChangeListener implements AutoCloseable, DataChangeListener {
+ private LogicalDatastoreType type;
private final Set<InstanceIdentifier<?>> createdIids = new HashSet<>();
private final Set<InstanceIdentifier<?>> removedIids = new HashSet<>();
private final Set<InstanceIdentifier<?>> updatedIids = new HashSet<>();
- private final InstanceIdentifier<?> iid;
+ private InstanceIdentifier<?> iid;
private final int RETRY_WAIT = 100;
+ private final int MDSAL_TIMEOUT = 1000;
+ private ListenerRegistration<?> listenerRegistration;
private NotifyingDataChangeListener(LogicalDatastoreType type, InstanceIdentifier<?> iid) {
this.type = type;
this.iid = iid;
+ waitList.add(this);
+ }
+
+ private void modify(LogicalDatastoreType type, InstanceIdentifier<?> iid) throws Exception {
+ this.close();
+ this.clear();
+ this.type = type;
+ this.iid = iid;
}
@Override
public void onDataChanged(
AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
LOG.info("{} DataChanged: created {}", type, asyncDataChangeEvent.getCreatedData().keySet());
- LOG.info("{} DataChanged: removed {}", type, asyncDataChangeEvent.getRemovedPaths());
LOG.info("{} DataChanged: updated {}", type, asyncDataChangeEvent.getUpdatedData().keySet());
+ LOG.info("{} DataChanged: removed {}", type, asyncDataChangeEvent.getRemovedPaths());
createdIids.addAll(asyncDataChangeEvent.getCreatedData().keySet());
removedIids.addAll(asyncDataChangeEvent.getRemovedPaths());
updatedIids.addAll(asyncDataChangeEvent.getUpdatedData().keySet());
return createdIids.remove(iid);
}
- public boolean isRemoved(InstanceIdentifier<?> iid) {
- return removedIids.remove(iid);
- }
-
public boolean isUpdated(InstanceIdentifier<?> iid) {
return updatedIids.remove(iid);
}
+ public boolean isRemoved(InstanceIdentifier<?> iid) {
+ return removedIids.remove(iid);
+ }
+
public void clear() {
createdIids.clear();
removedIids.clear();
}
public void registerDataChangeListener() {
- dataBroker.registerDataChangeListener(type, iid, this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ listenerRegistration = dataBroker.registerDataChangeListener(type, iid, this,
+ AsyncDataBroker.DataChangeScope.SUBTREE);
+ }
+
+ public void waitForCreation() throws InterruptedException {
+ waitForCreation(MDSAL_TIMEOUT);
}
public void waitForCreation(long timeout) throws InterruptedException {
}
}
+ public void waitForUpdate() throws InterruptedException {
+ waitForUpdate(MDSAL_TIMEOUT);
+ }
+
+ public void waitForUpdate(long timeout) throws InterruptedException {
+ synchronized (this) {
+ long _start = System.currentTimeMillis();
+ LOG.info("Waiting for {} DataChanged update on {}", type, iid);
+ while (!isUpdated(iid) && (System.currentTimeMillis() - _start) < timeout) {
+ wait(RETRY_WAIT);
+ }
+ LOG.info("Woke up, waited {}ms for update of {}", (System.currentTimeMillis() - _start), iid);
+ }
+ }
+
+ public void waitForDeletion() throws InterruptedException {
+ waitForDeletion(MDSAL_TIMEOUT);
+ }
+
public void waitForDeletion(long timeout) throws InterruptedException {
synchronized (this) {
long _start = System.currentTimeMillis();
}
}
- public void waitForUpdate(long timeout) throws InterruptedException {
- synchronized (this) {
- long _start = System.currentTimeMillis();
- LOG.info("Waiting for {} DataChanged update on {}", type, iid);
- while (!isUpdated(iid) && (System.currentTimeMillis() - _start) < timeout) {
- wait(RETRY_WAIT);
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception ex) {
+ LOG.warn("Failed to close registration {}, iid {}", listenerRegistration, iid, ex);
}
- LOG.info("Woke up, waited {}ms for update of {}", (System.currentTimeMillis() - _start), iid);
}
+ waitList.remove(this);
+ listenerRegistration = null;
}
}
}