<Embed-Dependency>utils.mdsal-openflow;type=!pom;inline=false</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Export-Package>
- org.opendaylight.ovsdb.openstack.netvirt.sfc
+ org.opendaylight.ovsdb.openstack.netvirt.sfc,
+ org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services
</Export-Package>
</instructions>
</configuration>
public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
Preconditions.checkNotNull(changes, "Changes may not be null!");
- LOG.info("Received Data Tree Changed ...", changes);
+ LOG.info("onDataTreeChanged: Received Data Tree Changed ...", changes);
for (DataTreeModification<T> change : changes) {
final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
final DataObjectModification<T> mod = change.getRootNode();
- LOG.info("Received Data Tree Changed Update of Type={} for Key={}", mod.getModificationType(), key);
+ LOG.info("onDataTreeChanged: Received Data Tree Changed Update of Type={} for Key={}",
+ mod.getModificationType(), key);
+ LOG.info("onDataTreeChanged: mod: {}", mod);
switch (mod.getModificationType()) {
case DELETE:
remove(key, mod.getDataBefore());
package org.opendaylight.ovsdb.openstack.netvirt.sfc;
import java.net.InetAddress;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
public interface ISfcClassifierService {
- void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
- NshUtils nshHeader, long vxGpeOfPort, boolean write);
+ void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
+ NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write);
void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
- long sfOfPort, int tunnelId, boolean write);
+ long sfOfPort, int tunnelId, String rspName, boolean write);
void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
- long sfOfPort, int tunnelId, boolean write);
+ long sfOfPort, int tunnelId, String rspName, boolean write);
void program_sfEgress(long dataPathId, int dstPort, boolean write);
String ipAddress, String sfDplName, boolean write);
void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
- String ipAddress, boolean write);
+ String ipAddress, String rspName, boolean write);
+
+ void clearFlows(DataBroker dataBroker, String rspName);
}
--- /dev/null
+/*
+ * Copyright © 2015 Red Hat, 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.ovsdb.openstack.netvirt.sfc;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
+
+public interface ISfcStandaloneClassifierService {
+ void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
+ NshUtils nshHeader, long vxGpeOfPort, boolean write);
+
+ void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write);
+
+ void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+ int tunnelOfPort, int tunnelId, short gotoTableId, boolean write);
+
+ void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+ long sfOfPort, int tunnelId, boolean write);
+
+ void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
+ long sfOfPort, int tunnelId, boolean write);
+
+ void program_sfEgress(long dataPathId, int dstPort, boolean write);
+
+ void program_sfIngress(long dataPathId, int dstPort, long sfOfPort,
+ String ipAddress, String sfDplName, boolean write);
+
+ void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
+ String ipAddress, boolean write);
+}
LOG.info("Registering Data Change Listener for NetvirtSfc AccessList configuration.");
listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
} catch (final Exception e) {
- LOG.warn("Netvirt AccesList DataChange listener registration fail!");
+ LOG.warn("Netvirt AccessList DataChange listener registration fail!");
throw new IllegalStateException("NetvirtSfcAccessListListener startup fail! System needs restart.", e);
}
}
*/
public class RspListener extends AbstractDataTreeListener<RenderedServicePath> {
private static final Logger LOG = LoggerFactory.getLogger(RspListener.class);
+ private ListenerRegistration<RspListener> listenerRegistration;
public RspListener(final INetvirtSfcOF13Provider provider, final DataBroker db) {
super(provider, RenderedServicePath.class);
private void registrationListener(final DataBroker db) {
final DataTreeIdentifier<RenderedServicePath> treeId =
- new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getRspIid());
+ new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, getRspIid());
try {
LOG.info("Registering Data Change Listener for NetvirtSfc RenderedServicePath configuration.");
- ListenerRegistration<RspListener> listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
+ listenerRegistration = db.registerDataTreeChangeListener(treeId, this);
} catch (final Exception e) {
LOG.warn("Netvirt RenderedServicePath DataChange listener registration failed!");
- throw new IllegalStateException("NetvirtSfcAccessListListener startup failed! System needs restart.", e);
+ throw new IllegalStateException("RspListener startup failed! System needs restart.", e);
}
}
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
import org.opendaylight.sfc.provider.api.SfcProviderAclAPI;
+import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
import org.opendaylight.sfc.provider.api.SfcProviderServiceFunctionAPI;
import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths;
+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.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.ServiceFunctions;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunctionKey;
List<Ace> aces = accessListEntries.getAce();
for (Ace ace : aces) {
RedirectToSfc sfcRedirect = ace.getActions().getAugmentation(RedirectToSfc.class);
- if ((sfcRedirect != null && sfcRedirect.getRspName().equals(name)) ||
- (sfcRedirect != null && sfcRedirect.getSfcName().equals(name)) ||
- (sfcRedirect != null && sfcRedirect.getSfpName().equals(name))) {
+ if ((sfcRedirect != null) &&
+ (sfcRedirect.getRspName().equals(name) ||
+ (sfcRedirect.getSfcName().equals(name)) ||
+ (sfcRedirect.getSfpName().equals(name)))) {
aceFound = ace;
break;
}
}
}
+ if (aceFound != null) {
+ break;
+ }
}
}
}
return (Ip)serviceFunctionForwarder.getSffDataPlaneLocator().get(0).getDataPlaneLocator().getLocatorType();
}
+
+ public RenderedServicePathHop getFirstHop(RenderedServicePath rsp) {
+ List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+ if (pathHopList.isEmpty()) {
+ LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+ return null;
+ }
+
+ return pathHopList.get(0);
+ }
+
+ public RenderedServicePathHop getLastHop(RenderedServicePath rsp) {
+ List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
+ if (pathHopList.isEmpty()) {
+ LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
+ return null;
+ }
+
+ return pathHopList.get(pathHopList.size()-1);
+ }
}
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcStandaloneClassifierService;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
+public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface,
+ ISfcStandaloneClassifierService {
private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
public SfcClassifierService(Service service) {
@Override
public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr, String ipAddress, boolean write) {
-
}
}
private static final short SFC_TABLE = 150;
private MdsalUtils mdsalUtils;
private SfcUtils sfcUtils;
+ private DataBroker dataBroker;
private static final String VXGPE = "vxgpe";
public static final String TUNNEL_ENDPOINT_KEY = "local_ip";
Preconditions.checkNotNull(mdsalUtils, "Input mdsalUtils cannot be NULL!");
Preconditions.checkNotNull(sfcUtils, "Input sfcUtils cannot be NULL!");
+ this.dataBroker = dataBroker;
this.mdsalUtils = mdsalUtils;
this.sfcUtils = sfcUtils;
}
}
+ @Override
+ public void removeRsp(RenderedServicePath change) {
+ LOG.info("removeRsp not implemented yet");
+ sfcClassifierService.clearFlows(dataBroker, change.getName().getValue());
+ }
+
+ @Override
+ public void updateRsp(RenderedServicePath change) {
+ LOG.info("updateRsp not implemented yet");
+ }
+
private void processAclEntry(Ace entry) {
Matches matches = entry.getMatches();
Preconditions.checkNotNull(matches, "ACL Entry cannot be null!");
for (RenderedServicePathHop hop : pathHopList) {
for (Node bridgeNode : bridgeNodes) {
// ignore bridges other than br-int
+ // TODO: Get bridge name from DPL, rework this loop to use DPL list
OvsdbBridgeAugmentation ovsdbBridgeAugmentation = southbound.getBridge(bridgeNode, "br-int");
if (ovsdbBridgeAugmentation == null) {
continue;
}
+ // TODO: Get port name from the DPL
long vxGpeOfPort = getOFPort(bridgeNode, VXGPE);
if (vxGpeOfPort == 0L) {
- LOG.warn("programAclEntry: Could not identify gpe vtep {} -> OF ({}) on {}",
+ LOG.warn("handleRenderedServicePath: Could not identify gpe vtep {} -> OF ({}) on {}",
VXGPE, vxGpeOfPort, bridgeNode);
continue;
}
long dataPathId = southbound.getDataPathId(bridgeNode);
if (dataPathId == 0L) {
- LOG.warn("programAclEntry: Could not identify datapathId on {}", bridgeNode);
+ LOG.warn("handleRenderedServicePath: Could not identify datapathId on {}", bridgeNode);
continue;
}
ServiceFunction serviceFunction =
SfcProviderServiceFunctionAPI.readServiceFunction(firstHop.getServiceFunctionName());
if (serviceFunction == null) {
- LOG.warn("programAclEntry: Could not identify ServiceFunction {} on {}",
+ LOG.warn("handleRenderedServicePath: Could not identify ServiceFunction {} on {}",
firstHop.getServiceFunctionName().getValue(), bridgeNode);
continue;
}
SfcProviderServiceForwarderAPI
.readServiceFunctionForwarder(hop.getServiceFunctionForwarder());
if (serviceFunctionForwarder == null) {
- LOG.warn("programAclEntry: Could not identify ServiceFunctionForwarder {} on {}",
+ LOG.warn("handleRenderedServicePath: Could not identify ServiceFunctionForwarder {} on {}",
firstHop.getServiceFunctionName().getValue(), bridgeNode);
continue;
}
- handleSf(bridgeNode, serviceFunction);
+ handleSf(bridgeNode, serviceFunction, rsp);
handleSff(bridgeNode, serviceFunctionForwarder, serviceFunction, hop, firstHop, lastHop,
entry.getRuleName(), matches, vxGpeOfPort, rsp);
if (firstHop == lastHop) {
nshHeader.setNshTunUdpPort(ip.getPort());
}
sfcClassifierService.programIngressClassifier(dataPathId, ruleName, matches,
- nshHeader, vxGpeOfPort, true);
+ rsp.getPathId(), rsp.getStartingIndex(),
+ nshHeader, vxGpeOfPort, rsp.getName().getValue(), true);
} else if (hop == lastHop) {
LOG.info("handleSff: last hop processing {} - {}",
bridgeNode.getNodeId().getValue(), serviceFunctionForwarder.getName().getValue());
long sfOfPort = getSfPort(bridgeNode, sfDplName);
// TODO: Coexistence: SFC flows should take this using new egressTable REST
sfcClassifierService.programEgressClassifier(dataPathId, vxGpeOfPort, rsp.getPathId(),
- lastServiceindex, sfOfPort, 0, true);
+ lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
// TODO: Coexistence: This flow should like like one above, change port, add reg0=1, resubmit
sfcClassifierService.programEgressClassifierBypass(dataPathId, vxGpeOfPort, rsp.getPathId(),
- lastServiceindex, sfOfPort, 0, true);
+ lastServiceindex, sfOfPort, 0, rsp.getName().getValue(), true);
} else {
// add typical sff flows
}
//sfcClassifierService.programSfcTable(dataPathId, vxGpeOfPort, SFC_TABLE, true);
}
- void handleSf(Node bridgeNode, ServiceFunction serviceFunction) {
+ void handleSf(Node bridgeNode, ServiceFunction serviceFunction, RenderedServicePath rsp) {
if (isSfOnBridge(bridgeNode, serviceFunction)) {
LOG.info("handleSf: sf and bridge are on the same node: {} - {}, adding workaround and arp",
bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
// TODO: Coexistence: SFC flows should take this using new sf dpl augmentation
//sfcClassifierService.program_sfEgress(dataPathId, sfIpPort, true);
//sfcClassifierService.program_sfIngress(dataPathId, sfIpPort, sfOfPort, sfIpAddr, sfDplName, true);
- sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr, true);
+ sfcClassifierService.programStaticArpEntry(dataPathId, 0L, sfMac, sfIpAddr,
+ rsp.getName().getValue(), true);
} else {
LOG.info("handleSf: sf and bridge are not on the same node: {} - {}, do nothing",
bridgeNode.getNodeId().getValue(), serviceFunction.getName().getValue());
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);
return ace;
return mac;
}
- @Override
- public void removeRsp(RenderedServicePath change) {
- LOG.info("removeRsp not implemented yet");
- }
-
- @Override
- public void updateRsp(RenderedServicePath change) {
- LOG.info("updateRsp not implemented yet");
- }
-
@Override
public void setDependencies(ServiceReference serviceReference) {
nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
--- /dev/null
+/*
+ * Copyright © 2015 Red Hat, 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.ovsdb.openstack.netvirt.sfc.workaround.services;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
+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.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCache {
+ private static final Logger LOG = LoggerFactory.getLogger(FlowCache.class);
+ private Map<String, Map<Integer, InstanceIdentifier<Flow>>> flowCache = new HashMap<>();
+
+ public void addFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, int flowId) {
+ Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.get(rspName);
+ if (flowMap == null) {
+ LOG.info("addFlow: adding new flowMap for {}({})", rspName, flowId);
+ flowMap = new HashMap<>();
+ }
+ InstanceIdentifier<Flow> path = FlowUtils.createFlowPath(flowBuilder, nodeBuilder);
+ flowMap.put(flowId, path);
+ flowCache.put(rspName, flowMap);
+ LOG.info("addFlow: added {}({}) {} to cache size {} - {}", rspName, flowId, path,
+ flowCache.size(), flowCache);
+ }
+
+ public void removeFlow(String rspName, int flowId) {
+ Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.get(rspName);
+ if (flowMap != null) {
+ flowMap.remove(flowId);
+ if (flowMap.isEmpty()) {
+ flowCache.remove(rspName);
+ LOG.info("removeFlow: removed flowMap {}({}) from cache size {} - {}", rspName, flowId,
+ flowCache.size(), flowCache);
+ } else {
+ flowCache.put(rspName, flowMap);
+ }
+ }
+ LOG.info("removeFlow: removed {}({}) from cache size {} - {}", rspName, flowId, flowCache.size(), flowCache);
+ }
+
+ public Map<Integer, InstanceIdentifier<Flow>> getFlows(String rspName) {
+ return flowCache.get(rspName);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 Red Hat, 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.ovsdb.openstack.netvirt.sfc.workaround.services;
+
+public class FlowNames {
+
+ public static String getSfcIngressClass(String ruleName, long nsp, short nsi) {
+ return "sfcIngressClass_" + nsp + "_" + nsi + "_" + ruleName;
+ }
+
+ public static String getSfcTable(long vxGpeOfPort) {
+ return "sfcTable_" + vxGpeOfPort;
+ }
+
+ public static String getSfcEgressClass1(long vxGpeOfPort) {
+ return "sfcEgressClass1_" + vxGpeOfPort;
+ }
+
+ public static String getSfcEgressClass(long vxGpeOfPort, long nsp, short nsi) {
+ return "sfcEgressClass_" + nsp + "_" + nsi + "_" + vxGpeOfPort;
+ }
+
+ public static String getSfcEgressClassBypass(long nsp, short nsi, long sfOfPort) {
+ return "sfcEgressClassBypass_" + nsp + "_" + nsi + "_" + sfOfPort;
+ }
+
+ public static String getSfEgress(int dstPort) {
+ return "sfEgress_" + dstPort;
+ }
+
+ public static String getSfIngress(int dstPort, String ipAddress) {
+ return "sfIngress_" + dstPort + "_" + ipAddress;
+ }
+
+ public static String getArpResponder(String ipAddress) {
+ return "ArpResponder_" + ipAddress;
+ }
+}
package org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services;
import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.TransactionCommitFailedException;
import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
-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.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.FlowCookie;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
private static final short UDP_SHORT = 17;
static int cookieIndex = 0;
+ private FlowCache flowCache = new FlowCache();
private enum FlowID {
FLOW_INGRESSCLASS(1), FLOW_SFINGRESS(2), FLOW_SFEGRESS(3), FLOW_SFARP(4),
FlowID(int value) {
this.value = value;
}
-
}
private BigInteger getCookie(FlowID flowID) {
return flowBuilder;
}
+ private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
+ flowCache.addFlow(flowBuilder, nodeBuilder, rspName, flowID.value);
+ writeFlow(flowBuilder, nodeBuilder);
+ }
+
+ private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder, String rspName, FlowID flowID) {
+ flowCache.removeFlow(rspName, flowID.value);
+ removeFlow(flowBuilder, nodeBuilder);
+ }
+
@Override
- public void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
- NshUtils nshHeader, long vxGpeOfPort, boolean write) {
+ public void programIngressClassifier(long dataPathId, String ruleName, Matches matches, long nsp, short nsi,
+ NshUtils nshHeader, long vxGpeOfPort, String rspName, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfcIngressClass_" + ruleName;// + "_" + nshHeader.getNshNsp();
+ String flowName = FlowNames.getSfcIngressClass(ruleName, nsp, nsi);
initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_INGRESSCLASS,
(short)nshHeader.getNshNsp(), nshHeader.getNshNsi());
InstructionsBuilder isb = new InstructionsBuilder();
isb.setInstruction(instructions);
flowBuilder.setInstructions(isb.build());
- writeFlow(flowBuilder, nodeBuilder);
+ writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
} else {
- removeFlow(flowBuilder, nodeBuilder);
+ removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_INGRESSCLASS);
}
}
public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfcTable_" + vxGpeOfPort;
+ String flowName = FlowNames.getSfcTable(vxGpeOfPort);
initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_SFCTABLE)
.setPriority(1000);
int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfcEgressClass1_" + vxGpeOfPort;
+ String flowName = FlowNames.getSfcEgressClass1(vxGpeOfPort);
initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER), FlowID.FLOW_EGRESSCLASSUNUSED,
(short)nsp, nsi);
@Override
public void programEgressClassifier(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
- long sfOfPort, int tunnelId, boolean write) {
+ long sfOfPort, int tunnelId, String rspName, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfcEgressClass_" + nsp + "_" + + nsi + "_" + vxGpeOfPort;
+ String flowName = FlowNames.getSfcEgressClass(vxGpeOfPort, nsp, nsi);
initFlowBuilder(flowBuilder, flowName, getTable(Service.SFC_CLASSIFIER), FlowID.FLOW_EGRESSCLASS,
(short)nsp, nsi);
isb.setInstruction(instructions);
flowBuilder.setInstructions(isb.build());
- writeFlow(flowBuilder, nodeBuilder);
+ writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
} else {
- removeFlow(flowBuilder, nodeBuilder);
+ removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASS);
}
}
@Override
public void programEgressClassifierBypass(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
- long sfOfPort, int tunnelId, boolean write) {
+ long sfOfPort, int tunnelId, String rspName, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfcEgressClassBypass_" + nsp + "_" + + nsi + "_" + sfOfPort;
+ String flowName = FlowNames.getSfcEgressClassBypass(nsp, nsi, sfOfPort);
initFlowBuilder(flowBuilder, flowName, getTable(Service.CLASSIFIER),
FlowID.FLOW_EGRESSCLASSBYPASS, (short)nsp, nsi)
.setPriority(40000);
isb.setInstruction(instructions);
flowBuilder.setInstructions(isb.build());
- writeFlow(flowBuilder, nodeBuilder);
+ writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
} else {
- removeFlow(flowBuilder, nodeBuilder);
+ removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_EGRESSCLASSBYPASS);
}
}
public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfEgress_" + dstPort;
+ String flowName = FlowNames.getSfEgress(dstPort);
initFlowBuilder(flowBuilder, flowName, getTable(), FlowID.FLOW_SFEGRESS);
MatchBuilder matchBuilder = new MatchBuilder();
String ipAddress, String sfDplName, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "sfIngress_" + dstPort + "_" + ipAddress;
+ String flowName = FlowNames.getSfIngress(dstPort, ipAddress);
initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable(), FlowID.FLOW_SFINGRESS);
MatchBuilder matchBuilder = new MatchBuilder();
@Override
public void programStaticArpEntry(long dataPathId, long ofPort, String macAddressStr,
- String ipAddress, boolean write) {
+ String ipAddress, String rspName, boolean write) {
NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
FlowBuilder flowBuilder = new FlowBuilder();
- String flowName = "ArpResponder_" + ipAddress;
+ String flowName = FlowNames.getArpResponder(ipAddress);
initFlowBuilder(flowBuilder, flowName, getTable(Service.ARP_RESPONDER), FlowID.FLOW_SFARP)
.setPriority(1024);
isb.setInstruction(instructions);
flowBuilder.setInstructions(isb.build());
- writeFlow(flowBuilder, nodeBuilder);
+ writeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
} else {
- removeFlow(flowBuilder, nodeBuilder);
+ removeFlow(flowBuilder, nodeBuilder, rspName, FlowID.FLOW_SFARP);
}
}
LOG.info("buildMatch: {}", matchBuilder.build());
return matchBuilder;
}
+
+ private static FlowID flowSet[] = {FlowID.FLOW_INGRESSCLASS, FlowID.FLOW_EGRESSCLASS,
+ FlowID.FLOW_EGRESSCLASSBYPASS, FlowID.FLOW_SFARP};
+
+ @Override
+ public void clearFlows(DataBroker dataBroker, String rspName) {
+ Map<Integer, InstanceIdentifier<Flow>> flowMap = flowCache.getFlows(rspName);
+ if (flowMap != null) {
+ for (FlowID flowID : flowSet) {
+ InstanceIdentifier<Flow> path = flowMap.get(flowID.value);
+ if (path != null) {
+ flowCache.removeFlow(rspName, flowID.value);
+ removeFlow(dataBroker, path);
+ }
+ }
+ }
+ }
+
+ private void removeFlow(DataBroker dataBroker, InstanceIdentifier<Flow> path) {
+ WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
+ modification.delete(LogicalDatastoreType.CONFIGURATION, path);
+
+ CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+ try {
+ commitFuture.get(); // TODO: Make it async (See bug 1362)
+ LOG.debug("Transaction success for deletion of Flow {}", path);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ modification.cancel();
+ }
+ }
}
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashSet;
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.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
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.MdsalHelper;
import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionPathUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.ServiceFunctionUtils;
import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcConfigUtils;
-import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.SfcUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.utils.NetvirtSfcUtils;
+import org.opendaylight.ovsdb.openstack.netvirt.sfc.workaround.services.FlowNames;
import org.opendaylight.ovsdb.southbound.SouthboundConstants;
import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
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.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry;
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;
@ExamReactorStrategy(PerClass.class)
public class NetvirtSfcIT extends AbstractMdsalTestBase {
private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcIT.class);
+ private static final int MDSAL_TIMEOUT = 10000;
+ private static final int NO_MDSAL_TIMEOUT = 0;
private static AclUtils aclUtils = new AclUtils();
private static ClassifierUtils classifierUtils = new ClassifierUtils();
- private static SfcUtils sfcUtils = new SfcUtils();
+ private static NetvirtSfcUtils netvirtSfcUtils = new NetvirtSfcUtils();
private static ServiceFunctionUtils serviceFunctionUtils = new ServiceFunctionUtils();
private static ServiceFunctionForwarderUtils serviceFunctionForwarderUtils = new ServiceFunctionForwarderUtils();
private static ServiceFunctionChainUtils serviceFunctionChainUtils = new ServiceFunctionChainUtils();
private static MdsalUtils mdsalUtils;
private static AtomicBoolean setup = new AtomicBoolean(false);
private static SouthboundUtils southboundUtils;
+ private static SfcUtils sfcUtils;
private static String addressStr;
private static String portStr;
private static String connectionType;
private static final String SF1DPLNAME = "sf1";
private static final String SF2DPLNAME = "sf2";
// Use 192.168.50.70 when running against vagrant vm for workaround testing
+ // Use 192.168.1.129 (or whatever address is dhcp'ed) for tacker-vm
// "192.168.50.70"; "127.0.0.1"; "192.168.1.129";
- private static final String SFF1IP = "192.168.1.129";
- private static final String SFF2IP = "192.168.1.129";//"127.0.0.1";
+ private static final String SFF1IP = "192.168.50.70";
+ private static final String SFF2IP = "127.0.0.1";
private static final String SFF1NAME = "sff1";
private static final String SFF2NAME = "sff2";
private static final String SFFDPL1NAME = "vxgpe";
private static final String BRIDGE2NAME= "br-int";
private static final String ACLNAME= "httpAcl";
private static final String RULENAME= "httpRule";
- private static final String SFCNAME = "sfc1";
+ private static final String SFCNAME = "SFC";
private static final String SFCPATH = "SFC-Path";
+ private static final String RSPNAME = SFCPATH + "_rsp";
private static final String SFCSF1NAME = "firewall-abstract";
private static final SftType SFCSF1TYPE = new SftType("firewall");
private static final int GPEUDPPORT = 6633;
.version(asInProject())
.type("jar")),
configureConsole().startLocalConsole(),
+ //vmOption("-verbose:class"),
vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
- keepRuntimeFolder()
+ keepRuntimeFolder()
};
}
mdsalUtils = new MdsalUtils(dataBroker);
assertNotNull("mdsalUtils should not be null", mdsalUtils);
southboundUtils = new SouthboundUtils(mdsalUtils);
+ sfcUtils = new SfcUtils(mdsalUtils);
assertTrue("Did not find " + NETVIRT_TOPOLOGY_ID, getNetvirtTopology());
southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
assertNotNull("southbound should not be null", southbound);
pipelineOrchestrator =
(PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
assertNotNull("pipelineOrchestrator should not be null", pipelineOrchestrator);
+
setup.set(true);
}
}
private SfcBuilder netvirtSfcBuilder() {
- return sfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
+ return netvirtSfcUtils.sfcBuilder(new SfcBuilder(), "sfc");
}
@Test
* Test that the NetvirtSfc SfcClassifierService is added to the Netvirt pipeline.
* @throws InterruptedException
*/
- @Test
+ /*@Test
public void testNetvirtSfcPipeline() throws InterruptedException {
- String bridgeName = INTEGRATION_BRIDGE_NAME;
ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
- assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+ InstanceIdentifier<Node> ovsdbIid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
+ final NotifyingDataChangeListener ovsdbOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+ ovsdbOperationalListener.registerDataChangeListener();
+
+ String bridgeName = INTEGRATION_BRIDGE_NAME;
+ InstanceIdentifier<Node> bridgeIid = SouthboundUtils.createInstanceIdentifier(connectionInfo, bridgeName);
+ final NotifyingDataChangeListener bridgeOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+ bridgeOperationalListener.registerDataChangeListener();
+ assertNotNull("connection failed", southboundUtils.addOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+
+ ovsdbOperationalListener.waitForCreation(MDSAL_TIMEOUT);
Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
assertNotNull("node is not connected", ovsdbNode);
+ bridgeOperationalListener.waitForCreation(MDSAL_TIMEOUT);
assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+ " is not connected", isControllerConnected(connectionInfo));
LOG.info("testNetVirt: bridgeNode: {}, datapathId: {} - {}", bridgeNode, datapathIdString, datapathId);
assertNotEquals("datapathId was not found", datapathId, 0);
- String flowId = "DEFAULT_PIPELINE_FLOW_" + Service.SFC_CLASSIFIER.getTable();
+ String flowId = "DEFAULT_PIPELINE_FLOW_" + pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
- readwait();
-
- assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
- Thread.sleep(1000);
- assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
+ assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName, NO_MDSAL_TIMEOUT));
+ bridgeOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+ assertNull("Bridge should not be found", bridgeNode);
+ assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+ ovsdbOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+ assertNull("Ovsdb node should not be found", ovsdbNode);
+ }*/
+
+ public class NotifyingDataChangeListener2 {
+ int something;
+
+ public NotifyingDataChangeListener2(int something) {
+ this.something = something;
+ }
}
+ @Test
+ public void testClassNotFound() throws InterruptedException {
+ LOG.info("shague >>>>>");
+ final NotifyingDataChangeListener2 lis2 = new NotifyingDataChangeListener2(500);
+ LOG.info("shague 2 >>>>>");
+ }
/**
* Test the full NetvirtSfc functionality by creating everything needed to realize a chain and
* then verify all flows have been created.
* NOTE: This test requires an OVS with the NSH v8 patch, otherwise it will fail miserably.
* @throws InterruptedException
*/
- @Test
+ /*@Test
public void testNetvirtSfcAll() throws InterruptedException {
if (userSpaceEnabled.equals("yes")) {
LOG.info("testNetvirtSfcAll: skipping test because userSpaceEnabled {}", userSpaceEnabled);
short egressTable = pipelineOrchestrator.getTable(Service.SFC_CLASSIFIER);
testModelPut(sfcOfRendererConfigBuilder(sfcTableoffset, egressTable), SfcOfRendererConfig.class);
- String bridgeName = INTEGRATION_BRIDGE_NAME;
ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
- assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
+ InstanceIdentifier<Node> ovsdbIid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
+ final NotifyingDataChangeListener ovsdbOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+ ovsdbOperationalListener.registerDataChangeListener();
+
+ String bridgeName = INTEGRATION_BRIDGE_NAME;
+ InstanceIdentifier<Node> bridgeIid = SouthboundUtils.createInstanceIdentifier(connectionInfo, bridgeName);
+ final NotifyingDataChangeListener bridgeOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+ bridgeOperationalListener.registerDataChangeListener();
+ assertNotNull("connection failed", southboundUtils.addOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+
+ ovsdbOperationalListener.waitForCreation(MDSAL_TIMEOUT);
Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
assertNotNull("node is not connected", ovsdbNode);
+ bridgeOperationalListener.waitForCreation(MDSAL_TIMEOUT);
assertTrue("Controller " + SouthboundUtils.connectionInfoToString(connectionInfo)
+ " is not connected", isControllerConnected(connectionInfo));
externalIds.clear();
externalIds.put("attached-mac", "f6:00:00:0c:00:02");
southboundUtils.addTerminationPoint(bridgeNode, "vm2", "internal");
- // SFC will add the SFF dpl port when creating the RSP
- /*Map<String, String> options = Maps.newHashMap();
- options.put("key", "flow");
- options.put("dst_port", String.valueOf(GPEUDPPORT));
- options.put("remote_ip", "flow");
- options.put("nshc1", "flow");
- options.put("nshc2", "flow");
- options.put("nsp", "flow");
- options.put("nsi", "flow");
- southboundUtils.addTerminationPoint(bridgeNode, "vxgpe", "vxlan", options, null);
- options.clear();
- options.put("key", "flow");
- options.put("remote_ip", "192.168.120.32");
- southboundUtils.addTerminationPoint(bridgeNode, "vx", "vxlan", options, null);*/
+
+ InstanceIdentifier<TerminationPoint> tpIid =
+ southboundUtils.createTerminationPointInstanceIdentifier(bridgeNode, SFFDPL1NAME);
+ final NotifyingDataChangeListener portOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, tpIid);
+ portOperationalListener.registerDataChangeListener();
+
+ InstanceIdentifier<RenderedServicePath> rspIid = sfcUtils.getRspId(RSPNAME);
+ final NotifyingDataChangeListener rspOperationalListener =
+ new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, rspIid);
+ rspOperationalListener.registerDataChangeListener();
testModelPut(serviceFunctionsBuilder(), ServiceFunctions.class);
testModelPut(serviceFunctionForwardersBuilder(), ServiceFunctionForwarders.class);
testModelPut(accessListsBuilder(), AccessLists.class);
testModelPut(classifiersBuilder(), Classifiers.class);
- long vxGpeOfPort = getOFPort(bridgeNode, "vxgpe");
+ portOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+ long vxGpeOfPort = southbound.getOFPort(bridgeNode, SFFDPL1NAME);
assertNotEquals("vxGpePort was not found", 0, vxGpeOfPort);
- readwait();
+ rspOperationalListener.waitForCreation(MDSAL_TIMEOUT);
+ RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
+ assertNotNull("RSP was not found", rsp);
- flowId = "sfcIngressClass_" + "httpRule";
+ flowId = FlowNames.getSfcIngressClass(RULENAME, rsp.getPathId(), rsp.getStartingIndex());
verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
- // SFC is adding these flows now
- //flowId = "sfcTable_" + vxGpeOfPort;
- //verifyFlow(datapathId, flowId, Service.CLASSIFIER);
- //flowId = "sfEgress_" + GPEUDPPORT;
- //verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
- //flowId = "sfIngress_" + GPEUDPPORT + "_" + SF1IP;
- //verifyFlow(datapathId, flowId, Service.CLASSIFIER);
- flowId = "ArpResponder_" + SF1IP;
+ flowId = FlowNames.getArpResponder(SF1IP);
verifyFlow(datapathId, flowId, Service.ARP_RESPONDER);
-
- readwait();
-
- assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName));
- Thread.sleep(1000);
- assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo));
- }
-
- // Not used yet
- private void getSffDplPort(String rspName) {
- long ofPort = 0;
+ RenderedServicePathHop lastHop = sfcUtils.getLastHop(rsp);
+ short lastServiceindex = (short)((lastHop.getServiceIndex()).intValue() - 1);
+ flowId = FlowNames.getSfcEgressClass(vxGpeOfPort, rsp.getPathId(), lastServiceindex);
+ verifyFlow(datapathId, flowId, Service.SFC_CLASSIFIER);
+ flowId = FlowNames.getSfcEgressClassBypass(rsp.getPathId(), lastServiceindex, 1);
+ verifyFlow(datapathId, flowId, Service.CLASSIFIER);
+
+ deleteRsp(RSPNAME);
+ rspOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, rspIid);
+ assertNull("RSP should not be found", rsp);
+
+ assertTrue(southboundUtils.deleteBridge(connectionInfo, bridgeName, NO_MDSAL_TIMEOUT));
+ bridgeOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid);
+ assertNull("Bridge should not be found", bridgeNode);
+ assertTrue(southboundUtils.disconnectOvsdbNode(connectionInfo, NO_MDSAL_TIMEOUT));
+ ovsdbOperationalListener.waitForDeletion(MDSAL_TIMEOUT);
+ ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbIid);
+ assertNull("Ovsdb node should not be found", ovsdbNode);
+ }*/
+
+ private void deleteRsp(String rspName) {
RenderedServicePathKey renderedServicePathKey =
new RenderedServicePathKey(RspName.getDefaultInstance(rspName));
InstanceIdentifier<RenderedServicePath> path =
InstanceIdentifier.create(RenderedServicePaths.class)
.child(RenderedServicePath.class, renderedServicePathKey);
- RenderedServicePath rsp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
- if (rsp == null) {
- LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
- return;
- }
- List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
- if (pathHopList.isEmpty()) {
- LOG.warn("handleRenderedServicePath: RSP {} has empty hops!!", rsp.getName());
- return;
- }
-
- for (RenderedServicePathHop hop : pathHopList) {
- }
+ mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, path);
}
/**
@Test
public void testStandalone() throws InterruptedException {
String bridgeName = "sw1";
- ConnectionInfo connectionInfo = southboundUtils.getConnectionInfo(addressStr, portStr);
+ ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(addressStr, portStr);
assertNotNull("connection failed", southboundUtils.connectOvsdbNode(connectionInfo));
Node ovsdbNode = southboundUtils.getOvsdbNode(connectionInfo);
assertNotNull("node is not connected", ovsdbNode);
return connected;
}
- private long getOFPort(Node bridgeNode, String portName) {
- long ofPort = 0L;
- OvsdbTerminationPointAugmentation port =
- southbound.extractTerminationPointAugmentation(bridgeNode, portName);
- if (port != null) {
- ofPort = southbound.getOFPort(port);
+ /*private static class NotifyingDataChangeListener2 implements DataChangeListener {
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent) {
+
+ }
+ }*/
+
+ /*public class NotifyingDataChangeListener implements DataChangeListener {
+ private final 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 final int RETRY_WAIT = 100;
+
+ private NotifyingDataChangeListener(LogicalDatastoreType type, InstanceIdentifier<?> iid) {
+ 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());
+ createdIids.addAll(asyncDataChangeEvent.getCreatedData().keySet());
+ removedIids.addAll(asyncDataChangeEvent.getRemovedPaths());
+ updatedIids.addAll(asyncDataChangeEvent.getUpdatedData().keySet());
+ synchronized(this) {
+ notifyAll();
+ }
+ }
+
+ public boolean isCreated(InstanceIdentifier<?> iid) {
+ return createdIids.remove(iid);
}
- if (ofPort == 0L) {
- for (int i = 0; i < 10; i++) {
- LOG.info("Looking for ofPort {}, try: {}", portName, i);
- TerminationPoint tp = southbound.readTerminationPoint(bridgeNode, null, portName);
- if (tp != null) {
- port = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
- if (port != null) {
- ofPort = southbound.getOFPort(port);
- LOG.info("found ofPort {} - {}, try: {}", portName, ofPort, i);
- break;
- }
+
+ public boolean isRemoved(InstanceIdentifier<?> iid) {
+ return removedIids.remove(iid);
+ }
+
+ public boolean isUpdated(InstanceIdentifier<?> iid) {
+ return updatedIids.remove(iid);
+ }
+
+ public void clear() {
+ createdIids.clear();
+ removedIids.clear();
+ updatedIids.clear();
+ }
+
+ public void registerDataChangeListener() {
+ dataBroker.registerDataChangeListener(type, iid, this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ }
+
+ public void waitForCreation(long timeout) throws InterruptedException {
+ synchronized (this) {
+ long _start = System.currentTimeMillis();
+ LOG.info("Waiting for {} DataChanged creation on {}", type, iid);
+ while (!isCreated(iid) && (System.currentTimeMillis() - _start) < timeout) {
+ wait(RETRY_WAIT);
}
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- LOG.error("Interrupted while waiting for ofPort {}", portName, e);
+ LOG.info("Woke up, waited {}ms for creation of {}", (System.currentTimeMillis() - _start), iid);
+ }
+ }
+
+ public void waitForDeletion(long timeout) throws InterruptedException {
+ synchronized (this) {
+ long _start = System.currentTimeMillis();
+ LOG.info("Waiting for {} DataChanged deletion on {}", type, iid);
+ while (!isRemoved(iid) && (System.currentTimeMillis() - _start) < timeout) {
+ wait(RETRY_WAIT);
}
+ LOG.info("Woke up, waited {}ms for deletion of {}", (System.currentTimeMillis() - _start), iid);
}
}
- return ofPort;
- }
+ }*/
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.rev150105.SfcBuilder;
-public class SfcUtils {
+public class NetvirtSfcUtils {
public SfcBuilder sfcBuilder(SfcBuilder sfcBuilder, String sfcName) {
return sfcBuilder.setName(sfcName);
}
return SouthboundMapper.createInstanceIdentifier(createManagedNodeId(key, bridgeName));
}
+ public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key, String bridgeName) {
+ return createInstanceIdentifier(key, new OvsdbBridgeName(bridgeName));
+ }
+
public InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(Node node, String portName){
InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier
}
public boolean addOvsdbNode(final ConnectionInfo connectionInfo) {
+ return addOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+ }
+
+ public boolean addOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
createInstanceIdentifier(connectionInfo),
createNode(connectionInfo));
- try {
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- } catch (InterruptedException e) {
- LOG.warn("Interrupted while waiting after adding OVSDB node {}", connectionInfoToString(connectionInfo), e);
+ if (timeout != 0) {
+ try {
+ Thread.sleep(timeout);
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting after adding OVSDB node {}",
+ connectionInfoToString(connectionInfo), e);
+ }
}
return result;
}
}
public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) {
+ return deleteOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+ }
+
+ public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
createInstanceIdentifier(connectionInfo));
- try {
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- } catch (InterruptedException e) {
- LOG.warn("Interrupted while waiting after deleting OVSDB node {}", connectionInfoToString(connectionInfo),
- e);
+ if (timeout != 0) {
+ try {
+ Thread.sleep(timeout);
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting after deleting OVSDB node {}",
+ connectionInfoToString(connectionInfo), e);
+ }
}
return result;
}
public Node connectOvsdbNode(final ConnectionInfo connectionInfo) {
- addOvsdbNode(connectionInfo);
+ return connectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+ }
+
+ public Node connectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
+ addOvsdbNode(connectionInfo, timeout);
Node node = getOvsdbNode(connectionInfo);
LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
return node;
}
public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) {
- deleteOvsdbNode(connectionInfo);
+ return disconnectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT);
+ }
+
+ public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) {
+ deleteOvsdbNode(connectionInfo, timeout);
LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
return true;
}
}
public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName) {
+ return deleteBridge(connectionInfo, bridgeName, OVSDB_UPDATE_TIMEOUT);
+ }
+ public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName, long timeout) {
boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName)));
- try {
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
- } catch (InterruptedException e) {
- LOG.warn("Interrupted while waiting after deleting bridge {}", bridgeName, e);
+ if (timeout != 0) {
+ try {
+ Thread.sleep(timeout);
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting after deleting bridge {}", bridgeName, e);
+ }
}
return result;
}
return protocolList;
}
+ public boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier<Node> bridgeIid,
+ final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries,
+ final Class<? extends OvsdbFailModeBase> failMode, final boolean setManagedBy,
+ final Class<? extends DatapathTypeBase> dpType,
+ final List<BridgeExternalIds> externalIds,
+ final List<ControllerEntry> controllerEntries,
+ final List<BridgeOtherConfigs> otherConfigs,
+ final String dpid) throws InterruptedException {
+ return addBridge(connectionInfo, bridgeIid, bridgeName, bridgeNodeId, setProtocolEntries, failMode,
+ setManagedBy, dpType, externalIds, controllerEntries, otherConfigs, dpid);
+ }
+
/*
* base method for adding test bridges. Other helper methods used to create bridges should utilize this method.
*
final List<BridgeExternalIds> externalIds,
final List<ControllerEntry> controllerEntries,
final List<BridgeOtherConfigs> otherConfigs,
- final String dpid) throws InterruptedException {
+ final String dpid, long timeout) throws InterruptedException {
NodeBuilder bridgeNodeBuilder = new NodeBuilder();
if (bridgeIid == null) {
ovsdbBridgeAugmentationBuilder.toString());
boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
bridgeIid, bridgeNodeBuilder.build());
- Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+ if (timeout != 0) {
+ Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+ }
return result;
}