/* * Copyright (c) 2016 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.sxp.csit.libraries; import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.sxp.core.Configuration; import org.opendaylight.sxp.core.SxpNode; import org.opendaylight.sxp.core.service.BindingDispatcher; import org.opendaylight.sxp.csit.LibraryServer; import org.opendaylight.sxp.util.database.MasterDatabaseImpl; import org.opendaylight.sxp.util.database.SxpDatabaseImpl; import org.opendaylight.sxp.util.inet.Search; import org.opendaylight.sxp.util.time.TimeConv; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.SxpBindingFields; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBinding; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.peer.sequence.fields.PeerSequenceBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.sxp.database.fields.binding.database.binding.sources.binding.source.sxp.database.bindings.SxpDatabaseBinding; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentityBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.node.fields.SecurityBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.node.identity.fields.TimersBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.ConnectionMode; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.Version; import org.robotframework.javalib.annotation.ArgumentNames; import org.robotframework.javalib.annotation.RobotKeyword; import org.robotframework.javalib.annotation.RobotKeywords; import org.robotframework.remoteserver.RemoteServer; /** * Robot library used for Bindings export/forwarding measuring */ @RobotKeywords public class ExportTestLibrary extends AbstractLibrary { public final static String DESTINATION = "destination"; private final AtomicLong bindingsReceived = new AtomicLong(0), exportTimeEnd = new AtomicLong(0); private long exportTimeBegin, totalOfBindings; /** * @param libraryServer Server where Library will be added */ public ExportTestLibrary(RemoteServer libraryServer) { super(libraryServer); } /** * @return Amount of bindings that were processed */ @RobotKeyword("Get Bindings Exchange Count") @ArgumentNames({}) public synchronized long getBindingsExchangeCount() { return bindingsReceived.get(); } /** * @return Time elapsed while exporting all bindings or 0 if exports is still in progress */ @RobotKeyword("Get Export Time") @ArgumentNames({}) public synchronized double getExportTime() { long time = exportTimeEnd.get(); return time == 0 ? 1 : (time - exportTimeBegin) / 1000f; } /** * @return If all bindings were exported */ @RobotKeyword("All Exported") @ArgumentNames({}) public synchronized boolean allExported() { return totalOfBindings <= bindingsReceived.get(); } /** * @param amount Amount of bindings that will be exported between nodes */ @RobotKeyword("Set Export Amount") @ArgumentNames({"amount"}) public synchronized void setExportAmount( String amount) { totalOfBindings = (long) Double.parseDouble(amount); } /** * Adds Node that is used as Destination of bindings export * * @param nodeId Id of SxpNode * @param version Default version used * @param port Port of SxpNode * @param password Password used by TCP-MD5 */ @RobotKeyword("Add Destination Node") @ArgumentNames({"node_id", "version", "port", "password"}) public synchronized void addDestinationNode(String nodeId, String version, String port, String password) { LibraryServer.putNode(SxpNode.createInstance(new NodeId(nodeId), new SxpNodeIdentityBuilder().setSourceIp(new IpAddress(nodeId.toCharArray())) .setCapabilities(Configuration.getCapabilities(getVersion(version))) .setEnabled(true) .setName(DESTINATION) .setVersion(getVersion(version)) .setTcpPort(new PortNumber(Integer.parseInt(port))) .setSecurity(new SecurityBuilder().setPassword( password == null || password.isEmpty() ? null : password).build()) .setTimers(new TimersBuilder().setRetryOpenTime(5).build()) .build(), new MasterDatabaseImpl(), new SxpDatabaseImpl() { @Override public synchronized <T extends SxpBindingFields> List<SxpDatabaseBinding> deleteBindings( NodeId nodeId, List<T> bindings) { if (bindingsReceived.addAndGet(-bindings.size()) == totalOfBindings) { exportTimeEnd.set(System.currentTimeMillis()); } return Collections.emptyList(); } @Override public synchronized <T extends SxpBindingFields> List<SxpDatabaseBinding> addBinding(NodeId nodeId, List<T> bindings) { if (bindingsReceived.addAndGet(bindings.size()) == totalOfBindings) { exportTimeEnd.set(System.currentTimeMillis()); } return Collections.emptyList(); } })); } /** * Expand and exports bindings fromSource nodes to Destination nodes and start measuring forwarding speed * * @param prefix IpPrefix of binding that will be expanded and send * @param sgt Sgt of binding */ @RobotKeyword("Initiate Export") @ArgumentNames({"prefix", "sgt"}) public synchronized void initiateExport( String prefix, String sgt) { final List<MasterDatabaseBinding> exportBindings = Search.expandBinding(new MasterDatabaseBindingBuilder().setPeerSequence( new PeerSequenceBuilder().setPeer(new ArrayList<>()).build()) .setIpPrefix(new IpPrefix(Preconditions.checkNotNull(prefix).toCharArray())) .setTimestamp(TimeConv.toDt(System.currentTimeMillis())) .setSecurityGroupTag(new Sgt(Integer.parseInt(Preconditions.checkNotNull(sgt)))) .build(), Integer.MAX_VALUE); totalOfBindings = totalOfBindings == 0 ? getDestinationNodes() * exportBindings.size() : getDestinationNodes() * totalOfBindings; LibraryServer.getNodes().stream().filter(node -> node != null && SOURCE.equals(node.getName())).forEach(n -> { new BindingDispatcher(n).propagateUpdate(Collections.emptyList(), exportBindings, n.getAllConnections()); }); exportTimeBegin = System.currentTimeMillis(); } /** * Connects Destination Nodes to tested nodes and start measuring export speed * * @param address Address of tested Node */ @RobotKeyword("Initiate Simple Export") @ArgumentNames({"address"}) public synchronized void initiateSimpleExport( String address) { totalOfBindings = getDestinationNodes() * totalOfBindings; LibraryServer.getNodes() .stream() .parallel() .filter(node -> node != null && DESTINATION.equals(node.getName())) .forEach( node -> addConnection(node, Version.Version4, ConnectionMode.Listener, address, "64999", null)); exportTimeBegin = System.currentTimeMillis(); } /** * @return Sum of SxpNodes marked as Destination Nodes */ private int getDestinationNodes() { return LibraryServer.getNodes() .stream() .parallel() .filter(node -> node != null && DESTINATION.equals(node.getName())) .map(n -> 1) .reduce(0, Integer::sum); } @Override public synchronized void close() { bindingsReceived.set(0); exportTimeEnd.set(0); exportTimeBegin = 0; totalOfBindings = 0; } }