import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.unimgr.mef.nrp.api.EndPoint;
import org.opendaylight.unimgr.mef.nrp.common.ResourceActivator;
-import org.opendaylight.unimgr.mef.nrp.common.ResourceActivatorException;
import org.opendaylight.unimgr.mef.nrp.common.ResourceNotAvailableException;
import org.opendaylight.unimgr.mef.nrp.ovs.transaction.TableTransaction;
import org.opendaylight.unimgr.mef.nrp.ovs.transaction.TopologyTransaction;
import org.opendaylight.unimgr.mef.nrp.ovs.util.OpenFlowUtils;
-import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPort;
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.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
public class OvsActivator implements ResourceActivator {
private final DataBroker dataBroker;
+ private String serviceName;
private static final Logger LOG = LoggerFactory.getLogger(OvsActivator.class);
public OvsActivator(DataBroker dataBroker) {
this.dataBroker = dataBroker;
}
+ /**
+ * Set state for the driver for a (de)activation transaction.
+ * @param endPoints list of endpoint to interconnect
+ */
@Override
- public void activate(List<EndPoint> endPoints, String serviceName) throws ResourceActivatorException, TransactionCommitFailedException {
-// // Transaction - Get Open vSwitch node and its flow table
-// String portName = flowPoint.getTp().getValue();
-// TopologyTransaction topologyTransaction = new TopologyTransaction(dataBroker);
-// Node node = topologyTransaction.readNode(portName);
-// Table table = OpenFlowUtils.getTable(node);
-//
-// // Prepare list of flows to be added/removed
-// List<Flow> flowsToWrite = new ArrayList<>();
-// List<Flow> flowsToDelete = new ArrayList<>();
-// List<Link> interswitchLinks = topologyTransaction.readInterswitchLinks(node);
-// if (!OpenFlowUtils.isTablePreconfigured(table)) {
-// LOG.debug("Table is not preconfigured. Adding base flows.");
-// flowsToWrite.addAll(OpenFlowUtils.getBaseFlows(interswitchLinks));
-// flowsToDelete.addAll(OpenFlowUtils.getExistingFlows(table));
-// }
-// OvsActivatorHelper ovsActivatorHelper = new OvsActivatorHelper(topologyTransaction, flowPoint);
-// String openFlowPortName = ovsActivatorHelper.getOpenFlowPortName();
-// int externalVlanId = ovsActivatorHelper.getServiceVlanId();
-// int internalVlanId = ovsActivatorHelper.getInternalVlanId();
-// flowsToWrite.addAll(OpenFlowUtils.getVlanFlows(openFlowPortName, externalVlanId, internalVlanId, interswitchLinks, outerName));
-//
-// // Transaction - Add flows related to service to table and remove unnecessary flows
-// TableTransaction tableTransaction = new TableTransaction(dataBroker, node, table);
-// tableTransaction.deleteFlows(flowsToDelete, true);
-// tableTransaction.writeFlows(flowsToWrite);
+ public void activate(List<EndPoint> endPoints, String serviceName) throws ResourceNotAvailableException, TransactionCommitFailedException {
+ this.serviceName = serviceName;
+ for (EndPoint endPoint:endPoints)
+ activateEndpoint(endPoint);
+ }
+
+ private void activateEndpoint(EndPoint endPoint) throws ResourceNotAvailableException, TransactionCommitFailedException {
+ // Transaction - Get Open vSwitch node and its flow table
+ String portName = OvsActivatorHelper.getPortName(endPoint.getEndpoint().getServiceInterfacePoint().getValue());
+ TopologyTransaction topologyTransaction = new TopologyTransaction(dataBroker);
+ Node node = topologyTransaction.readNode(portName);
+ Table table = OpenFlowUtils.getTable(node);
+
+ // Prepare list of flows to be added/removed
+ List<Flow> flowsToWrite = new ArrayList<>();
+ List<Flow> flowsToDelete = new ArrayList<>();
+ List<Link> interswitchLinks = topologyTransaction.readInterswitchLinks(node);
+ if (!OpenFlowUtils.isTablePreconfigured(table)) {
+ LOG.debug("Table is not preconfigured. Adding base flows.");
+ flowsToWrite.addAll(OpenFlowUtils.getBaseFlows(interswitchLinks));
+ flowsToDelete.addAll(OpenFlowUtils.getExistingFlows(table));
+ }
+
+ OvsActivatorHelper ovsActivatorHelper = new OvsActivatorHelper(topologyTransaction, endPoint);
+ String openFlowPortName = ovsActivatorHelper.getOpenFlowPortName();
+ int externalVlanId = ovsActivatorHelper.getCeVlanId();
+ int internalVlanId = ovsActivatorHelper.getInternalVlanId();
+ flowsToWrite.addAll(OpenFlowUtils.getVlanFlows(openFlowPortName, externalVlanId, internalVlanId, interswitchLinks, serviceName));
+
+ // Transaction - Add flows related to service to table and remove unnecessary flows
+ TableTransaction tableTransaction = new TableTransaction(dataBroker, node, table);
+ tableTransaction.deleteFlows(flowsToDelete, true);
+ tableTransaction.writeFlows(flowsToWrite);
}
@Override
- public void deactivate(List<EndPoint> endPoints, String serviceName) throws TransactionCommitFailedException, ResourceActivatorException {
-// // Transaction - Get Open vSwitch node and its flow table
-// String portName = flowPoint.getTp().getValue();
-// TopologyTransaction topologyTransaction = new TopologyTransaction(dataBroker);
-// Node node = topologyTransaction.readNode(portName);
-// Table table = OpenFlowUtils.getTable(node);
-//
-// // Get list of flows to be removed
-// List<Flow> flowsToDelete = OpenFlowUtils.getServiceFlows(table, outerName);
-//
-// // Transaction - Remove flows related to service from table
-// TableTransaction tableTransaction = new TableTransaction(dataBroker, node, table);
-// tableTransaction.deleteFlows(flowsToDelete, false);
+ public void deactivate(List<EndPoint> endPoints, String serviceName) throws TransactionCommitFailedException, ResourceNotAvailableException {
+ for (EndPoint endPoint:endPoints)
+ deactivateEndpoint(endPoint);
}
+
+ private void deactivateEndpoint(EndPoint endPoint) throws ResourceNotAvailableException, TransactionCommitFailedException {
+ // Transaction - Get Open vSwitch node and its flow table
+ TopologyTransaction topologyTransaction = new TopologyTransaction(dataBroker);
+ OvsActivatorHelper ovsActivatorHelper = new OvsActivatorHelper(topologyTransaction,endPoint);
+
+ Node node = topologyTransaction.readNodeOF(ovsActivatorHelper.getOpenFlowPortName());
+ Table table = OpenFlowUtils.getTable(node);
+ // Get list of flows to be removed
+ List<Flow> flowsToDelete = OpenFlowUtils.getServiceFlows(table, serviceName);
+
+ // Transaction - Remove flows related to service from table
+ TableTransaction tableTransaction = new TableTransaction(dataBroker, node, table);
+ tableTransaction.deleteFlows(flowsToDelete, false);
+ }
+
}
*/
package org.opendaylight.unimgr.mef.nrp.ovs.activator;
+import org.opendaylight.unimgr.mef.nrp.api.EndPoint;
import org.opendaylight.unimgr.mef.nrp.common.ResourceNotAvailableException;
import org.opendaylight.unimgr.mef.nrp.ovs.exception.VlanNotSetException;
import org.opendaylight.unimgr.mef.nrp.ovs.transaction.TopologyTransaction;
import org.opendaylight.unimgr.mef.nrp.ovs.util.VlanUtils;
import org.opendaylight.unimgr.utils.NullAwareDatastoreGetter;
-import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.FcPort1;
-import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPort;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.nrp_interface.rev170227.nrp.create.connectivity.service.end.point.attrs.NrpCgEthFrameFlowCpaAspec;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
*/
class OvsActivatorHelper {
private List<NullAwareDatastoreGetter<Node>> nodes;
- private FcPort flowPoint;
+ private EndPoint endPoint;
+ private String tpName;
private Map<String, String> portMap;
- private static final String CTAG_VLAN_ID_NOT_SET_ERROR_MESSAGE = "C-Tag VLAN Id not set for termination point '%s'.";
- private static final String FC_PORT_NOT_AUGMENTED_ERROR_MESSAGE = "Forwarding Construct port '%s' does not have '%s' augmentation.";
+ private static final String CTAG_VLAN_ID_NOT_SET_ERROR_MESSAGE = "C-Tag VLAN Id not set for End Point '%s'.";
+ private static final String ATTRS_NOT_SET_ERROR_MESSAGE = "End Point '%s' does not have '%s' set.";
+
private static final Logger LOG = LoggerFactory.getLogger(OvsActivatorHelper.class);
- OvsActivatorHelper(TopologyTransaction topologyTransaction, FcPort flowPoint) {
+ OvsActivatorHelper(TopologyTransaction topologyTransaction, EndPoint endPoint) {
this.nodes = topologyTransaction.readNodes();
- this.flowPoint = flowPoint;
+ this.endPoint = endPoint;
+ tpName = getPortName(endPoint.getEndpoint().getServiceInterfacePoint().getValue());
this.portMap = createPortMap(nodes);
}
*
* @return Integer with VLAN Id
*/
- int getServiceVlanId() throws ResourceNotAvailableException {
- FcPort1 fcPort1 = flowPoint.getAugmentation(FcPort1.class);
- String tpName = flowPoint.getTp().getValue();
+ int getCeVlanId() throws ResourceNotAvailableException {
- if (fcPort1 != null) {
- if (fcPort1.getCTagVlanId() != null) {
- return fcPort1.getCTagVlanId().getValue().intValue();
+ if( (endPoint.getAttrs() != null) && (endPoint.getAttrs().getNrpCgEthFrameFlowCpaAspec()!=null) ){
+ NrpCgEthFrameFlowCpaAspec attr = endPoint.getAttrs().getNrpCgEthFrameFlowCpaAspec();
+ if( (attr.getCeVlanIdList()!=null) && !(attr.getCeVlanIdList().getVlanIdList().isEmpty()) ){
+ //for now we support only one CE VLAN
+ return attr.getCeVlanIdList().getVlanIdList().get(0).getVlanId().getValue().intValue();
} else {
LOG.warn(String.format(CTAG_VLAN_ID_NOT_SET_ERROR_MESSAGE, tpName));
throw new VlanNotSetException(String.format(CTAG_VLAN_ID_NOT_SET_ERROR_MESSAGE, tpName));
}
} else {
- String fcPort1ClassName = FcPort1.class.toString();
- LOG.warn(String.format(FC_PORT_NOT_AUGMENTED_ERROR_MESSAGE, tpName, fcPort1ClassName));
- throw new ResourceNotAvailableException(String.format(FC_PORT_NOT_AUGMENTED_ERROR_MESSAGE, tpName, fcPort1ClassName));
+ String className = NrpCgEthFrameFlowCpaAspec.class.toString();
+ LOG.warn(String.format(ATTRS_NOT_SET_ERROR_MESSAGE, tpName, className));
+ throw new ResourceNotAvailableException(String.format(ATTRS_NOT_SET_ERROR_MESSAGE, tpName, className));
}
}
*/
int getInternalVlanId() throws ResourceNotAvailableException {
VlanUtils vlanUtils = new VlanUtils(nodes);
- int serviceVlanId = getServiceVlanId();
+ int serviceVlanId = getCeVlanId();
if (vlanUtils.isVlanInUse(serviceVlanId)) {
LOG.debug("VLAN ID = '" + serviceVlanId + "' already in use.");
* @return String with port name
*/
String getOpenFlowPortName() {
- return portMap.get(flowPoint.getTp().getValue());
+ return portMap.get(tpName);
}
private Map<String, String> createPortMap(List<NullAwareDatastoreGetter<Node>> nodes) {
}
return portMap;
}
+
+ protected static String getPortName(String sip){
+ String[] tab = sip.split(":");
+ return tab[tab.length-1];
+ }
}
import org.opendaylight.unimgr.mef.nrp.api.ActivationDriver;
import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverBuilder;
import org.opendaylight.unimgr.mef.nrp.api.EndPoint;
-import org.opendaylight.unimgr.mef.nrp.common.ResourceActivatorException;
+import org.opendaylight.unimgr.mef.nrp.common.ResourceNotAvailableException;
import org.opendaylight.unimgr.mef.nrp.ovs.activator.OvsActivator;
+import org.opendaylight.unimgr.mef.nrp.ovs.tapi.TopologyDataHandler;
import org.opendaylight.yang.gen.v1.urn.mef.yang.nrp_interface.rev170227.NrpCreateConnectivityServiceAttrs;
import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.UniversalId;
-import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPort;
import java.util.List;
import java.util.Optional;
public class OvsDriver implements ActivationDriverBuilder {
private OvsActivator activator;
- private final DataBroker dataBroker;
- private static final String GROUP_NAME = "local";
- private static final long MTU_VALUE = 1522;
public OvsDriver(DataBroker dataBroker){
- this.dataBroker = dataBroker;
activator = new OvsActivator(dataBroker);
}
+
private ActivationDriver getDriver() {
return new ActivationDriver() {
- private FcPort aEnd;
- private FcPort zEnd;
- private String uuid;
+ List<EndPoint> endPoints;
+ String serviceId;
@Override
public void commit() {
@Override
public void initialize(List<EndPoint> endPoints, String serviceId, NrpCreateConnectivityServiceAttrs context) {
-
+ this.endPoints = endPoints;
+ this.serviceId = serviceId;
}
@Override
- public void activate() throws TransactionCommitFailedException, ResourceActivatorException {
- activator.activate(null,null);
+ public void activate() throws TransactionCommitFailedException, ResourceNotAvailableException {
+ activator.activate(endPoints,serviceId);
}
@Override
- public void deactivate() throws TransactionCommitFailedException, ResourceActivatorException {
- activator.deactivate(null,null);
+ public void deactivate() throws TransactionCommitFailedException, ResourceNotAvailableException {
+ activator.deactivate(endPoints,serviceId);
}
@Override
@Override
public UniversalId getNodeUuid() {
- return null;
+ return new UniversalId(TopologyDataHandler.getOvsNode());
}
}
--- /dev/null
+package org.opendaylight.unimgr.mef.nrp.ovs.tapi;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.unimgr.utils.CapabilitiesService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+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.yang.binding.DataObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import static org.opendaylight.unimgr.utils.CapabilitiesService.Capability.Mode.AND;
+import static org.opendaylight.unimgr.utils.CapabilitiesService.NodeContext.NodeCapability.OVSDB;
+
+/**
+ * Class created to classify object according to its modification types.
+ *
+ * @author marek.ryznar@amartus.com
+ */
+public class DataObjectModificationQualifier {
+ private static final Logger LOG = LoggerFactory.getLogger(DataObjectModificationQualifier.class);
+ private CapabilitiesService capabilitiesService;
+
+ public DataObjectModificationQualifier(DataBroker dataBroker){
+ capabilitiesService = new CapabilitiesService(dataBroker);
+ }
+
+ private Function<Node,Boolean> isOvs = node -> capabilitiesService.node(node).isSupporting(AND, OVSDB);
+
+ protected void checkNodes(List<DataObjectModification> nodes, Map<TerminationPoint,String> toAddMap, Map<TerminationPoint,String> toUpdateMap, Map<TerminationPoint,String> toDeleteMap){
+ Node n;
+ for(DataObjectModification node: nodes){
+ switch(node.getModificationType()){
+ //new ovs node
+ case WRITE :{
+ n = (Node) node.getDataAfter();
+ if(!isOvs.apply(n) || n.getTerminationPoint()==null)
+ break;
+ String bridgeName = n.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue();
+ n.getTerminationPoint().forEach(tp -> toAddMap.put(tp,bridgeName));
+ } break;
+ case SUBTREE_MODIFIED:{
+ checkTerminationPoints(node, toAddMap, toUpdateMap, toDeleteMap);
+ } break;
+ //whole ovs-node eg. s1 deleted
+ case DELETE:{
+ n = (Node) node.getDataBefore();
+ if(!isOvs.apply(n) || n.getTerminationPoint()==null)
+ break;
+ String bridgeName = n.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue();
+ n.getTerminationPoint().forEach(tp -> toDeleteMap.put(tp,bridgeName));
+ } break;
+ default:{
+ LOG.debug("Not supported modification type: {}",node.getModificationType());
+ } break;
+ }
+ }
+ }
+
+ private void checkTerminationPoints(DataObjectModification node, Map<TerminationPoint,String> toAddMap, Map<TerminationPoint,String> toUpdateMap, Map<TerminationPoint,String> toDeleteMap){
+ Node n = (Node) node.getDataAfter();
+ if(!isOvs.apply(n))
+ return ;
+ String bridgeName = n.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue();
+ Collection<DataObjectModification<? extends DataObject>> modifiedChildren = node.getModifiedChildren();
+
+ TerminationPoint terminationPoint;
+ for(DataObjectModification tp: modifiedChildren) {
+ if(!tp.getDataType().equals(TerminationPoint.class))
+ continue;
+ switch (tp.getModificationType()) {
+ //new port added eg. s1-eth7
+ case WRITE: {
+ terminationPoint = (TerminationPoint) tp.getDataAfter();
+ toAddMap.put(terminationPoint,bridgeName);
+ } break;
+ case SUBTREE_MODIFIED: {
+ terminationPoint = (TerminationPoint) tp.getDataAfter();
+ if (!tp.getDataBefore().equals(tp.getDataAfter()))
+ toUpdateMap.put(terminationPoint,bridgeName);
+ } break;
+ case DELETE: {
+ terminationPoint = (TerminationPoint) tp.getDataBefore();
+ toDeleteMap.put(terminationPoint,bridgeName);
+ } break;
+ default: {
+ LOG.debug("Not supported modification type: SUBTREE_MODIFIED.{}",tp.getModificationType());
+ } break;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs.tapi;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.*;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.unimgr.mef.nrp.common.NrpDao;
+import org.opendaylight.unimgr.mef.nrp.common.ResourceNotAvailableException;
+import org.opendaylight.unimgr.mef.nrp.ovs.transaction.TopologyTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.LifecycleState;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.TerminationDirection;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.UniversalId;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.context.attrs.ServiceInterfacePoint;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.context.attrs.ServiceInterfacePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.context.attrs.ServiceInterfacePointKey;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.service._interface.point.StateBuilder;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.node.OwnedNodeEdgePoint;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.node.OwnedNodeEdgePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.node.OwnedNodeEdgePointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+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.Link;
+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.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+
+/**
+ * TopologyDataHandler listens to ovsdb topology and propagate significant changes to presto ext topology.
+ *
+ * @author bartosz.michalik@amartus.com
+ */
+public class TopologyDataHandler implements DataTreeChangeListener<Node> {
+ private static final Logger LOG = LoggerFactory.getLogger(TopologyDataHandler.class);
+ private static final String OVS_NODE = "ovs-node";
+ private static final String DELIMETER = ":";
+ private static final InstanceIdentifier<Topology> OVSDB_TOPO_IID = InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId(new Uri("ovsdb:1"))));
+ private ListenerRegistration<TopologyDataHandler> registration;
+ private TopologyTransaction topologyTransaction;
+ private DataObjectModificationQualifier dataObjectModificationQualifier;
+
+ private final DataBroker dataBroker;
+
+ public TopologyDataHandler(DataBroker dataBroker) {
+ Objects.requireNonNull(dataBroker);
+ this.dataBroker = dataBroker;
+ topologyTransaction = new TopologyTransaction(dataBroker);
+ }
+
+ public void init() {
+ ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+
+ NrpDao dao = new NrpDao(tx);
+ dao.createSystemNode(OVS_NODE, null);
+
+ Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable Void result) {
+ LOG.info("Node {} created", OVS_NODE);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("No node created due to the error", t);
+ }
+ });
+
+ dataObjectModificationQualifier = new DataObjectModificationQualifier(dataBroker);
+ registerOvsdbTreeListener();
+ }
+
+ private void registerOvsdbTreeListener(){
+ InstanceIdentifier<Node> nodeId = OVSDB_TOPO_IID.child(Node.class);
+ registration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, nodeId), this);
+ }
+
+ public void close() {
+ ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+
+ NrpDao dao = new NrpDao(tx);
+ dao.removeNode(OVS_NODE, true);
+
+ Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable Void result) {
+ LOG.info("Node {} deleted", OVS_NODE);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("No node deleted due to the error", t);
+ }
+ });
+
+ if(registration != null) {
+ LOG.info("closing netconf tree listener");
+ registration.close();
+ }
+ }
+
+ @Override
+ public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> collection) {
+ final Map<TerminationPoint,String> toAddMap = new HashMap<>();
+ final Map<TerminationPoint,String> toDeleteMap = new HashMap<>();
+ final Map<TerminationPoint,String> toUpdateMap = new HashMap<>();
+
+ List<DataObjectModification> nodes = collection.stream()
+ .map(DataTreeModification::getRootNode)
+ .collect(Collectors.toList());
+
+ dataObjectModificationQualifier.checkNodes(nodes,toAddMap,toUpdateMap,toDeleteMap);
+
+ executeDbAction(addAction,toAddMap);
+ executeDbAction(updateAction,toUpdateMap);
+ executeDbAction(deleteAction,toDeleteMap);
+ }
+
+ BiConsumer<Map<TerminationPoint,String>,NrpDao> updateAction = (map,dao) -> {
+ map.entrySet()
+ .forEach(entry -> {
+ String nepId = OVS_NODE + DELIMETER + getFullPortName(entry.getValue(), entry.getKey().getTpId().getValue());
+ OwnedNodeEdgePoint nep;
+ if(dao.hasSip(nepId)){
+ nep = createNep(nepId);
+ dao.updateNep(OVS_NODE,nep);
+ } else {
+ addEndpoint(dao,nepId);
+ }
+ });
+ };
+
+ BiConsumer<Map<TerminationPoint,String>,NrpDao> deleteAction = (map,dao) -> {
+ map.entrySet()
+ .forEach(entry -> {
+ String nepId = OVS_NODE + DELIMETER + getFullPortName(entry.getValue(), entry.getKey().getTpId().getValue());
+ dao.removeNep(OVS_NODE,nepId,true);
+ });
+ };
+
+ BiConsumer<Map<TerminationPoint,String>,NrpDao> addAction = (map,dao) -> {
+ List<OwnedNodeEdgePoint> newNeps = getNewNeps(map);
+ newNeps.forEach(nep -> addEndpoint(dao,nep.getKey().getUuid().getValue()));
+ };
+
+ private void executeDbAction(BiConsumer<Map<TerminationPoint,String>,NrpDao> action,Map<TerminationPoint,String> map){
+ if(map.isEmpty())
+ return ;
+ final ReadWriteTransaction topoTx = dataBroker.newReadWriteTransaction();
+ NrpDao dao = new NrpDao(topoTx);
+
+ action.accept(map,dao);
+
+ Futures.addCallback(topoTx.submit(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(@Nullable Void result) {
+ LOG.debug("Ovs TAPI node action executed successfully");
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.warn("Ovs TAPI node action execution failed due to an error", t);
+ }
+ });
+ }
+
+ private String getFullPortName(String switchName, String portName){
+ return switchName + DELIMETER + portName;
+ }
+
+ private void addEndpoint(NrpDao dao, String nepName) {
+ ServiceInterfacePoint sip = createSip(nepName);
+
+ dao.addSip(sip);
+ dao.updateNep(OVS_NODE, nep(nepName, sip.getUuid()));
+ }
+
+ private OwnedNodeEdgePoint nep(String nepName, UniversalId sipUuid) {
+ UniversalId uuid = new UniversalId(nepName);
+ return new OwnedNodeEdgePointBuilder()
+ .setUuid(uuid)
+ .setKey(new OwnedNodeEdgePointKey(uuid))
+ .setMappedServiceInterfacePoint(Collections.singletonList(sipUuid))
+ .build();
+ }
+
+ private ServiceInterfacePoint createSip(String nep) {
+ UniversalId uuid = new UniversalId( "sip" + DELIMETER + nep);
+ return new ServiceInterfacePointBuilder()
+ .setUuid(uuid)
+ .setKey(new ServiceInterfacePointKey(uuid))
+ .setState(new StateBuilder().setLifecycleState(LifecycleState.Installed).build())
+ .setDirection(TerminationDirection.Bidirectional)
+ .build();
+ }
+
+ private OwnedNodeEdgePoint createNep(String nepId){
+ OwnedNodeEdgePointBuilder tpBuilder = new OwnedNodeEdgePointBuilder();
+ UniversalId tpId = new UniversalId(OVS_NODE + DELIMETER + nepId);
+ return tpBuilder
+ .setUuid(tpId)
+ .setKey(new OwnedNodeEdgePointKey(tpId))
+ .build();
+ }
+
+ private List<OwnedNodeEdgePoint> getNewNeps(Map<TerminationPoint,String> toAddMap){
+ return toAddMap.entrySet().stream()
+ .map(entry -> createNep(getFullPortName(entry.getValue(),entry.getKey().getTpId().getValue())) )
+ .collect(Collectors.toList());
+ }
+
+ //TODO: write better implementation
+ private boolean isNep(TerminationPoint terminationPoint){
+ OvsdbTerminationPointAugmentation ovsdbTerminationPoint = terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
+ if( ovsdbTerminationPoint==null || (ovsdbTerminationPoint.getInterfaceType()!=null && ovsdbTerminationPoint.getInterfaceType().equals(InterfaceTypeInternal.class))) {
+ return false;
+ }
+
+ if( ovsdbTerminationPoint.getOfport() == null )
+ return false;
+
+ String ofPortNumber = ovsdbTerminationPoint.getOfport().toString();
+ try {
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node = topologyTransaction.readNode(terminationPoint.getTpId().getValue());
+ String ofPortName = node.getId().getValue()+":"+ofPortNumber;
+ List<Link> links = topologyTransaction.readLinks(node);
+ return !links.stream()
+ .anyMatch(link -> link.getSource().getSourceTp().getValue().equals(ofPortName));
+ } catch (ResourceNotAvailableException e) {
+ LOG.warn(e.getMessage());
+ }
+ return false;
+ }
+
+ public static String getOvsNode() {
+ return OVS_NODE;
+ }
+}
\ No newline at end of file
throw new ResourceNotAvailableException(String.format(NODE_NOT_FOUND_ERROR_MESSAGE, portName));
}
+ public Node readNodeOF(String ofportName) throws ResourceNotAvailableException {
+ String ofNodeName = ofportName.split(":")[0]+":"+ofportName.split(":")[1];
+ Nodes nodes = readOpenFLowTopology(dataBroker);
+ if(nodes != null){
+ for(Node node: nodes.getNode()){
+ if(node.getId().getValue().equals(ofNodeName)){
+ return node;
+ }
+ }
+ } else {
+ LOG.warn(String.format(NODE_NOT_FOUND_ERROR_MESSAGE, "OpenFlow"));
+ throw new ResourceNotAvailableException(String.format(NODE_NOT_FOUND_ERROR_MESSAGE, "OpenFlow"));
+ }
+
+ LOG.warn(String.format(NODE_NOT_FOUND_ERROR_MESSAGE, ofportName));
+ throw new ResourceNotAvailableException(String.format(NODE_NOT_FOUND_ERROR_MESSAGE, ofportName));
+ }
+
/**
* Returns links associated with specified node
*
private InstanceIdentifier<Nodes> getNodesInstanceId() {
return InstanceIdentifier.builder(Nodes.class).build();
}
+
+ public static Nodes readOpenFLowTopology(DataBroker dataBroker){
+ InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
+ return (Nodes) MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,instanceIdentifier);
+ }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
/**
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import java.util.HashSet;
import java.util.List;
import java.util.Set;
<argument ref="dataBroker" />
</bean>
</service>
+ <bean id="topologyHandler" class="org.opendaylight.unimgr.mef.nrp.ovs.tapi.TopologyDataHandler" init-method="init" destroy-method="close">
+ <argument ref="dataBroker" />
+ </bean>
</blueprint>
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+
+import static org.junit.Assert.fail;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class DataStoreTestUtils {
+ private static final Logger LOG = LoggerFactory.getLogger(DataStoreTestUtils.class);
+
+ public static <T extends DataObject> T read(InstanceIdentifier instanceIdentifier, DataBroker dataBroker){
+ return read(instanceIdentifier,dataBroker,LogicalDatastoreType.OPERATIONAL);
+ }
+
+ public static <T extends DataObject> T readConfig(InstanceIdentifier instanceIdentifier, DataBroker dataBroker){
+ return read(instanceIdentifier,dataBroker,LogicalDatastoreType.CONFIGURATION);
+ }
+
+ public static <T extends DataObject> void write(T object, InstanceIdentifier<T> instanceIdentifier, DataBroker dataBroker){
+ ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
+ transaction.put(LogicalDatastoreType.OPERATIONAL,instanceIdentifier,object,true);
+
+ Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable Void result) {
+ LOG.debug("Object: {} created.",object.toString());
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.debug("Object: {} wasn't created due to a error: {}",object.toString(), t.getMessage());
+ fail("Object wasn't created due to a error: "+ t.getMessage());
+ }
+ });
+ }
+
+ public static void delete(InstanceIdentifier instanceIdentifier, DataBroker dataBroker){
+ ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
+
+ Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable Void result) {
+ LOG.debug("Object: {} deleted.",instanceIdentifier.toString());
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.debug("Object: {} wasn't deleted due to a error: {}",instanceIdentifier.toString(), t.getMessage());
+ fail("Object wasn't deleted due to a error: "+ t.getMessage());
+ }
+ });
+ }
+
+ private static <T extends DataObject> T read(InstanceIdentifier instanceIdentifier, DataBroker dataBroker, LogicalDatastoreType type){
+ ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
+ try {
+ Optional<T> opt = (Optional<T>) transaction.read(type,instanceIdentifier).checkedGet();
+ if (opt.isPresent()){
+ return opt.get();
+ } else {
+ fail("Could not find object");
+ }
+ } catch (Exception e) {
+ fail("Could not find object, "+e.getMessage());
+ }
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.*;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
+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.TopologyBuilder;
+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.Link;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.List;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class FlowTopologyTestUtils {
+ private static final TopologyId flowTopologyId = new TopologyId(new Uri("flow:1"));
+ private static final InstanceIdentifier<Topology> FLOW_TOPO_IID = InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(flowTopologyId));
+ private static final String prefix = "openflow:";
+
+ /**
+ * Creates flow topology with link nodes (Links between ovs).
+ */
+ public static void createFlowTopology(DataBroker dataBroker, List<Link> links){
+ TopologyBuilder topologyBuilder = new TopologyBuilder();
+ topologyBuilder.setTopologyId(flowTopologyId);
+ topologyBuilder.setLink(links);
+ Topology topology = topologyBuilder.build();
+ DataStoreTestUtils.write(topology,FLOW_TOPO_IID,dataBroker);
+ }
+
+ public static Link createLink(String sourceNode, Long sourcePort, String destNode, Long destPort){
+ LinkBuilder linkBuilder = new LinkBuilder();
+ String sourcePortName = prefix + sourceNode + ":" + sourcePort.toString();
+ String destPortName = prefix + destNode + ":" + destPort;
+
+ linkBuilder.setLinkId(new LinkId(sourcePortName));
+
+ SourceBuilder sourceBuilder = new SourceBuilder();
+ sourceBuilder.setSourceTp(new TpId(sourcePortName));
+ sourceBuilder.setSourceNode(new NodeId(prefix+sourceNode));
+ linkBuilder.setSource(sourceBuilder.build());
+
+ DestinationBuilder destinationBuilder = new DestinationBuilder();
+ destinationBuilder.setDestTp(new TpId(destPortName));
+ destinationBuilder.setDestNode(new NodeId(prefix+destNode));
+ linkBuilder.setDestination(destinationBuilder.build());
+
+ return linkBuilder.build();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.unimgr.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortNumberUni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class OpenFlowTopologyTestUtils {
+
+ public static void createOpenFlowNodes(List<Node> nodeList, DataBroker dataBroker){
+ NodesBuilder nodesBuilder = new NodesBuilder();
+ nodesBuilder.setNode(nodeList);
+ Nodes nodes = nodesBuilder.build();
+ InstanceIdentifier<Nodes> nodesIId = InstanceIdentifier.builder(Nodes.class).build();
+ DataStoreTestUtils.write(nodes,nodesIId,dataBroker);
+ }
+
+ public static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node createOpenFlowNode(String oFName, List<NodeConnector> nodeConnectorList){
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder();
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(oFName);
+ nodeBuilder.setId(nodeId);
+ nodeBuilder.setKey(new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(nodeId));
+ nodeBuilder.setNodeConnector(nodeConnectorList);
+ nodeBuilder.addAugmentation(FlowCapableNode.class,createFlowCapableNode());
+ return nodeBuilder.build();
+ }
+
+ public static NodeConnector createNodeConnector(String ofBridgeName, Long portNumber, String ovsdbPortName){
+ NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+ String ofPortName = ofBridgeName + ":" + portNumber.toString();
+ NodeConnectorId nodeConnectorId = new NodeConnectorId(ofPortName);
+ nodeConnectorBuilder.setId(nodeConnectorId);
+ nodeConnectorBuilder.setKey(new NodeConnectorKey(nodeConnectorId));
+ nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnector.class,createFlowCapableNodeConnector(ovsdbPortName,portNumber));
+ return nodeConnectorBuilder.build();
+ }
+
+ private static FlowCapableNodeConnector createFlowCapableNodeConnector(String ovsdbName, Long portNumber){
+ FlowCapableNodeConnectorBuilder flowCapableNodeConnectorBuilder = new FlowCapableNodeConnectorBuilder();
+ flowCapableNodeConnectorBuilder.setName(ovsdbName);
+ flowCapableNodeConnectorBuilder.setPortNumber(new PortNumberUni(portNumber));
+ return flowCapableNodeConnectorBuilder.build();
+ }
+
+ public static FlowCapableNode createFlowCapableNode(){
+ FlowCapableNodeBuilder flowCapableNodeBuilder = new FlowCapableNodeBuilder();
+
+ flowCapableNodeBuilder.setTable(createOfTable());
+ return flowCapableNodeBuilder.build();
+ }
+
+ private static List<Table> createOfTable(){
+ List<Table> tables = new ArrayList<>();
+ TableBuilder tableBuilder = new TableBuilder();
+ tableBuilder.setId(Short.valueOf("0"));
+ List<Flow> flows = new ArrayList<>();
+ tableBuilder.setFlow(flows);
+ tables.add(tableBuilder.build());
+ return tables;
+ }
+
+ public static InstanceIdentifier<NodeConnector> getNodeConnectorInstanceIdentifier(String ofBridgeName, String nodeConnectorId){
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(ofBridgeName)))
+ .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(nodeConnectorId)))
+ .build();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
+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.NodeId;
+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.TpId;
+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.TopologyBuilder;
+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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.List;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class OvsdbTopologyTestUtils {
+ private static final TopologyId ovsdbTopologyId = new TopologyId(new Uri("ovsdb:1"));
+ private static final InstanceIdentifier ovsdbTopology =
+ InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(ovsdbTopologyId));
+
+ /**
+ * Ovsdb topology initializator.
+ */
+ public static void createOvsdbTopology(DataBroker dataBroker){
+ TopologyBuilder topologyBuilder = new TopologyBuilder();
+ topologyBuilder.setTopologyId(ovsdbTopologyId);
+ Topology topology = topologyBuilder.build();
+ DataStoreTestUtils.write(topology,ovsdbTopology, dataBroker);
+ }
+
+ public static void writeBridge(Node node, DataBroker dataBroker){
+ InstanceIdentifier bridgeIid = getNodeInstanceIdentifier(node.getNodeId());
+ DataStoreTestUtils.write(node,bridgeIid,dataBroker);
+ }
+
+ public static Node createBridge(String nodeId, List<TerminationPoint> tps){
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.setNodeId(new NodeId(nodeId));
+ nodeBuilder.setTerminationPoint(tps);
+ nodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class,createOvsdbBridgeAugmentation(nodeId));
+ return nodeBuilder.build();
+ }
+
+ public static InstanceIdentifier getNodeInstanceIdentifier(NodeId nodeId){
+ return InstanceIdentifier
+ .builder(NetworkTopology.class)
+ .child(Topology.class,
+ new TopologyKey(ovsdbTopologyId))
+ .child(Node.class,
+ new NodeKey(nodeId))
+ .build();
+ }
+
+ public static InstanceIdentifier getPortInstanceIdentifier(String nodeName, String portName){
+ return getNodeInstanceIdentifier(new NodeId(nodeName))
+ .child(TerminationPoint.class,
+ new TerminationPointKey(new TpId(portName)));
+ }
+
+ private static OvsdbBridgeAugmentation createOvsdbBridgeAugmentation(String ovsdbBridgeName){
+ OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
+ ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(ovsdbBridgeName));
+ return ovsdbBridgeAugmentationBuilder.build();
+ }
+
+ public static TerminationPoint createTerminationPoint(String tpId, Long ofName) {
+ TerminationPointBuilder terminationPointBuilder = new TerminationPointBuilder();
+ terminationPointBuilder.setTpId(new TpId(tpId));
+ terminationPointBuilder.setKey(new TerminationPointKey(new TpId(tpId)));
+ terminationPointBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, createOvsdbTerminationPointAugmentation(ofName));
+ TerminationPoint terminationPoint = terminationPointBuilder.build();
+ return terminationPoint;
+ }
+
+ private static OvsdbTerminationPointAugmentation createOvsdbTerminationPointAugmentation(Long ofPort) {
+ OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
+ ovsdbTerminationPointAugmentationBuilder.setOfport(ofPort);
+ return ovsdbTerminationPointAugmentationBuilder.build();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs.activator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.unimgr.mef.nrp.api.EndPoint;
+import org.opendaylight.unimgr.mef.nrp.common.ResourceNotAvailableException;
+import org.opendaylight.unimgr.mef.nrp.ovs.FlowTopologyTestUtils;
+import org.opendaylight.unimgr.mef.nrp.ovs.OpenFlowTopologyTestUtils;
+import org.opendaylight.unimgr.mef.nrp.ovs.OvsdbTopologyTestUtils;
+import org.opendaylight.unimgr.mef.nrp.ovs.util.OpenFlowUtils;
+import org.opendaylight.unimgr.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.nrm_connectivity.rev170227.PositiveInteger;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.nrm_connectivity.rev170227.cg.eth.frame.flow.cpa.aspec.CeVlanIdList;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.nrm_connectivity.rev170227.vlan.id.listing.VlanIdList;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.nrp_interface.rev170227.NrpCreateConnectivityServiceEndPointAttrs;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.nrp_interface.rev170227.nrp.create.connectivity.service.end.point.attrs.NrpCgEthFrameFlowCpaAspec;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.UniversalId;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapiconnectivity.rev170227.ConnectivityServiceEndPoint;
+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.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+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.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class OvsActivatorTest extends AbstractDataBrokerTest{
+
+ private DataBroker dataBroker;
+ private OvsActivator ovsActivator;
+ private static final String port1Name = "sip:ovs-node:s1:s1-eth1";
+ private static final String port2Name = "sip:ovs-node:s5:s5-eth1";
+ private static final String ofPort1Name = "openflow:1";
+ private static final String ofPort2Name = "openflow:5";
+ private static final Integer expectedVlanId = 200;
+ private static final String serviceId = "serviceId";
+
+ private static final String interswitchName = "interswitch-openflow";
+ private static final String vlanName = "vlan-openflow";
+ private static final String dropName = "default-DROP";
+
+ List<String> of1InterwitchPorts = Arrays.asList("openflow:1:3", "openflow:1:4", "openflow:1:5");
+ List<String> of2InterwitchPorts = Arrays.asList("openflow:5:3", "openflow:5:4");
+
+ @Before
+ public void setUp(){
+ //given
+ dataBroker = getDataBroker();
+ ovsActivator = new OvsActivator(dataBroker);
+ OvsdbTopologyTestUtils.createOvsdbTopology(dataBroker);
+ initTopologies();
+ FlowTopologyTestUtils.createFlowTopology(dataBroker, getLinkList());
+ }
+
+ @Test
+ public void testActivate(){
+ //given
+ List<EndPoint> endPoints = prepareEndpoints();
+
+ //when
+ try {
+ ovsActivator.activate(endPoints,serviceId);
+ } catch (ResourceNotAvailableException e) {
+ fail(e.getMessage());
+ } catch (TransactionCommitFailedException e) {
+ fail(e.getMessage());
+ }
+
+ //then
+ Nodes nodes = readOpenFLowTopology(dataBroker);
+ checkTable(nodes,activated);
+ System.out.println("Before deactivation: "+ nodes.toString());
+
+ //when
+ try {
+ ovsActivator.deactivate(endPoints, serviceId);
+ } catch (TransactionCommitFailedException e) {
+ fail(e.getMessage());
+ } catch (ResourceNotAvailableException e) {
+ fail(e.getMessage());
+ }
+ nodes = readOpenFLowTopology(dataBroker);
+ checkTable(nodes,deactivated);
+ System.out.println("After deactivation: "+ nodes.toString());
+ }
+
+ BiConsumer<Table,List<String>> activated = (table,interswitchPorts) -> {
+ List<Flow> flows = table.getFlow();
+ int interswitchPortCount = interswitchPorts.size();
+ //vlan & interwitch + 1 vlan + 1 drop
+ int flowCount = interswitchPortCount * 2 + 2;
+ assertEquals(flowCount,flows.size());
+ List<Flow> interswitchFlows = flows.stream()
+ .filter(flow -> flow.getId().getValue().contains(interswitchName))
+ .collect(Collectors.toList());
+ assertEquals(interswitchPortCount,interswitchFlows.size());
+
+ List<Flow> vlanFlows = flows.stream()
+ .filter(flow -> flow.getId().getValue().contains(vlanName))
+ .filter(flow -> flow.getMatch().getVlanMatch().getVlanId().getVlanId().getValue().equals(expectedVlanId))
+ .collect(Collectors.toList());
+ assertEquals(interswitchPortCount+1,vlanFlows.size());
+
+ assertTrue(flows.stream().anyMatch(flow -> flow.getId().getValue().equals(dropName)));
+ };
+
+ BiConsumer<Table,List<String>> deactivated = (table,interswitchPorts) -> {
+ List<Flow> flows = table.getFlow();
+ boolean hasVlanFlows = flows.stream()
+ .filter(flow -> flow.getId().getValue().contains(serviceId+"-"+vlanName))
+ .anyMatch(this::hasVlanMatch);
+ assertFalse(hasVlanFlows);
+ };
+
+ private boolean hasVlanMatch(Flow flow){
+ if(flow.getMatch().getVlanMatch().getVlanId().getVlanId().getValue().equals(expectedVlanId)){
+ return true;
+ }
+ return false;
+ }
+
+ private void checkTable(Nodes nodes, BiConsumer<Table,List<String>> checkTable){
+ nodes.getNode()
+ .forEach(node -> {
+ try {
+ Table t = OpenFlowUtils.getTable(node);
+ if(node.getKey().getId().getValue().equals(ofPort1Name)){
+ checkTable.accept(t,of1InterwitchPorts);
+ } else if(node.getKey().getId().getValue().equals(ofPort2Name)){
+ checkTable.accept(t,of2InterwitchPorts);
+ }
+ } catch (ResourceNotAvailableException e) {
+ fail(e.getMessage());
+ }
+ });
+ }
+
+ private List<EndPoint> prepareEndpoints(){
+ List<EndPoint> endPoints = new ArrayList<>();
+ endPoints.add(mockEndPoint(port1Name));
+ endPoints.add(mockEndPoint(port2Name));
+ return endPoints;
+ }
+
+ private EndPoint mockEndPoint(String portName){
+ ConnectivityServiceEndPoint connectivityServiceEndPoint = mock(ConnectivityServiceEndPoint.class);
+ NrpCreateConnectivityServiceEndPointAttrs attrs = mock(NrpCreateConnectivityServiceEndPointAttrs.class);
+ //UNI port mock
+ when(connectivityServiceEndPoint.getServiceInterfacePoint())
+ .thenReturn(new UniversalId(portName));
+
+ //Vlan Id mock
+ VlanIdList vlanIdList = mock(VlanIdList.class);
+ when(vlanIdList.getVlanId())
+ .thenReturn(PositiveInteger.getDefaultInstance(expectedVlanId.toString()));
+
+ List<VlanIdList> vlanIds = new ArrayList<>();
+ vlanIds.add(vlanIdList);
+
+ CeVlanIdList ceVlanIdList = mock(CeVlanIdList.class);
+ when(ceVlanIdList.getVlanIdList())
+ .thenReturn(vlanIds);
+
+ NrpCgEthFrameFlowCpaAspec nrpCgEthFrameFlowCpaAspec = mock(NrpCgEthFrameFlowCpaAspec.class);
+ when(nrpCgEthFrameFlowCpaAspec.getCeVlanIdList())
+ .thenReturn(ceVlanIdList);
+
+ when(attrs.getNrpCgEthFrameFlowCpaAspec())
+ .thenReturn(nrpCgEthFrameFlowCpaAspec);
+
+ return new EndPoint(connectivityServiceEndPoint,attrs);
+ }
+
+ /**
+ * Add 5 ovsdb bridges and suitable openflow nodes
+ */
+ private void initTopologies(){
+ List<Node> bridges = new ArrayList<>();
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> ofNodes = new ArrayList<>();
+ bridges.add(createBridge("s1",5));
+ bridges.add(createBridge("s2",2));
+ bridges.add(createBridge("s3",4));
+ bridges.add(createBridge("s4",3));
+ bridges.add(createBridge("s5",4));
+
+ bridges.forEach(node -> {
+ OvsdbTopologyTestUtils.writeBridge(node,dataBroker);
+ ofNodes.add(createOpenFlowNode(node));
+ });
+
+ OpenFlowTopologyTestUtils.createOpenFlowNodes(ofNodes,dataBroker);
+ }
+
+ private Node createBridge(String name, int portCount){
+ List<TerminationPoint> tps = new ArrayList<>();
+ IntStream.range(1,portCount+1)
+ .forEach(i -> tps.add(OvsdbTopologyTestUtils.createTerminationPoint(name+"-eth"+i,Long.valueOf(i))));
+ return OvsdbTopologyTestUtils.createBridge(name, tps);
+ }
+
+ private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node createOpenFlowNode(Node node){
+ String ovsdbName = node.getKey().getNodeId().getValue();
+ String ofBridgeName = getOfName(ovsdbName);
+
+ List<NodeConnector> nodeConnectors = new ArrayList<>();
+ node.getTerminationPoint()
+ .forEach(tp -> nodeConnectors.add(OpenFlowTopologyTestUtils.createNodeConnector(ofBridgeName, tp.getAugmentation(OvsdbTerminationPointAugmentation.class).getOfport(), ovsdbName+"-eth"+tp.getAugmentation(OvsdbTerminationPointAugmentation.class).getOfport())));
+
+ return OpenFlowTopologyTestUtils.createOpenFlowNode(ofBridgeName,nodeConnectors);
+ }
+
+ private String getOfName(String ovsdbName){
+ String bridgeNumber = ovsdbName.substring(1,ovsdbName.length());
+ return "openflow:"+bridgeNumber;
+ }
+
+ public static Nodes readOpenFLowTopology(DataBroker dataBroker){
+ InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
+ return (Nodes) MdsalUtils.read(dataBroker,LogicalDatastoreType.CONFIGURATION,instanceIdentifier);
+ }
+
+ /**
+ * @return List of links between ovswitches
+ */
+ private static List<Link> getLinkList(){
+ List<Link> linkList = new ArrayList<>();
+
+ //openflow nodes
+ String of1 = "1";
+ String of2 = "2";
+ String of3 = "3";
+ String of4 = "4";
+ String of5 = "5";
+ //ports
+ Long p1 = 1L;
+ Long p2 = 2L;
+ Long p3 = 3L;
+ Long p4 = 4L;
+ Long p5 = 5L;
+
+ //openflow:1
+ linkList.add(FlowTopologyTestUtils.createLink(of1,p3,of2,p1));
+ linkList.add(FlowTopologyTestUtils.createLink(of1,p5,of4,p1));
+ linkList.add(FlowTopologyTestUtils.createLink(of1,p4,of3,p1));
+ //openflow:2
+ linkList.add(FlowTopologyTestUtils.createLink(of2,p2,of3,p2));
+ linkList.add(FlowTopologyTestUtils.createLink(of2,p1,of1,p3));
+ //openflow:3
+ linkList.add(FlowTopologyTestUtils.createLink(of3,p4,of5,p3));
+ linkList.add(FlowTopologyTestUtils.createLink(of3,p1,of1,p4));
+ linkList.add(FlowTopologyTestUtils.createLink(of3,p3,of4,p2));
+ linkList.add(FlowTopologyTestUtils.createLink(of3,p2,of2,p2));
+ //openflow:4
+ linkList.add(FlowTopologyTestUtils.createLink(of4,p3,of5,p4));
+ linkList.add(FlowTopologyTestUtils.createLink(of4,p2,of3,p3));
+ linkList.add(FlowTopologyTestUtils.createLink(of4,p1,of1,p5));
+ //openflow:5
+ linkList.add(FlowTopologyTestUtils.createLink(of5,p3,of3,p4));
+ linkList.add(FlowTopologyTestUtils.createLink(of5,p4,of4,p3));
+
+ return linkList;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs.tapi;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.unimgr.mef.nrp.ovs.FlowTopologyTestUtils;
+import org.opendaylight.unimgr.mef.nrp.ovs.OvsdbTopologyTestUtils;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.UniversalId;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.BiFunction;
+
+import static junit.framework.TestCase.assertNotNull;
+import static org.junit.Assert.*;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class TopologyDataHandlerTest extends AbstractDataBrokerTest{
+
+ private TopologyDataHandler topologyDataHandler;
+ private DataBroker dataBroker;
+ private TopologyDataHandlerTestUtils helper;
+ private static final String ovs_nep_prefix = "ovs-node:";
+ private static final String sip_prefix = "sip:";
+ private static final String bridgeName = "br1";
+ private static final String expectedNep1 = "br1:br1-eth1";
+ private static final String expectedNep2 = "br1:br1-eth2";
+ private static String tp1Name = "br1-eth1";
+ private static int initialBridgePortCount = 3;
+
+ @Before
+ public void setUp(){
+ //given
+ dataBroker = getDataBroker();
+ helper = new TopologyDataHandlerTestUtils(dataBroker);
+
+ //helper.createOvsdbTopology();
+ OvsdbTopologyTestUtils.createOvsdbTopology(dataBroker);
+ helper.createOpenFlowNodes();
+ FlowTopologyTestUtils.createFlowTopology(dataBroker,getLinkList());
+ helper.createPrestoSystemTopology();
+
+ topologyDataHandler = new TopologyDataHandler(dataBroker);
+ topologyDataHandler.init();
+ }
+
+ @Test
+ public void testBridgeAddition(){
+ //when
+ helper.createTestBridge();
+
+ //then
+ Node ovsNode = helper.readOvsNode();
+ assertNotNull(ovsNode);
+ checkNeps(ovsNode,expectedNep1,expectedNep2);
+ checkSips(helper.readSips(),expectedNep1,expectedNep2);
+ }
+
+ @Test
+ public void testPortAddition(){
+ //given
+ String newPortName = "br1-eth4";
+ Long ofPortNumber = 4L;
+ helper.createTestBridge();
+ Node ovsNode = helper.readOvsNode();
+ assertEquals(initialBridgePortCount,ovsNode.getOwnedNodeEdgePoint().size());
+
+ //when
+ helper.addPort(bridgeName,newPortName,ofPortNumber);
+
+ //then
+ ovsNode = helper.readOvsNode();
+ assertEquals(initialBridgePortCount+1,ovsNode.getOwnedNodeEdgePoint().size());
+ checkNeps(ovsNode,"br1:"+newPortName,expectedNep1,expectedNep2);
+ checkSips(helper.readSips(),"br1:"+newPortName,expectedNep1,expectedNep2);
+ }
+
+ @Test
+ public void testBridgeRemoval(){
+ //given
+ helper.createTestBridge();
+ Node ovsNode = helper.readOvsNode();
+ assertEquals(initialBridgePortCount,ovsNode.getOwnedNodeEdgePoint().size());
+
+ //when
+ helper.deleteTestBridge();
+
+ //then
+ ovsNode = helper.readOvsNode();
+ assertEquals(0,ovsNode.getOwnedNodeEdgePoint().size());
+ }
+
+ @Test
+ public void testPortRemoval(){
+ //given
+ String fullPortNameToRemove = bridgeName+tp1Name;
+ //helper.createTestBridge();
+ helper.createTestBridge();
+ Node ovsNode = helper.readOvsNode();
+ assertEquals(initialBridgePortCount,ovsNode.getOwnedNodeEdgePoint().size());
+
+ //when
+ helper.deletePort(tp1Name);
+
+ //then
+ ovsNode = helper.readOvsNode();
+ assertEquals(initialBridgePortCount-1,ovsNode.getOwnedNodeEdgePoint().size());
+ assertFalse(checkNep.apply(ovsNode,fullPortNameToRemove));
+ assertFalse(checkSip.apply(helper.readSips(), fullPortNameToRemove));
+ }
+
+ private BiFunction<Node, String, Boolean> checkNep = (node,nepName) ->
+ node.getOwnedNodeEdgePoint().stream()
+ .anyMatch(ownedNep -> ownedNep.getMappedServiceInterfacePoint().contains(new UniversalId(sip_prefix + ovs_nep_prefix + nepName))
+ && ownedNep.getUuid().getValue().equals(ovs_nep_prefix + nepName)
+ );
+
+ private void checkNeps(Node node,String ... neps){
+ Arrays.stream(neps)
+ .forEach(nep -> assertTrue(checkNep.apply(node,nep)));
+ }
+
+ private BiFunction<List<org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.context.attrs.ServiceInterfacePoint>, String, Boolean> checkSip =
+ (sips, nep) -> sips.stream()
+ .anyMatch(sip -> sip.getUuid().getValue().equals(sip_prefix + ovs_nep_prefix + nep));
+
+ private void checkSips(List<org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.context.attrs.ServiceInterfacePoint> sips, String ... neps){
+ Arrays.stream(neps)
+ .forEach(nep -> assertTrue(checkSip.apply(sips,nep)));
+ }
+
+ private List<Link> getLinkList(){
+ List<Link> linkList = new ArrayList<>();
+
+ //For testing purposes only - can't be find anywhere else in DataStore
+ String of1NodeName = "1";
+ String of2NodeName = "2";
+ Long of2PortNumber = 1L;
+ Long of1PortNumber = 3L;
+
+ //openflow:1:3 -> <- openflow:2:1
+ linkList.add(FlowTopologyTestUtils.createLink(of1NodeName,of1PortNumber,of2NodeName,of2PortNumber));
+ linkList.add(FlowTopologyTestUtils.createLink(of2NodeName,of2PortNumber,of1NodeName,of1PortNumber));
+
+ return linkList;
+ }
+
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Cisco Systems Inc and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.unimgr.mef.nrp.ovs.tapi;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.unimgr.mef.nrp.impl.NrpInitializer;
+import org.opendaylight.unimgr.mef.nrp.ovs.DataStoreTestUtils;
+import org.opendaylight.unimgr.mef.nrp.ovs.OpenFlowTopologyTestUtils;
+import org.opendaylight.unimgr.mef.nrp.ovs.OvsdbTopologyTestUtils;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.Context;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.UniversalId;
+import org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.Context1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortNumberUni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.junit.Assert.fail;
+
+/**
+ * @author marek.ryznar@amartus.com
+ */
+public class TopologyDataHandlerTestUtils {
+ private static String bridgeName = "br1";
+ private static String ofBridgeName = "openflow:1";
+ private static String tp1Name = "br1-eth1";
+ private static String tp2Name = "br1-eth2";
+ private static String tp3Name = "br1-eth3";
+ private static Long tp1OFport = 1L;
+ private static Long tp2OFport = 2L;
+ private static Long tp3OFport = 3L;
+
+ private static final String prestoNrpTopoId = "mef:presto-nrp-topology-system";
+ private static final String ovsNodeId = "ovs-node";
+
+ private final DataBroker dataBroker;
+
+ protected TopologyDataHandlerTestUtils(DataBroker dataBroker){
+ this.dataBroker = dataBroker;
+ }
+
+ /**
+ * Creates ovsdb bridge "br1" with 3 ports:
+ * 1. tp1 - nep
+ * 2. tp2 - nep
+ * 3. tp3 - not nep, becouse it is connected to other switch
+ */
+ public void createTestBridge(){
+ List<TerminationPoint> tps = new LinkedList<>();
+
+ tps.add(OvsdbTopologyTestUtils.createTerminationPoint(tp1Name,tp1OFport));
+ tps.add(OvsdbTopologyTestUtils.createTerminationPoint(tp2Name,tp2OFport));
+ tps.add(OvsdbTopologyTestUtils.createTerminationPoint(tp3Name,tp3OFport));
+
+ org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node node = OvsdbTopologyTestUtils.createBridge(bridgeName,tps);
+ InstanceIdentifier instanceIdentifier = OvsdbTopologyTestUtils.getNodeInstanceIdentifier(node.getNodeId());
+ DataStoreTestUtils.write(node,instanceIdentifier,dataBroker);
+ }
+
+ protected void deleteTestBridge(){
+ InstanceIdentifier instanceIdentifier = OvsdbTopologyTestUtils.getNodeInstanceIdentifier(new NodeId(bridgeName));
+ DataStoreTestUtils.delete(instanceIdentifier,dataBroker);
+ }
+
+ protected void deletePort(String port){
+ InstanceIdentifier<TerminationPoint> tpIid = OvsdbTopologyTestUtils.getPortInstanceIdentifier(bridgeName,port);
+ DataStoreTestUtils.delete(tpIid,dataBroker);
+ }
+
+ protected void addPort(String bridgeName, String portName, Long ofNumber){
+ String bridgeId = bridgeName;
+ //openflow init
+ NodeConnector nodeConnector = OpenFlowTopologyTestUtils.createNodeConnector(ofBridgeName,ofNumber,portName);
+ InstanceIdentifier<NodeConnector> nodeConnectorInstanceIdentifier =
+ OpenFlowTopologyTestUtils.getNodeConnectorInstanceIdentifier(ofBridgeName,ofBridgeName+":"+ofNumber.toString());
+ DataStoreTestUtils.write(nodeConnector,nodeConnectorInstanceIdentifier,dataBroker);
+ //ovsdb init
+ TerminationPoint terminationPoint = OvsdbTopologyTestUtils.createTerminationPoint(portName,ofNumber);
+ InstanceIdentifier<TerminationPoint> tpIid = OvsdbTopologyTestUtils.getPortInstanceIdentifier(bridgeId,portName);
+ DataStoreTestUtils.write(terminationPoint,tpIid,dataBroker);
+ }
+
+ /**
+ * Creates OpenFlow Nodes with one Node ("openflow:1" openflow equivalent of ovsdb's "br1"), which consist of 3 NodeConnectors:
+ * 1. id:"openflow:1:1", name: "br1-eth1", portNumber: "1"
+ * 2. id:"openflow:1:2", name: "br1-eth2", portNumber: "2"
+ * 3. id:"openflow:1:3", name: "br1-eth3", portNumber: "3"
+ */
+ protected void createOpenFlowNodes(){
+ NodesBuilder nodesBuilder = new NodesBuilder();
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeList = new ArrayList<>();
+ nodeList.add(createOpenFlowNode(ofBridgeName));
+ nodesBuilder.setNode(nodeList);
+ Nodes nodes = nodesBuilder.build();
+ InstanceIdentifier<Nodes> nodesIId = InstanceIdentifier.builder(Nodes.class).build();
+
+ ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
+ transaction.put(LogicalDatastoreType.OPERATIONAL,nodesIId,nodes);
+ transaction.submit();
+ }
+
+ private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node createOpenFlowNode(String oFName){
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder nodeBuilder =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder();
+ org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(oFName);
+ nodeBuilder.setId(nodeId);
+ nodeBuilder.setKey(new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(nodeId));
+ List<NodeConnector> nodeConnectorList = new ArrayList<>();
+ nodeConnectorList.add(createNodeConnector(oFName,tp1OFport,tp1Name));
+ nodeConnectorList.add(createNodeConnector(oFName,tp2OFport,tp2Name));
+ nodeConnectorList.add(createNodeConnector(oFName,tp3OFport,tp3Name));
+ nodeBuilder.setNodeConnector(nodeConnectorList);
+ return nodeBuilder.build();
+ }
+
+ private NodeConnector createNodeConnector(String ofBridgeName, Long portNumber, String ovsdbPortName){
+ NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+ String ofPortName = ofBridgeName + ":" + portNumber.toString();
+ NodeConnectorId nodeConnectorId = new NodeConnectorId(ofPortName);
+ nodeConnectorBuilder.setId(nodeConnectorId);
+ nodeConnectorBuilder.setKey(new NodeConnectorKey(nodeConnectorId));
+ nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnector.class,createFlowCapableNodeConnector(ovsdbPortName,portNumber));
+ return nodeConnectorBuilder.build();
+ }
+
+ private FlowCapableNodeConnector createFlowCapableNodeConnector(String ovsdbName, Long portNumber){
+ FlowCapableNodeConnectorBuilder flowCapableNodeConnectorBuilder = new FlowCapableNodeConnectorBuilder();
+ flowCapableNodeConnectorBuilder.setName(ovsdbName);
+ flowCapableNodeConnectorBuilder.setPortNumber(new PortNumberUni(portNumber));
+ return flowCapableNodeConnectorBuilder.build();
+ }
+
+ protected void createPrestoSystemTopology(){
+ NrpInitializer nrpInitializer = new NrpInitializer(dataBroker);
+ try {
+ nrpInitializer.init();
+ } catch (Exception e) {
+ fail("Could not initialize NRP topology.");
+ }
+ }
+
+ protected org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.topology.Node readOvsNode(){
+ return DataStoreTestUtils.read(getNodeIid(),dataBroker);
+ }
+
+ protected List<org.opendaylight.yang.gen.v1.urn.mef.yang.tapicommon.rev170227.context.attrs.ServiceInterfacePoint> readSips(){
+ ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
+ try {
+ Optional<Context> opt = readWriteTransaction.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Context.class)).checkedGet();
+ if(opt.isPresent()){
+ return opt.get().getServiceInterfacePoint();
+ } else {
+ fail("There are no sips.");
+ }
+ } catch (ReadFailedException e) {
+ fail(e.getMessage());
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier getNodeIid(){
+ return getTopoIid()
+ .child(org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.topology.Node.class,
+ new org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.topology.NodeKey(new UniversalId(ovsNodeId)));
+ }
+
+ private static InstanceIdentifier getTopoIid(){
+ return InstanceIdentifier.create(Context.class)
+ .augmentation(Context1.class)
+ .child(org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.topology.context.Topology.class,
+ new org.opendaylight.yang.gen.v1.urn.mef.yang.tapitopology.rev170227.topology.context.TopologyKey(new UniversalId(prestoNrpTopoId)));
+ }
+}
\ No newline at end of file