Commit f7053183 authored by NILANJAN DAW's avatar NILANJAN DAW

Added DPDK and java impl: lsmtree based metadata service

parent 7b6d2857
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
# Default ignored files
/shelf/
/workspace.xml
HpdosClient
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="14" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="true" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/local/Cellar/gradle/6.8.3/libexec" />
<option name="gradleJvm" value="14" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="true" project-jdk-name="14" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/hpdos_client.iml" filepath="$PROJECT_DIR$/.idea/hpdos_client.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>
\ No newline at end of file
app.name="HPDOS-Client"
app.version="0.1.4"
app.thread_count=12
app.runtime=5
app.cycle_create=1
app.cycle_read=4
app.cycle_update=3
app.cycle_delete=0
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/6.8.3/userguide/building_java_projects.html
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id "com.google.protobuf" version "0.8.15"
id "java"
}
repositories {
// Use JCenter for resolving dependencies.
jcenter()
mavenCentral()
}
dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13'
// This dependency is used by the application.
implementation 'com.google.guava:guava:29.0-jre'
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.15.6'
implementation 'io.grpc:grpc-netty-shaded:1.36.0'
implementation 'io.grpc:grpc-protobuf:1.36.0'
implementation 'io.grpc:grpc-stub:1.36.0'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+
}
application {
// Define the main class for the application.
mainClass = 'HpdosClient.ClientRunner'
}
sourceSets {
src {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.15.6'
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.36.0"
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package HpdosClient;
import HpdosClient.MessageFormat.MessageConstants;
import HpdosClient.MessageFormat.RequestBuilder;
import com.google.common.base.Stopwatch;
import hpdos.grpc.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.*;
public class ClientRunner {
public static int parallelCount = 10;
public static int runtime = 0;
private final String clientID;
public static String propertiesFile;
private int cCreate, cRead, cUpdate, cDelete;
public boolean experimentEnded = false;
private List<Follower> replicaSet;
private Queue<Long> createTime, updateTime, readTime, deleteTime;
public ClientRunner() {
clientID = UUID.randomUUID().toString();
Properties properties = new Properties();
try {
InputStream inputStream = new FileInputStream(propertiesFile);
properties.load(inputStream);
parallelCount = Integer.parseInt((String) properties.get("app.thread_count"));
runtime = Integer.parseInt((String) properties.get("app.runtime"));
cCreate = Integer.parseInt((String) properties.get("app.cycle_create"));
cRead = Integer.parseInt((String) properties.get("app.cycle_read"));
cUpdate = Integer.parseInt((String) properties.get("app.cycle_update"));
cDelete = Integer.parseInt((String) properties.get("app.cycle_delete"));
createTime = new ConcurrentLinkedQueue<>();
updateTime = new ConcurrentLinkedQueue<>();
readTime = new ConcurrentLinkedQueue<>();
deleteTime = new ConcurrentLinkedQueue<>();
} catch (IOException e) {
e.printStackTrace();
}
}
public String getGreeting() {
return "Hello World!";
}
// create a metadata block
public long create(NetworkServiceGrpc.NetworkServiceBlockingStub stub, String key, String value) {
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_CREATE,
0, value.length(), key,
0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, value));
Packet packet = RequestBuilder.buildPacket(request);
long timestampCreateStart = System.currentTimeMillis();
Packet response = stub.createMetadata(packet);
return timestampCreateStart;
}
// read back the metadata
public Map.Entry<Packet, Long> read(ArrayList<ManagedChannel> channels, String key) {
int rnd = new Random().nextInt(channels.size());
NetworkServiceGrpc.NetworkServiceBlockingStub stub = NetworkServiceGrpc.newBlockingStub(channels.get(rnd));
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_READ,
0, 0, key, 0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, ""));
Packet packet = RequestBuilder.buildPacket(request);
long timestampReadStart = System.currentTimeMillis();
Packet response = stub.readMetadata(packet);
// System.out.println(response);
return new AbstractMap.SimpleEntry<>(response, timestampReadStart);
}
public long update(NetworkServiceGrpc.NetworkServiceBlockingStub stub, String key, String value, int version) {
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_UPDATE,
version, value.length(), key,
0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, value));
Packet packet = RequestBuilder.buildPacket(request);
long timestampCreateStart = System.currentTimeMillis();
Packet response = stub.updateMetadata(packet);
return timestampCreateStart;
}
public long delete(NetworkServiceGrpc.NetworkServiceBlockingStub stub, String key, int version) {
ArrayList<Request> request = new ArrayList<>();
request.add(RequestBuilder.buildRequest(MessageConstants.METADATA_DELETE,
version, 0, key,
0, MessageConstants.METADATA_ACCESS_PRIVATE, this.clientID, ""));
Packet packet = RequestBuilder.buildPacket(request);
long timestampCreateStart = System.currentTimeMillis();
Packet response = stub.deleteMetadata(packet);
return timestampCreateStart;
}
public double runExperiment(String id, long experimentStartTime) {
final ManagedChannel masterChannel = ManagedChannelBuilder.
forAddress(ConfigConstants.HOST, ConfigConstants.PORT)
.usePlaintext()
.build();
ArrayList<ManagedChannel> channels = new ArrayList<>();
channels.add(masterChannel);
for (Follower follower: replicaSet) {
ManagedChannel channel = ManagedChannelBuilder.
forAddress(follower.getIp(), follower.getPort())
.usePlaintext()
.build();
channels.add(channel);
}
for (;;) {
String key = id + (int) (Math.random() * Integer.MAX_VALUE),
value = "dummy",
updatedValue = "dummyUpdated";
NetworkServiceGrpc.NetworkServiceBlockingStub stub = NetworkServiceGrpc.newBlockingStub(masterChannel);
for (int j = 0; j < cCreate; j++) {
long timestampCreateStart = create(stub, key, value);
createTime.add(System.currentTimeMillis() - timestampCreateStart);
}
for (int j = 0; j < cRead; j++) {
AbstractMap.Entry<Packet, Long> data = read(channels, key);
readTime.add(System.currentTimeMillis() - data.getValue());
}
for (int j = 0; j < cUpdate; j++) {
AbstractMap.Entry<Packet, Long> data = read(channels, key);
long timestampUpdateStart = update(stub, key, updatedValue,
data.getKey().getResponse(0).getAck().getVersion());
readTime.add(System.currentTimeMillis() - data.getValue());
updateTime.add(System.currentTimeMillis() - timestampUpdateStart);
}
for (int j = 0; j < cDelete; j++) {
AbstractMap.Entry<Packet, Long> data = read(channels, key);
long timestampDeleteStart = delete(stub, key, data.getKey().getResponse(0).getAck().getVersion());
readTime.add(System.currentTimeMillis() - data.getValue());
deleteTime.add(System.currentTimeMillis() - timestampDeleteStart);
}
long currentTime = System.currentTimeMillis();
if ((currentTime - experimentStartTime) >= runtime * 1000L)
break;
}
// System.out.println(id + "runtime " + (System.currentTimeMillis() - startTime) +
// "ms qps " + qps);
masterChannel.shutdown();
return 0;
}
public void retrieveFollowerList() {
final ManagedChannel channel = ManagedChannelBuilder.
forAddress(ConfigConstants.HOST, ConfigConstants.PORT)
.usePlaintext()
.build();
NetworkServiceGrpc.NetworkServiceBlockingStub stub = NetworkServiceGrpc.newBlockingStub(channel);
ResponseList responseList = stub.getReadReplicaList(null);
this.replicaSet = responseList.getFollowerList();
for (Follower follower: this.replicaSet) {
System.out.println(follower);
}
channel.shutdown();
}
private void timerService() {
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (experimentEnded) {
timer.cancel();
timer.purge();
}
System.out.println("Experiment ran: " + stopwatch);
}
}, 5000, 5000);
}
private void printStatistics(double totalRuntime) {
long readQps = 0, createQps = 0, updateQps = 0, deleteQps = 0;
double avgRead = 0, avgCreate = 0, avgUpdate = 0, avgDelete = 0;
for (Long time: this.readTime) {
readQps++;
avgRead += time;
}
avgRead /= readQps * 1.0;
for (Long time: this.createTime) {
createQps++;
avgCreate += time;
}
avgCreate /= createQps * 1.0;
for (Long time: this.updateTime) {
updateQps++;
avgUpdate += time;
}
avgUpdate /= updateQps * 1.0;
for (Long time: this.deleteTime) {
deleteQps++;
avgDelete += time;
}
avgDelete /= deleteQps * 1.0;
double totalQps = readQps + createQps + updateQps + deleteQps;
System.out.println("Total runtime: " + totalRuntime);
System.out.println("Read: " + readQps + " Create: " + createQps
+ " Update: " + updateQps + " Delete: " + deleteQps + " Total: " + totalQps);
totalRuntime /= 1000;
//System.out.println("Total QPS: " + totalQps / totalRuntime + " avg query time: " + (totalQps * parallelCount / (totalRuntime)));
System.out.println("Total QPS: " + totalQps / totalRuntime + " avg query time: " +
((avgRead + avgCreate + avgUpdate + avgDelete) / 4));
System.out.println("Read QPS: " + readQps / totalRuntime + " avg query time: " + avgRead);
System.out.println("Create QPS: " + createQps / totalRuntime + " avg query time: " + avgCreate);
System.out.println("Update QPS: " + updateQps / totalRuntime + " avg query time: " + avgUpdate);
System.out.println("Delete QPS: " + deleteQps / totalRuntime + " avg query time: " + avgDelete);
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
propertiesFile = args[0];
ClientRunner clientRunner = new ClientRunner();
System.out.println(clientRunner.getGreeting());
System.out.println("Thread count: " + parallelCount + " runtime: " + runtime + "s");
ExecutorService executorService = Executors.newFixedThreadPool(parallelCount);
Thread.sleep(1000); // let things settle down a bit
clientRunner.retrieveFollowerList();
Set<Callable<Double>> callables = new HashSet<>();
final long startTime = System.currentTimeMillis();
for (int i = 0; i < parallelCount; i++) {
int finalI = i;
callables.add(() -> clientRunner.runExperiment(Integer.toString(finalI), startTime));
}
clientRunner.timerService();
List<Future<Double>> futures = executorService.invokeAll(callables);
for (Future<Double> future: futures) {
future.get();
}
clientRunner.experimentEnded = true;
long endTime = System.currentTimeMillis();
double totalRuntime = endTime - startTime;
clientRunner.printStatistics(totalRuntime);
executorService.shutdown();
executorService.awaitTermination(2, TimeUnit.SECONDS);
}
}
package HpdosClient;
public class ConfigConstants {
public static final String HOST = "localhost";
public static final int PORT = 8080;
public static final String URL = HOST + ":" + PORT;
}
package HpdosClient.MessageFormat;
public class MessageConstants {
public static final int INIT_VERSION = 0;
public static final int INVALID_VERSION = -1;
public static final int METADATA_ACCESS_PRIVATE = 700;
public static final int METADATA_ACCESS_SHARED = 777;
// 00 to 99 - Client Server Interaction operations
public static final int PACKET_METADATA_REQUEST = 0;
public static final int PACKET_METADATA_RESPONSE = 1;
// Distinguishing ACK and NACK packets
public static final int STATUS_OK = 200;
public static final int STATUS_OWNER_MISMATCH = 401;
public static final int STATUS_REPLICATE_FAILED = 402;
public static final int STATUS_SERVER_NOT_MASTER = 403;
public static final int STATUS_KEY_NOT_FOUND = 404;
// 100 to 199 - HPDOS System internal operations
public static final int MASTER_HEARTBEAT = 100;
public static final int METADATA_CREATE = 101;
public static final int METADATA_READ = 102;
public static final int METADATA_UPDATE = 103;
public static final int METADATA_DELETE = 104;
}
package HpdosClient.MessageFormat;
import hpdos.grpc.Packet;
import hpdos.grpc.Request;
import java.util.ArrayList;
public class RequestBuilder {
public static Request buildRequest(int operationType, int version,
int dataSize, String key, int crc,
int accessType, String clientID, String value) {
Request.Builder request = Request.newBuilder();
request.setOperationType(operationType);
request.setVersion(version);
request.setDataSize(dataSize);
request.setKey(key);
request.setCrc(crc);
request.setAccessType(accessType);
request.setClientID(clientID);
request.setValue(value);
return request.build();
}
public static Packet buildPacket(ArrayList<Request> requests) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
packet.addAllRequest(requests);
return packet.build();
}
}
package HpdosClient.MessageFormat;
import hpdos.grpc.*;
import java.util.ArrayList;
public class ResponseBuilder {
public static Ack buildAck(int version, int dataSize, String key, long crc, String value) {
Ack.Builder ack = Ack.newBuilder();
ack.setKey(key);
ack.setVersion(version);
ack.setDataSize(dataSize);
ack.setCrc(crc);
ack.setValue(value);
return ack.build();
}
public static Nack buildNack(int version, String key) {
Nack.Builder nack = Nack.newBuilder();
nack.setKey(key);
nack.setVersion(version);
return nack.build();
}
public static Response buildResponsePacket(int operationType, int status,
Ack ack,
Nack nack) {
Response.Builder response = Response.newBuilder();
response.setOperationType(operationType);
response.setStatus(status);
if (ack != null)
response.setAck(ack);
else
response.clearAck();
if (nack != null)
response.setNack(nack);
else
response.clearNack();
return response.build();
}
public static Packet buildPacket(ArrayList<Response> responses) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addAllResponse(responses);
return packet.build();
}
public static Packet buildPacket(Response response) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addResponse(response);
return packet.build();
}
}
syntax = "proto3";
package hpdos.grpc;
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "PacketFormatProto";
service NetworkService {
/**
Receive Packet from client
*/
rpc readMetadata(Packet) returns (Packet) {}
rpc createMetadata(Packet) returns (Packet) {}
rpc updateMetadata(Packet) returns (Packet) {}
rpc deleteMetadata(Packet) returns (Packet) {}
rpc getReadReplicaList(RequestList) returns (ResponseList) {}
}
message Packet {
int32 packetType = 1;
repeated Request request = 2;
repeated Response response = 3;
}
message Request {
int32 operationType = 1;
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
int32 accessType = 6;
string clientID = 7;
string value = 8;
}
message Response {
int32 operationType = 1;
int32 status = 2;
Ack ack = 3;
Nack nack = 4;
}
message Ack {
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
string value = 6;
}
message Nack {
string key = 2;
int32 version = 3;
}
message RequestList {}
message ResponseList {
int32 operationType = 1;
int32 status = 2;
repeated Follower follower = 3;
}
message Follower {
string ip = 1;
int32 port = 2;
string followerID = 3;
int64 lastSeen = 4;
}
\ No newline at end of file
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package HpdosClient;
import org.junit.Test;
import static org.junit.Assert.*;
public class AppTest {
@Test public void testAppHasAGreeting() {
ClientRunner classUnderTest = new ClientRunner();
assertNotNull("app should have a greeting", classUnderTest.getGreeting());
}
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/6.8.3/userguide/multi_project_builds.html
*/
rootProject.name = 'HpdosClient'
include('app')
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="14" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="true" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/local/Cellar/gradle/6.8.3/libexec" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="true" project-jdk-name="14" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/hpdos_server.iml" filepath="$PROJECT_DIR$/.idea/hpdos_server.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="build/generated/source/proto/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-14/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1617116007477</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/6.8.3/userguide/building_java_projects.html
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id "com.google.protobuf" version "0.8.15"
id "java"
}
repositories {
// Use JCenter for resolving dependencies.
jcenter()
mavenCentral()
}
dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13'
// This dependency is used by the application.
implementation 'com.google.guava:guava:29.0-jre'
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.15.6'
implementation 'io.grpc:grpc-netty-shaded:1.36.0'
implementation 'io.grpc:grpc-protobuf:1.36.0'
implementation 'io.grpc:grpc-stub:1.36.0'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+
// https://mvnrepository.com/artifact/org.rocksdb/rocksdbjni
implementation group: 'org.rocksdb', name: 'rocksdbjni', version: '5.8.0'
// for object to byte array serialization
//compile 'org.apache.commons:commons-lang3:3.5'
}
application {
// Define the main class for the application.
mainClass = 'hpdos.MetadataServer'
}
sourceSets {
src {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.15.6'
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.36.0"
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
\ No newline at end of file
package hpdos;
public class ConfigConstants {
public static final boolean DEBUG = false;
public static final String HOST = "localhost";
public static final int PORT = 8080;
public static final int HEARTBEAT_INTERVAL = 500;
public static final int REPLICATION_TIMEOUT = 5000;
// Backend types 300-399
public static final int BACKEND_IN_MEMORY = 300;
public static final int LSM_BACKEND = 301;
public static final int BINARY_TREE_BACKEND = 302;
public static final int ROCKSDB_BACKEND = 303;
public static final int REPLICATOR_THREAD_POOL_SIZE = 12;
}
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package hpdos;
import hpdos.grpc.HeartbeatRequest;
import hpdos.grpc.HeartbeatResponse;
import hpdos.grpc.HeartbeatServiceGrpc;
import hpdos.handler.HeartbeatHandler;
import hpdos.handler.IOHandler;
import hpdos.handler.NetworkHandler;
import hpdos.handler.ReplicateHandler;
import hpdos.lib.*;
import hpdos.message.MessageConstants;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
public class MetadataServer {
private Server server;
private final HashMap<String, MasterFollower> followers;
private final String serverID;
private boolean isMaster = false;
private int port;
private final String host;
private IOHandler ioHandler;
private ReplicationService replicationService;
public MetadataServer() {
this.followers = new HashMap<>();
this.serverID = UUID.randomUUID().toString();
this.port = 10000 + (int)(Math.random() * 40000);
this.host = "localhost";
this.replicationService = null;
}
public String getGreeting() {
return "Hello World!";
}
public boolean startMasterServices() {
this.server = ServerBuilder.forPort(ConfigConstants.PORT)
.addService(new NetworkHandler(this.ioHandler, this.replicationService))
.addService(new HeartbeatHandler(followers, serverID))
.build();
try {
this.server.start();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean startFollowerServices() {
// In case of followers NetworkHandler will only serve read requests for private metadata
// Other network handler services will fail
this.server = ServerBuilder.forPort(port)
.addService(new NetworkHandler(this.ioHandler, this.replicationService))
.addService(new ReplicateHandler(this.ioHandler))
.build();
try {
this.server.start();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public void blockForIO(Server server) {
if (server == null)
return;
try {
server.awaitTermination();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void announceToMaster() {
final ManagedChannel channel = ManagedChannelBuilder.
forAddress(ConfigConstants.HOST, ConfigConstants.PORT)
.usePlaintext()
.build();
HeartbeatServiceGrpc.HeartbeatServiceBlockingStub stub = HeartbeatServiceGrpc.newBlockingStub(channel);
HeartbeatRequest.Builder heartbeat = HeartbeatRequest.newBuilder();
heartbeat.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
heartbeat.setOperationType(MessageConstants.MASTER_HEARTBEAT);
heartbeat.setFollowerID(this.serverID);
heartbeat.setIp(this.host);
heartbeat.setPort(this.port);
try {
HeartbeatResponse response = stub.heartbeat(heartbeat.build());
} catch (Exception e) {
System.out.println("Metadata Master not found, electing self as master");
this.isMaster = true;
this.port = ConfigConstants.PORT;
}
channel.shutdown();
}
private void startHeartbeatService() {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
announceToMaster();
}
}, ConfigConstants.HEARTBEAT_INTERVAL, ConfigConstants.HEARTBEAT_INTERVAL);
}
private IOHandler initStorage(int backend) {
StorageService storageService;
switch (backend) {
case ConfigConstants.BACKEND_IN_MEMORY:
storageService = new MemoryStorageService();
break;
case ConfigConstants.ROCKSDB_BACKEND:
storageService = new RocksDBStorageService();
// Uncomment the code below for local testing
/* StorageModel value = new StorageModel(1,5,"Hello",0,"A", "World");
storageService.create("Hello",value);
value = new StorageModel(1,5,"Hello",0,"A", "World");
storageService.update("Hello",value);
storageService.readByKey("Hello");
storageService.delete("Hello",value);*/
break;
case ConfigConstants.BINARY_TREE_BACKEND:
case ConfigConstants.LSM_BACKEND:
default: return null;
}
return new IOHandler(storageService, this.isMaster);
}
private void cleanup () {
if (this.replicationService != null) {
try {
this.replicationService.cleanup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MetadataServer metaDataServer = new MetadataServer();
System.out.println(metaDataServer.getGreeting());
System.out.println("Starting Metadata service");
System.out.println("Initialising storage service");
// Check ConfigConstants for available storage options
//metaDataServer.ioHandler = metaDataServer.initStorage(ConfigConstants.BACKEND_IN_MEMORY);
metaDataServer.ioHandler = metaDataServer.initStorage(ConfigConstants.ROCKSDB_BACKEND);
if (metaDataServer.ioHandler == null) {
System.out.println("Storage server initialisation error");
return;
}
System.out.println("Searching for MetadataMaster");
metaDataServer.announceToMaster();
if (metaDataServer.isMaster) {
metaDataServer.replicationService = new InlineReplicationService(metaDataServer.followers);
System.out.println("Started master replication module");
boolean status = metaDataServer.startMasterServices();
System.out.println("Master ID: " + metaDataServer.serverID);
if (status) {
System.out.println("Starting Master MetadataServer at: " + ConfigConstants.PORT);
metaDataServer.blockForIO(metaDataServer.server);
}
else
System.out.println("Failed to create server");
} else {
System.out.println("Master Node detected.\nStarting heartbeat service");
metaDataServer.startHeartbeatService();
System.out.println("Starting replication service");
boolean status = metaDataServer.startFollowerServices();
if (status) {
System.out.println("Starting Follower MetadataServer at: " + metaDataServer.port);
metaDataServer.blockForIO(metaDataServer.server);
}
else
System.out.println("Failed to create server");
}
// Adding a shutdown hook
Runtime current = Runtime.getRuntime();
current.addShutdownHook(new Thread(metaDataServer::cleanup));
}
}
package hpdos.handler;
import hpdos.grpc.HeartbeatRequest;
import hpdos.grpc.HeartbeatResponse;
import hpdos.grpc.HeartbeatServiceGrpc;
import hpdos.lib.MasterFollower;
import hpdos.message.MessageConstants;
import io.grpc.stub.StreamObserver;
import java.time.Instant;
import java.util.HashMap;
public class HeartbeatHandler extends HeartbeatServiceGrpc.HeartbeatServiceImplBase {
private final HashMap<String, MasterFollower> followers;
private final String serverID;
public HeartbeatHandler(HashMap<String, MasterFollower> followers, String serverID) {
this.followers = followers;
this.serverID = serverID;
}
@Override
public void heartbeat(HeartbeatRequest request, StreamObserver<HeartbeatResponse> heartbeatResponseStreamObserver) {
if (!followers.containsKey(request.getFollowerID())) {
System.out.println("New follower autodiscovery. Added to system " + request);
followers.put(request.getFollowerID(), new MasterFollower(request.getIp(),
request.getPort(), request.getFollowerID()));
} else {
MasterFollower follower = followers.get(request.getFollowerID());
follower.setLastSeen(Instant.now().getEpochSecond());
}
HeartbeatResponse.Builder response = HeartbeatResponse.newBuilder();
response.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
response.setOperationType(MessageConstants.MASTER_HEARTBEAT);
response.setMasterID(this.serverID);
heartbeatResponseStreamObserver.onNext(response.build());
heartbeatResponseStreamObserver.onCompleted();
}
}
package hpdos.handler;
import hpdos.grpc.Ack;
import hpdos.grpc.Nack;
import hpdos.grpc.Request;
import hpdos.grpc.Response;
import hpdos.lib.StorageModel;
import hpdos.lib.StorageService;
import hpdos.lib.StoredModel;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
public class IOHandler {
StorageService storageService;
private final boolean isMaster;
public IOHandler(StorageService storageService, boolean isMaster) {
this.storageService = storageService;
this.isMaster = isMaster;
}
public Response create(Request request) {
Ack ack = null; Nack nack = null;
StorageModel blob = new StorageModel(
MessageConstants.INIT_VERSION,
request.getDataSize(),
request.getKey(),
request.getAccessType(),
request.getClientID(),
request.getValue());
StoredModel storedData = storageService.create(request.getKey(), blob);
if (storedData.getStatus() == MessageConstants.STATUS_OK) {
ack = ResponseBuilder.buildAck(storedData.getData().getVersion(),
storedData.getData().getDataSize(),
storedData.getData().getKey(),
storedData.getData().getCrc(),
storedData.getData().getValue());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, MessageConstants.STATUS_OK,
ack, null);
}
else {
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, storedData.getStatus(),
null, nack);
}
}
public Response update(Request request) {
Ack ack = null; Nack nack = null;
StorageModel blob = new StorageModel(
request.getVersion(),
request.getDataSize(),
request.getKey(),
request.getAccessType(),
request.getClientID(),
request.getValue());
StoredModel storedData = storageService.update(request.getKey(), blob);
if (storedData.getStatus() == MessageConstants.STATUS_OK) {
ack = ResponseBuilder.buildAck(storedData.getData().getVersion(),
storedData.getData().getDataSize(),
storedData.getData().getKey(),
storedData.getData().getCrc(),
storedData.getData().getValue());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, MessageConstants.STATUS_OK,
ack, null);
}
else {
int version = (storedData.getStatus() == MessageConstants.STATUS_UPDATE_VERSION_MISMATCH)?
storedData.getData().getVersion(): MessageConstants.INVALID_VERSION;
nack = ResponseBuilder.buildNack(version, request.getKey());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, storedData.getStatus(),
null, nack);
}
}
/**
* Removes the object from the KV store if the request version matches with the current version of data
* @param request Models to be deleted. Only the key, clientID and version needs to be valid
* @return previous value if successful else null with status
*/
public Response delete(Request request) {
Ack ack = null; Nack nack = null;
StorageModel blob = new StorageModel(
request.getVersion(),
request.getDataSize(),
request.getKey(),
request.getAccessType(),
request.getClientID(),
request.getValue());
StoredModel storedData = storageService.delete(request.getKey(), blob);
if (storedData.getStatus() == MessageConstants.STATUS_OK) {
ack = ResponseBuilder.buildAck(storedData.getData().getVersion(),
storedData.getData().getDataSize(),
storedData.getData().getKey(),
storedData.getData().getCrc(),
storedData.getData().getValue());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, MessageConstants.STATUS_OK,
ack, null);
}
else {
int version = (storedData.getStatus() == MessageConstants.STATUS_UPDATE_VERSION_MISMATCH)?
storedData.getData().getVersion(): MessageConstants.INVALID_VERSION;
nack = ResponseBuilder.buildNack(version, request.getKey());
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, storedData.getStatus(),
null, nack);
}
}
public Response read(Request request) {
Ack ack = null; Nack nack = null;
int status;
// Only Metadata Master can serve shared object lookup requests
if (!isMaster && request.getAccessType() == MessageConstants.METADATA_ACCESS_SHARED) {
status = MessageConstants.STATUS_SERVER_NOT_MASTER;
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
} else {
StoredModel readData = storageService.readByKey(request.getKey());
if (readData.getStatus() == MessageConstants.STATUS_KEY_NOT_FOUND) {
status = MessageConstants.STATUS_KEY_NOT_FOUND;
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
} else if (readData.getData().getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE &&
!request.getClientID().equals(readData.getData().getOwner())) {
status = MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS;
nack = ResponseBuilder.buildNack(MessageConstants.INVALID_VERSION,
request.getKey());
} else {
status = MessageConstants.STATUS_OK;
ack = ResponseBuilder.buildAck(readData.getData().getVersion(),
readData.getData().getDataSize(),
readData.getData().getKey(),
readData.getData().getCrc(),
readData.getData().getValue());
}
}
return ResponseBuilder.buildResponsePacket(
MessageConstants.METADATA_CREATE, status,
ack, nack);
}
}
package hpdos.handler;
import com.google.common.base.Stopwatch;
import hpdos.grpc.*;
import hpdos.lib.MasterFollower;
import hpdos.lib.ReplicationService;
import hpdos.message.RequestBuilder;
import hpdos.message.ResponseBuilder;
import io.grpc.stub.StreamObserver;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
public class NetworkHandler extends NetworkServiceGrpc.NetworkServiceImplBase {
private final IOHandler ioHandler;
private final ReplicationService replicationService;
public NetworkHandler(IOHandler ioHandler, ReplicationService replicationService) {
this.ioHandler = ioHandler;
this.replicationService = replicationService;
}
@Override
public void readMetadata(Packet requestPacket,
StreamObserver<Packet> responseObserver) {
// System.out.println("Data received" + requestPacket.toString());
for (Request request: requestPacket.getRequestList()) {
Response response = ioHandler.read(request);
Packet packet = ResponseBuilder.buildPacket(response);
// System.out.println(packet);
responseObserver.onNext(packet);
}
responseObserver.onCompleted();
}
@Override
public void createMetadata(Packet requestPacket, StreamObserver<Packet> responseObserver) {
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
for (Request request: requestPacket.getRequestList()) {
ioHandler.create(request);
}
stopwatch.stop();
// System.out.println("Added to local memory " + stopwatch);
stopwatch.reset();
stopwatch.start();
Packet packet = replicate(requestPacket);
stopwatch.stop();
// System.out.println("Replication time " + stopwatch);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void updateMetadata(Packet requestPacket, StreamObserver<Packet> responseObserver) {
// System.out.println("new create request " + requestPacket);
for (Request request: requestPacket.getRequestList()) {
ioHandler.update(request);
}
// System.out.println("Added to local memory");
Packet packet = replicate(requestPacket);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void deleteMetadata(Packet requestPacket, StreamObserver<Packet> responseObserver) {
// System.out.println("new create request " + requestPacket);
for (Request request: requestPacket.getRequestList()) {
ioHandler.delete(request);
}
// System.out.println("Added to local memory");
Packet packet = replicate(requestPacket);
responseObserver.onNext(packet);
responseObserver.onCompleted();
}
@Override
public void getReadReplicaList(RequestList requestList,
StreamObserver<ResponseList> responseListStreamObserver) {
HashMap<String, MasterFollower> followers = replicationService.getFollowers();
ResponseList.Builder responseList = ResponseList.newBuilder();
for (MasterFollower follower: followers.values()) {
Follower.Builder replica = Follower.newBuilder();
replica.setIp(follower.getIp());
replica.setPort(follower.getPort());
replica.setFollowerID(follower.getFollowerID());
replica.setLastSeen(follower.getLastSeen());
replica.build();
responseList.addFollower(replica);
}
responseListStreamObserver.onNext(responseList.build());
responseListStreamObserver.onCompleted();
}
private Packet replicate(Packet requestPacket) {
ReplicationRequest replicationRequest = RequestBuilder.
buildReplicationRequest(new ArrayList<>(requestPacket.getRequestList()));
ReplicationResponse replicationResponse = null;
try {
// System.out.println("starting replication");
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
replicationResponse = replicationService.replicateMetadata(replicationRequest);
stopwatch.stop();
// System.out.println("Network handler replicate" + stopwatch);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// System.out.println("replication complete");
Packet packet = ResponseBuilder.buildPacket(new ArrayList<>(replicationResponse.getResponseList()));
// System.out.println(packet);
return packet;
}
}
package hpdos.handler;
import com.google.common.base.Stopwatch;
import hpdos.grpc.*;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
import io.grpc.stub.StreamObserver;
public class ReplicateHandler extends ReplicationServiceGrpc.ReplicationServiceImplBase {
private final IOHandler ioHandler;
public ReplicateHandler(IOHandler ioHandler) {
this.ioHandler = ioHandler;
}
@Override
public void replicateMetadata(ReplicationRequest replicationRequest, StreamObserver<ReplicationResponse> responseObserver) {
ReplicationResponse responsePacket = null;
// System.out.println("Replication request " + replicationRequest);
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
if (replicationRequest.getPacketType() == MessageConstants.PACKET_METADATA_REQUEST) {
for (Request request: replicationRequest.getRequestList()) {
if (request.getOperationType() == MessageConstants.METADATA_CREATE) {
Response response = ioHandler.create(request);
responsePacket = ResponseBuilder.buildReplicationResponse(response);
} else if (request.getOperationType() == MessageConstants.METADATA_UPDATE) {
Response response = ioHandler.update(request);
responsePacket = ResponseBuilder.buildReplicationResponse(response);
} else if (request.getOperationType() == MessageConstants.METADATA_DELETE) {
Response response = ioHandler.delete(request);
responsePacket = ResponseBuilder.buildReplicationResponse(response);
}
responseObserver.onNext(responsePacket);
}
responseObserver.onCompleted();
}
stopwatch.stop();
// System.out.println("Replicate Handler " + stopwatch);
}
}
package hpdos.lib;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.ListenableFuture;
import hpdos.ConfigConstants;
import hpdos.grpc.ReplicationRequest;
import hpdos.grpc.ReplicationResponse;
import hpdos.grpc.ReplicationServiceGrpc;
import hpdos.grpc.Response;
import hpdos.message.MessageConstants;
import hpdos.message.ResponseBuilder;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.*;
import java.util.concurrent.*;
public class InlineReplicationService implements ReplicationService {
private final HashMap<String, MasterFollower> followers;
private final HashMap<String, ManagedChannel> channels;
private final ExecutorService executorService;
public InlineReplicationService(HashMap<String, MasterFollower> followers) {
this.followers = followers;
this.channels = new HashMap<>();
for (MasterFollower follower: this.followers.values()) {
ManagedChannel channel = ManagedChannelBuilder
.forAddress(follower.getIp(), follower.getPort())
.usePlaintext()
.build();
channels.put(follower.getFollowerID(), channel);
}
this.executorService = Executors.newFixedThreadPool(ConfigConstants.REPLICATOR_THREAD_POOL_SIZE);
}
@Override
public void cleanup() throws InterruptedException {
for (ManagedChannel channel: channels.values())
channel.shutdown();
executorService.shutdown();
executorService.awaitTermination(MessageConstants.STATUS_REPLICATION_TIMEOUT, TimeUnit.MILLISECONDS);
}
private void establishChannels() {
for (String followerID: followers.keySet()) {
if (!channels.containsKey(followerID)) {
MasterFollower follower = followers.get(followerID);
ManagedChannel channel = ManagedChannelBuilder
.forAddress(follower.getIp(), follower.getPort())
.usePlaintext()
.build();
channels.put(follower.getFollowerID(), channel);
}
}
}
@Override
public ReplicationResponse replicateMetadata(ReplicationRequest replicationRequest)
throws InterruptedException, ExecutionException {
Set<Callable<ReplicationResponse>> callables = new HashSet<>();
// new followers have joined or left.
// TODO: Handle follower leaving scenario
// FIXME: fix edge case where equal number of followers leaving and joining won't trigger connection reestablishment
if (channels.size() != followers.size()) {
establishChannels();
}
for (ManagedChannel channel: channels.values()) {
callables.add(() -> {
ReplicationServiceGrpc.ReplicationServiceBlockingStub stub =
ReplicationServiceGrpc.newBlockingStub(channel);
return stub.replicateMetadata(replicationRequest);
});
}
List<Future<ReplicationResponse>> futures = executorService.invokeAll(callables);
HashMap<String, Response> responseHashMap = new HashMap<>();
Stopwatch stopwatch = Stopwatch.createUnstarted();
stopwatch.start();
for (Future<ReplicationResponse> future: futures) {
ReplicationResponse replicationResponse;
replicationResponse = future.get(); //TODO: Add and handle get timeout. Timeout related constants already added
for (Response receivedResponse: replicationResponse.getResponseList()) {
int status = receivedResponse.getStatus();
if (status == MessageConstants.STATUS_OK) {
if (!responseHashMap.containsKey(receivedResponse.getAck().getKey()))
responseHashMap.put(receivedResponse.getAck().getKey(), receivedResponse);
} else {
responseHashMap.put(receivedResponse.getNack().getKey(), receivedResponse);
}
}
}
stopwatch.stop();
// System.out.println("replicateMetadata ReplicationService " + stopwatch);
return ResponseBuilder.
buildReplicationResponse(new ArrayList<>(responseHashMap.values()));
}
@Override
public ReplicationResponse replicateMetadataAsync(ReplicationRequest replicationRequest) {
for (ManagedChannel channel: channels.values()) {
ReplicationServiceGrpc.ReplicationServiceFutureStub stub =
ReplicationServiceGrpc.newFutureStub(channel);
ListenableFuture<ReplicationResponse> res = stub.replicateMetadata(replicationRequest);
}
throw new UnsupportedOperationException("Implementation not complete");
}
@Override
public HashMap<String, MasterFollower> getFollowers() {
return followers;
}
}
package hpdos.lib;
import java.time.Instant;
public class MasterFollower {
private String ip;
private int port;
private final String followerID;
private long lastSeen;
public MasterFollower(String ip, int port, String followerID) {
this.ip = ip;
this.port = port;
this.followerID = followerID;
this.lastSeen = Instant.now().getEpochSecond();
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getFollowerID() {
return followerID;
}
public long getLastSeen() {
return lastSeen;
}
public void setLastSeen(long lastSeen) {
this.lastSeen = lastSeen;
}
@Override
public String toString() {
return "MasterFollower {" +
"ip='" + ip + '\'' +
", port=" + port +
", followerID='" + followerID + '\'' +
'}';
}
}
package hpdos.lib;
import hpdos.message.MessageConstants;
import java.util.concurrent.ConcurrentHashMap;
public class MemoryStorageService implements StorageService {
private final ConcurrentHashMap<String, StorageModel> memoryKVStore;
public MemoryStorageService() {
this.memoryKVStore = new ConcurrentHashMap<>();
}
@Override
public StoredModel create(String key, StorageModel value) {
try {
if (memoryKVStore.putIfAbsent(key, value) != null)
return new StoredModel(null, MessageConstants.STATUS_KEY_EXISTS);
return new StoredModel(value, MessageConstants.STATUS_OK);
} catch (Exception e) {
return null;
}
}
@Override
public StoredModel readByKey(String key) {
if (!memoryKVStore.containsKey(key))
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
return new StoredModel(memoryKVStore.get(key), MessageConstants.STATUS_OK);
}
@Override
public StoredModel update(String key, StorageModel value) {
StorageModel previousValue = memoryKVStore.get(key);
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
// the request will have the old version number of the data to be inserted, we only update the data
// with a new version number if at the time of update the two versions match
// else we reject the update
StorageModel newValue = value.createVersionUpdatedModel();
boolean status = memoryKVStore.replace(key, value, newValue); // the equals method is overridden in Storage model
// to equate two objects based on their version numbers
if (status)
return new StoredModel(value, MessageConstants.STATUS_OK);
else
return new StoredModel(null, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
}
@Override
public StoredModel delete(String key, StorageModel value) {
StorageModel previousValue = memoryKVStore.get(key);
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
boolean status = memoryKVStore.remove(key, value);
if (status)
return new StoredModel(previousValue, MessageConstants.STATUS_OK);
else
return new StoredModel(null, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
}
}
package hpdos.lib;
import hpdos.grpc.ReplicationRequest;
import hpdos.grpc.ReplicationResponse;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
public interface ReplicationService {
abstract ReplicationResponse replicateMetadata(ReplicationRequest replicationRequest) throws InterruptedException, ExecutionException;
abstract ReplicationResponse replicateMetadataAsync(ReplicationRequest replicationRequest);
abstract void cleanup() throws InterruptedException;
abstract HashMap<String, MasterFollower> getFollowers();
}
package hpdos.lib;
import hpdos.ConfigConstants;
import hpdos.message.MessageConstants;
import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import java.io.*;
public class RocksDBStorageService implements StorageService {
//private final ConcurrentHashMap<String, StorageModel> memoryKVStore;
private static final String dbPath = "./rocksdb-data/";
private RocksDB rocksDB;
public RocksDBStorageService() {
//this.memoryKVStore = new ConcurrentHashMap<>();
RocksDB.loadLibrary();
//If the file does not exist, create the file first
try (final Options options = new Options().setCreateIfMissing(true)) {
try {
rocksDB = RocksDB.open(options, dbPath);
options.useDirectReads();
options.setIncreaseParallelism(12);
//options.writeBufferSize(); //16GB
//options.optimizeForPointLookup(256);
} catch (RocksDBException e) {
e.printStackTrace();
}
}
System.out.println("Persistent Store Opened Successfully!");
}
public static byte[] toStream(StorageModel val) {
// Reference for stream of bytes
if (val == null)
return null;
byte[] stream = null;
// ObjectOutputStream is used to convert a Java object into OutputStream
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(val);
stream = baos.toByteArray();
} catch (IOException e) {
// Error in serialization
e.printStackTrace();
}
return stream;
}
public static StorageModel toStorageModel(byte[] stream) {
StorageModel st = null;
if (stream == null)
return null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(stream);
ObjectInputStream ois = new ObjectInputStream(bais)) {
st = (StorageModel) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
// Error in de-serialization
e.printStackTrace();
} // You are converting an invalid stream to StorageModel
return st;
}
@Override
public StoredModel create(String key, StorageModel value) {
/* try {
if (memoryKVStore.putIfAbsent(key, value) != null)
return new StoredModel(null, MessageConstants.STATUS_KEY_EXISTS);
return new StoredModel(value, MessageConstants.STATUS_OK);
} catch (Exception e) {
return null;
}*/
try {
if (rocksDB.get(key.getBytes()) == null) {
rocksDB.put(key.getBytes(), toStream(value));
if (ConfigConstants.DEBUG) {
System.out.println("Created object with key = " + key);
}
//return new StoredModel(value, MessageConstants.STATUS_OK);
} else {
return new StoredModel(null, MessageConstants.STATUS_KEY_EXISTS);
}
} catch (RocksDBException e) {
e.printStackTrace();
}
return new StoredModel(value, MessageConstants.STATUS_OK);
}
@Override
public StoredModel readByKey(String key) {
/*if (!memoryKVStore.containsKey(key))
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
return new StoredModel(memoryKVStore.get(key), MessageConstants.STATUS_OK);*/
StorageModel tmpStorageModel = null;
try {
tmpStorageModel = toStorageModel(rocksDB.get(key.getBytes()));
if (tmpStorageModel == null) {
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
}
} catch (RocksDBException e) {
e.printStackTrace();
}
return new StoredModel(tmpStorageModel, MessageConstants.STATUS_OK);
}
@Override
public StoredModel update(String key, StorageModel value) {
/* StorageModel previousValue = memoryKVStore.get(key);
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
// the request will have the old version number of the data to be inserted, we only update the data
// with a new version number if at the time of update the two versions match
// else we reject the update
StorageModel newValue = value.createVersionUpdatedModel();
boolean status = memoryKVStore.replace(key, value, newValue); // the equals method is overridden in Storage model
// to equate two objects based on their version numbers
if (status)
return new StoredModel(value, MessageConstants.STATUS_OK);
else
return new StoredModel(null, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);*/
StorageModel previousValue;
boolean status = false;
try {
previousValue = toStorageModel(rocksDB.get(key.getBytes()));
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
// the request will have the old version number of the data to be inserted, we only update the data
// with a new version number if at the time of update the two versions match
// else we reject the update
StorageModel newValue = value.createVersionUpdatedModel();
if (newValue.getVersion() > previousValue.getVersion()) {
status = true;
rocksDB.put(key.getBytes(), toStream(value));
if (ConfigConstants.DEBUG) {
System.out.println("Updated object with key = " + key);
}
}
} catch (RocksDBException e) {
e.printStackTrace();
}
if (status)
return new StoredModel(value, MessageConstants.STATUS_OK);
else
return new StoredModel(null, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
}
@Override
public StoredModel delete(String key, StorageModel value) {
/*StorageModel previousValue = memoryKVStore.get(key);
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
boolean status = memoryKVStore.remove(key, value);
if (status)
return new StoredModel(previousValue, MessageConstants.STATUS_OK);
else
return new StoredModel(null, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
}*/
StorageModel previousValue = null;
//boolean status = false;
try {
previousValue = toStorageModel(rocksDB.get(key.getBytes()));
if (previousValue == null)
return new StoredModel(null, MessageConstants.STATUS_KEY_NOT_FOUND);
else {
if (previousValue.getAccessType() == MessageConstants.METADATA_ACCESS_PRIVATE
&& !previousValue.getOwner().equals(value.getOwner()))
return new StoredModel(null, MessageConstants.STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS);
if (value.getVersion() < previousValue.getVersion())
return new StoredModel(null, MessageConstants.STATUS_UPDATE_VERSION_MISMATCH);
//status = true;
rocksDB.delete(key.getBytes());
if (ConfigConstants.DEBUG) {
System.out.println("Deleted object with key = " + key);
}
}
} catch (RocksDBException e) {
e.printStackTrace();
}
return new StoredModel(previousValue, MessageConstants.STATUS_OK);
}
}
package hpdos.lib;
import java.io.Serializable;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
public class StorageModel implements Serializable {
private int version;
private int dataSize;
private final String key; // key is immutable
private long crc;
private int accessType;
private String value;
private final String owner; // ownership is immutable
public StorageModel(int version, int dataSize, String key, int accessType, String owner, String value) {
this.version = version;
this.dataSize = dataSize;
this.key = key;
this.accessType = accessType;
this.value = value;
this.owner = owner;
// calculate CRC32 based on the value field
byte[] bytes = value.getBytes();
Checksum checksum = new CRC32();
checksum.update(bytes, 0, bytes.length);
this.crc = checksum.getValue();
}
public StorageModel createVersionUpdatedModel() {
int updatedVersion = (this.getVersion() + 1) % Integer.MAX_VALUE; // version wraps around
return new StorageModel(updatedVersion, this.getDataSize(),
this.getKey(), this.getAccessType(), this.getOwner(), this.getValue());
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getDataSize() {
return dataSize;
}
public void setDataSize(int dataSize) {
this.dataSize = dataSize;
}
public String getKey() {
return key;
}
public long getCrc() {
return crc;
}
public void setCrc(long crc) {
this.crc = crc;
}
public int getAccessType() {
return accessType;
}
public void setAccessType(int accessType) {
this.accessType = accessType;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getOwner() {
return owner;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj.getClass() != this.getClass())
return false;
StorageModel model = (StorageModel) obj;
return this.getVersion() == model.getVersion();
}
}
package hpdos.lib;
public interface StorageService {
StoredModel create(String key, StorageModel value);
StoredModel readByKey(String key);
StoredModel update(String key, StorageModel value);
StoredModel delete(String key, StorageModel version);
}
package hpdos.lib;
public class StoredModel {
private StorageModel data;
private int status;
public StoredModel(StorageModel data, int status) {
this.data = data;
this.status = status;
}
public StorageModel getData() {
return data;
}
public void setData(StorageModel data) {
this.data = data;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
package hpdos.message;
public class MessageConstants {
public static final int INIT_VERSION = 0;
public static final int INVALID_VERSION = -1;
public static final int METADATA_ACCESS_PRIVATE = 700;
public static final int METADATA_ACCESS_SHARED = 777;
// 00 to 99 - Client Server Interaction operations
public static final int PACKET_METADATA_REQUEST = 0;
public static final int PACKET_METADATA_RESPONSE = 1;
// Distinguishing ACK and NACK packets
public static final int STATUS_OK = 200;
public static final int STATUS_UNAUTHORIZED_PRIVATE_KEY_ACCESS = 401;
public static final int STATUS_REPLICATION_FAILED = 402;
public static final int STATUS_SERVER_NOT_MASTER = 403;
public static final int STATUS_KEY_NOT_FOUND = 404;
public static final int STATUS_REPLICATION_TIMEOUT = 405;
public static final int STATUS_IO_WRITE_FAILED = 406;
public static final int STATUS_KEY_EXISTS = 407;
public static final int STATUS_UPDATE_VERSION_MISMATCH = 408;
// 100 to 199 - HPDOS System internal operations
public static final int MASTER_HEARTBEAT = 100;
public static final int METADATA_CREATE = 101;
public static final int METADATA_READ = 102;
public static final int METADATA_UPDATE = 103;
public static final int METADATA_DELETE = 104;
}
package hpdos.message;
import hpdos.grpc.Packet;
import hpdos.grpc.ReplicationRequest;
import hpdos.grpc.Request;
import java.util.ArrayList;
public class RequestBuilder {
public static Request buildRequest(int operationType, int version,
int dataSize, String key, int crc, String value) {
Request.Builder request = Request.newBuilder();
request.setOperationType(operationType);
request.setVersion(version);
request.setDataSize(dataSize);
request.setKey(key);
request.setCrc(crc);
request.setValue(value);
return request.build();
}
public static Packet buildPacket(ArrayList<Request> requests) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
packet.addAllRequest(requests);
return packet.build();
}
public static ReplicationRequest buildReplicationRequest(ArrayList<Request> requests) {
ReplicationRequest.Builder builder = ReplicationRequest.newBuilder();
builder.setPacketType(MessageConstants.PACKET_METADATA_REQUEST);
builder.addAllRequest(requests);
return builder.build();
}
}
package hpdos.message;
import hpdos.grpc.*;
import java.util.ArrayList;
public class ResponseBuilder {
public static Ack buildAck(int version, int dataSize, String key, long crc, String value) {
Ack.Builder ack = Ack.newBuilder();
ack.setKey(key);
ack.setVersion(version);
ack.setDataSize(dataSize);
ack.setCrc(crc);
ack.setValue(value);
return ack.build();
}
public static Nack buildNack(int version, String key) {
Nack.Builder nack = Nack.newBuilder();
nack.setKey(key);
nack.setVersion(version);
return nack.build();
}
public static Response buildResponsePacket(int operationType, int status,
Ack ack,
Nack nack) {
Response.Builder response = Response.newBuilder();
response.setOperationType(operationType);
response.setStatus(status);
if (ack != null)
response.setAck(ack);
else
response.clearAck();
if (nack != null)
response.setNack(nack);
else
response.clearNack();
return response.build();
}
public static Packet buildPacket(ArrayList<Response> responses) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addAllResponse(responses);
return packet.build();
}
public static Packet buildPacket(Response response) {
Packet.Builder packet = Packet.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addResponse(response);
return packet.build();
}
public static ReplicationResponse buildReplicationResponse(Response response) {
ReplicationResponse.Builder packet = ReplicationResponse.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addResponse(response);
return packet.build();
}
public static ReplicationResponse buildReplicationResponse(ArrayList<Response> response) {
ReplicationResponse.Builder packet = ReplicationResponse.newBuilder();
packet.setPacketType(MessageConstants.PACKET_METADATA_RESPONSE);
packet.addAllResponse(response);
return packet.build();
}
}
syntax = "proto3";
package hpdos.grpc;
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "Heartbeat";
service HeartbeatService {
/**
Exchange heartbeat
*/
rpc heartbeat(HeartbeatRequest) returns (HeartbeatResponse) {}
}
message HeartbeatRequest {
int32 packetType = 1;
int32 operationType = 2;
string ip = 3;
int32 port = 4;
string followerID = 5;
}
message HeartbeatResponse {
int32 packetType = 1;
int32 operationType = 2;
bool status = 3;
string masterID = 4;
}
syntax = "proto3";
package hpdos.grpc;
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "PacketFormatProto";
service NetworkService {
/**
Receive Packet from client
*/
rpc readMetadata(Packet) returns (Packet) {}
rpc createMetadata(Packet) returns (Packet) {}
rpc updateMetadata(Packet) returns (Packet) {}
rpc deleteMetadata(Packet) returns (Packet) {}
rpc getReadReplicaList(RequestList) returns (ResponseList) {}
}
message Packet {
int32 packetType = 1;
repeated Request request = 2;
repeated Response response = 3;
}
message Request {
int32 operationType = 1;
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
int32 accessType = 6;
string clientID = 7;
string value = 8;
}
message Response {
int32 operationType = 1;
int32 status = 2;
Ack ack = 3;
Nack nack = 4;
}
message Ack {
int32 version = 2;
int32 dataSize = 3;
string key = 4;
int64 crc = 5;
string value = 6;
}
message Nack {
string key = 2;
int32 version = 3;
}
message RequestList {}
message ResponseList {
int32 operationType = 1;
int32 status = 2;
repeated Follower follower = 3;
}
message Follower {
string ip = 1;
int32 port = 2;
string followerID = 3;
int64 lastSeen = 4;
}
\ No newline at end of file
syntax = "proto3";
package hpdos.grpc;
import "PacketFormat.proto";
option java_multiple_files = true;
option java_package = "hpdos.grpc";
option java_outer_classname = "Replicate";
service ReplicationService {
/**
Receive Packet from client
*/
rpc replicateMetadata(ReplicationRequest) returns (ReplicationResponse) {}
}
message ReplicationRequest {
int32 packetType = 1;
repeated Request request = 2;
}
message ReplicationResponse {
int32 packetType = 1;
repeated Response response = 2;
}
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package hpdos;
import org.junit.Test;
import static org.junit.Assert.*;
public class AppTest {
@Test public void testAppHasAGreeting() {
MetadataServer classUnderTest = new MetadataServer();
assertNotNull("app should have a greeting", classUnderTest.getGreeting());
}
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/6.8.3/userguide/multi_project_builds.html
*/
rootProject.name = 'hpdos'
include('app')
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2014 Intel Corporation
# binary name
APP = l2fwd
# all source are stored in SRCS-y
SRCS-y := main.c
# Build using pkg-config variables if possible
ifneq ($(shell pkg-config --exists libdpdk && echo 0),0)
$(error "no installation of DPDK found")
endif
all: shared
.PHONY: shared static
shared: build/$(APP)-shared
ln -sf $(APP)-shared build/$(APP)
static: build/$(APP)-static
ln -sf $(APP)-static build/$(APP)
PKGCONF ?= pkg-config
PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null)
CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk)
# Add flag to allow experimental API as l2fwd uses rte_ethdev_set_ptype API
CFLAGS += -DALLOW_EXPERIMENTAL_API
LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)
LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk)
build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)
build:
@mkdir -p $@
.PHONY: clean
clean:
rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
test -d build && rmdir -p build || true
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2016 Intel Corporation
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_string_fns.h>
#include <rte_udp.h>
#include <rte_ip.h>
#include <rte_hash.h>
#define CAPACITY 50000 // Size of the Hash Table
static volatile bool force_quit;
/* MAC updating enabled by default */
static int mac_updating = 1;
#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
#define MEMPOOL_CACHE_SIZE 256
/*
* Configurable number of RX/TX ring descriptors
*/
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/* ethernet addresses of ports */
static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;
/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
struct port_pair_params {
#define NUM_PORTS 2
uint16_t port[NUM_PORTS];
} __rte_cache_aligned;
static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2];
static struct port_pair_params *port_pair_params;
static uint16_t nb_port_pair_params;
static unsigned int l2fwd_rx_queue_per_lcore = 1;
#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf {
unsigned n_rx_port;
unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
} __rte_cache_aligned;
struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
/* Per-port statistics struct */
struct l2fwd_port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
static uint64_t timer_period = 10; /* default period is 10 seconds */
struct pkt_data {
uint16_t type;
uint16_t sep1;
uint16_t sep2;
uint16_t sep3;
uint32_t key;
uint16_t sep4;
uint16_t sep5;
uint16_t sep6;
uint32_t val;
};
/* Print out statistics on packets dropped */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
unsigned portid;
total_packets_dropped = 0;
total_packets_tx = 0;
total_packets_rx = 0;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
/* Clear screen and move to top left */
printf("%s%s", clr, topLeft);
printf("\nPort statistics ====================================");
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
/* skip disabled ports */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
"\nPackets sent: %24"PRIu64
"\nPackets received: %20"PRIu64
"\nPackets dropped: %21"PRIu64,
portid,
port_statistics[portid].tx,
port_statistics[portid].rx,
port_statistics[portid].dropped);
total_packets_dropped += port_statistics[portid].dropped;
total_packets_tx += port_statistics[portid].tx;
total_packets_rx += port_statistics[portid].rx;
}
printf("\nAggregate statistics ==============================="
"\nTotal packets sent: %18"PRIu64
"\nTotal packets received: %14"PRIu64
"\nTotal packets dropped: %15"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
fflush(stdout);
}
/*
* Create the hash table that will contain the flows that
* the node will handle, which will be used to decide if packet
* is transmitted or dropped.
*/
/*static struct rte_hash *
create_hash_table(const struct shared_info *info)
{
//uint32_t num_flows_node = info->num_flows / info->num_nodes;
//char name[RTE_HASH_NAMESIZE];
struct rte_hash *h;
// create table
struct rte_hash_parameters hash_params = {
.entries = 100000,
.key_len = sizeof(uint32_t), // Store IPv4 dest IP address
.socket_id = rte_socket_id(),
.hash_func_init_val = 0,
};
hash_params.name = "ht";
h = rte_hash_create(&hash_params);
if (h == NULL)
rte_exit(EXIT_FAILURE,
"Problem creating the hash table \n");
return h;
}
static void
populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
{
unsigned int i;
int32_t ret;
uint32_t key;
// Add keys in table
for (i = 0; i < 100000; i++) {
key = rte_cpu_to_be_32(i);
ret = rte_hash_add_key(h, (void *) &key);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Unable to add entry %u "
"in hash table\n", i);
}
printf("Hash table: Adding keys\n");
}*/
unsigned long hash_function(char* str) {
unsigned long i = 0;
for (int j=0; str[j]; j++)
i += str[j];
return i % CAPACITY;
}
typedef struct Ht_item Ht_item;
// Define the Hash Table Item here
struct Ht_item {
char* key;
char* value;
};
typedef struct HashTable HashTable;
// Define the Hash Table here
struct HashTable {
// Contains an array of pointers
// to items
Ht_item** items;
int size;
int count;
};
Ht_item* create_item(char* key, char* value) {
// Creates a pointer to a new hash table item
Ht_item* item = (Ht_item*) malloc (sizeof(Ht_item));
item->key = (char*) malloc (strlen(key) + 1);
item->value = (char*) malloc (strlen(value) + 1);
strcpy(item->key, key);
strcpy(item->value, value);
return item;
}
HashTable* create_table(int size) {
// Creates a new HashTable
HashTable* table = (HashTable*) malloc (sizeof(HashTable));
table->size = size;
table->count = 0;
table->items = (Ht_item**) calloc (table->size, sizeof(Ht_item*));
for (int i=0; i<table->size; i++)
table->items[i] = NULL;
return table;
}
void free_item(Ht_item* item) {
// Frees an item
free(item->key);
free(item->value);
free(item);
}
void free_table(HashTable* table) {
// Frees the table
for (int i=0; i<table->size; i++) {
Ht_item* item = table->items[i];
if (item != NULL)
free_item(item);
}
free(table->items);
free(table);
}
void handle_collision(HashTable* table, unsigned long index, Ht_item* item) {
}
void ht_insert(HashTable* table, char* key, char* value) {
// Create the item
Ht_item* item = create_item(key, value);
// Compute the index
unsigned long index = hash_function(key);
Ht_item* current_item = table->items[index];
if (current_item == NULL) {
// Key does not exist.
if (table->count == table->size) {
// Hash Table Full
printf("Insert Error: Hash Table is full\n");
// Remove the create item
free_item(item);
return;
}
// Insert directly
table->items[index] = item;
table->count++;
}
else {
// Scenario 1: We only need to update value
if (strcmp(current_item->key, key) == 0) {
strcpy(table->items[index]->value, value);
return;
}
else {
// Scenario 2: Collision
// We will handle case this a bit later
handle_collision(table, index, item);
return;
}
}
}
char* ht_search(HashTable* table, char* key) {
// Searches the key in the hashtable
// and returns NULL if it doesn't exist
int index = hash_function(key);
Ht_item* item = table->items[index];
// Ensure that we move to a non NULL item
if (item != NULL) {
if (strcmp(item->key, key) == 0)
return item->value;
}
return NULL;
}
void print_search(HashTable* table, char* key) {
char* val;
if ((val = ht_search(table, key)) == NULL) {
printf("Key:%s does not exist\n", key);
return;
}
else {
printf("Key:%s, Value:%s\n", key, val);
}
}
void print_table(HashTable* table) {
printf("\nHash Table\n-------------------\n");
for (int i=0; i<table->size; i++) {
if (table->items[i]) {
printf("Index:%d, Key:%s, Value:%s\n", i, table->items[i]->key, table->items[i]->value);
}
}
printf("-------------------\n\n");
}
static void
l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid)
{
struct rte_ether_hdr *eth;
void *tmp;
//struct pkt_data *data;
eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
/* 02:00:00:00:00:xx */
/* 0c:42:a1:df:ac:40 41 */
tmp = &eth->d_addr.addr_bytes[0];
// @rinku
//*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
*((uint64_t *)tmp) = 0x40acdfa1420c + ((uint64_t)dest_portid << 56);
/* src addr */
rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->s_addr);
// @rinku
struct rte_ipv4_hdr *ipv4_hdr;
if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
uint32_t tmp_dst;
tmp_dst = ipv4_hdr->src_addr;
ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
ipv4_hdr->dst_addr = tmp_dst;
}
// @rinku
struct rte_udp_hdr *udp;
struct pkt_data *data;
if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
udp = (struct rte_udp_hdr *)((unsigned char *)ipv4_hdr + sizeof(struct rte_ipv4_hdr));
uint16_t port_dst = udp->dst_port;
udp->dst_port = udp->src_port;
udp->src_port = port_dst;
//printf("len= %d ", ntohs(udp->dgram_len));
data = (struct pkt_data *) ((unsigned char *)udp + sizeof(struct rte_udp_hdr));
if ((data != NULL) && (ntohs(data->type)==4)) {
//if (data != NULL) {
//printf("len= %d ", udp->dgram_len);
//printf("%x %x %x %x %d %x %x %x %d \n",ntohs(data->type), ntohs(data->sep1), ntohs(data->sep2), ntohs(data->sep3), ntohl(data->key), ntohs(data->sep4), ntohs(data->sep5), ntohs(data->sep6),ntohl(data->val));
//printf("key= %d val= %d \n",ntohl(data->key),ntohs(data->val));
}
}
}
static void
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
{
unsigned dst_port;
int sent;
struct rte_eth_dev_tx_buffer *buffer;
dst_port = l2fwd_dst_ports[portid];
//printf("DEST PORT = %u", dst_port);
//@rinku
/*if (dst_port == 0)
dst_port = 1;
else if (dst_port == 1)
dst_port = 0;*/
if (mac_updating)
l2fwd_mac_updating(m, dst_port);
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
/* main processing loop */
static void
l2fwd_main_loop(void)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
HashTable* ht = create_table(CAPACITY);
ht_insert(ht, "1", "First address");
ht_insert(ht, "2", "Second address");
print_search(ht, "1");
print_search(ht, "2");
print_search(ht, "3");
print_table(ht);
free_table(ht);
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on main core */
if (lcore_id == rte_get_main_lcore()) {
print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid);
}
}
}
}
static int
l2fwd_launch_one_lcore(__rte_unused void *dummy)
{
l2fwd_main_loop();
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n"
" --portmap: Configure forwarding port pair mapping\n"
" Default: alternate port pairs\n\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
return pm;
}
static int
l2fwd_parse_port_pair_config(const char *q_arg)
{
enum fieldnames {
FLD_PORT1 = 0,
FLD_PORT2,
_NUM_FLD
};
unsigned long int_fld[_NUM_FLD];
const char *p, *p0 = q_arg;
char *str_fld[_NUM_FLD];
unsigned int size;
char s[256];
char *end;
int i;
nb_port_pair_params = 0;
while ((p = strchr(p0, '(')) != NULL) {
++p;
p0 = strchr(p, ')');
if (p0 == NULL)
return -1;
size = p0 - p;
if (size >= sizeof(s))
return -1;
memcpy(s, p, size);
s[size] = '\0';
if (rte_strsplit(s, sizeof(s), str_fld,
_NUM_FLD, ',') != _NUM_FLD)
return -1;
for (i = 0; i < _NUM_FLD; i++) {
errno = 0;
int_fld[i] = strtoul(str_fld[i], &end, 0);
if (errno != 0 || end == str_fld[i] ||
int_fld[i] >= RTE_MAX_ETHPORTS)
return -1;
}
if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
printf("exceeded max number of port pair params: %hu\n",
nb_port_pair_params);
return -1;
}
port_pair_params_array[nb_port_pair_params].port[0] =
(uint16_t)int_fld[FLD_PORT1];
port_pair_params_array[nb_port_pair_params].port[1] =
(uint16_t)int_fld[FLD_PORT2];
++nb_port_pair_params;
}
port_pair_params = port_pair_params_array;
return 0;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
#define CMD_LINE_OPT_PORTMAP_CONFIG "portmap"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
CMD_LINE_OPT_PORTMAP_NUM,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
port_pair_params = NULL;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case CMD_LINE_OPT_PORTMAP_NUM:
ret = l2fwd_parse_port_pair_config(optarg);
if (ret) {
fprintf(stderr, "Invalid config\n");
l2fwd_usage(prgname);
return -1;
}
break;
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/*
* Check port pair config with enabled port mask,
* and for valid port pair combinations.
*/
static int
check_port_pair_config(void)
{
uint32_t port_pair_config_mask = 0;
uint32_t port_pair_mask = 0;
uint16_t index, i, portid;
for (index = 0; index < nb_port_pair_params; index++) {
port_pair_mask = 0;
for (i = 0; i < NUM_PORTS; i++) {
portid = port_pair_params[index].port[i];
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("port %u is not enabled in port mask\n",
portid);
return -1;
}
if (!rte_eth_dev_is_valid_port(portid)) {
printf("port %u is not present on the board\n",
portid);
return -1;
}
port_pair_mask |= 1 << portid;
}
if (port_pair_config_mask & port_pair_mask) {
printf("port %u is used in other port pairs\n", portid);
return -1;
}
port_pair_config_mask |= port_pair_mask;
}
l2fwd_enabled_port_mask &= port_pair_config_mask;
return 0;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
int ret;
char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
ret = rte_eth_link_get_nowait(portid, &link);
if (ret < 0) {
all_ports_up = 0;
if (print_flag == 1)
printf("Port %u link get failed: %s\n",
portid, rte_strerror(-ret));
continue;
}
/* print link status if flag set */
if (print_flag == 1) {
rte_eth_link_to_str(link_status_text,
sizeof(link_status_text), &link);
printf("Port %d %s\n", portid,
link_status_text);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
main(int argc, char **argv)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
if (port_pair_params != NULL) {
if (check_port_pair_config() < 0)
rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
}
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/* populate destination port details */
if (port_pair_params != NULL) {
uint16_t idx, p;
for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
p = idx & 1;
portid = port_pair_params[idx >> 1].port[p];
l2fwd_dst_ports[portid] =
port_pair_params[idx >> 1].port[p ^ 1];
}
} else {
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
} else {
last_port = portid;
}
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
portid, l2fwd_dst_ports[portid]);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
ret = rte_eth_dev_info_get(portid, &dev_info);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
portid, strerror(-ret));
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_macaddr_get(portid,
&l2fwd_ports_eth_addr[portid]);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot get MAC address: err=%d, port=%u\n",
ret, portid);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
0);
if (ret < 0)
printf("Port %u, Failed to disable Ptype parsing\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
ret = rte_eth_promiscuous_enable(portid);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"rte_eth_promiscuous_enable:err=%s, port=%u\n",
rte_strerror(-ret), portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
RTE_LCORE_FOREACH_WORKER(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
ret = rte_eth_dev_stop(portid);
if (ret != 0)
printf("rte_eth_dev_stop: err=%d, port=%d\n",
ret, portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
return ret;
}
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2016 Intel Corporation
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_string_fns.h>
#include <rte_udp.h>
#include <rte_ip.h>
#include <rte_hash.h>
#define CAPACITY 50000 // Size of the Hash Table
static volatile bool force_quit;
/* MAC updating enabled by default */
static int mac_updating = 1;
#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
#define MEMPOOL_CACHE_SIZE 256
/*
* Configurable number of RX/TX ring descriptors
*/
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/* ethernet addresses of ports */
static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;
/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
struct port_pair_params {
#define NUM_PORTS 2
uint16_t port[NUM_PORTS];
} __rte_cache_aligned;
static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2];
static struct port_pair_params *port_pair_params;
static uint16_t nb_port_pair_params;
static unsigned int l2fwd_rx_queue_per_lcore = 1;
#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf {
unsigned n_rx_port;
unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
} __rte_cache_aligned;
struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
/* Per-port statistics struct */
struct l2fwd_port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
static uint64_t timer_period = 10; /* default period is 10 seconds */
struct pkt_data {
uint16_t type;
uint16_t sep1;
uint16_t sep2;
uint16_t sep3;
uint32_t key;
uint16_t sep4;
uint16_t sep5;
uint16_t sep6;
uint32_t val;
};
struct HashTable* ht;
/* Print out statistics on packets dropped */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
unsigned portid;
total_packets_dropped = 0;
total_packets_tx = 0;
total_packets_rx = 0;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
/* Clear screen and move to top left */
printf("%s%s", clr, topLeft);
printf("\nPort statistics ====================================");
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
/* skip disabled ports */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
"\nPackets sent: %24"PRIu64
"\nPackets received: %20"PRIu64
"\nPackets dropped: %21"PRIu64,
portid,
port_statistics[portid].tx,
port_statistics[portid].rx,
port_statistics[portid].dropped);
total_packets_dropped += port_statistics[portid].dropped;
total_packets_tx += port_statistics[portid].tx;
total_packets_rx += port_statistics[portid].rx;
}
printf("\nAggregate statistics ==============================="
"\nTotal packets sent: %18"PRIu64
"\nTotal packets received: %14"PRIu64
"\nTotal packets dropped: %15"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
fflush(stdout);
}
/*
* Create the hash table that will contain the flows that
* the node will handle, which will be used to decide if packet
* is transmitted or dropped.
*/
/*static struct rte_hash *
create_hash_table(const struct shared_info *info)
{
//uint32_t num_flows_node = info->num_flows / info->num_nodes;
//char name[RTE_HASH_NAMESIZE];
struct rte_hash *h;
// create table
struct rte_hash_parameters hash_params = {
.entries = 100000,
.key_len = sizeof(uint32_t), // Store IPv4 dest IP address
.socket_id = rte_socket_id(),
.hash_func_init_val = 0,
};
hash_params.name = "ht";
h = rte_hash_create(&hash_params);
if (h == NULL)
rte_exit(EXIT_FAILURE,
"Problem creating the hash table \n");
return h;
}
static void
populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
{
unsigned int i;
int32_t ret;
uint32_t key;
// Add keys in table
for (i = 0; i < 100000; i++) {
key = rte_cpu_to_be_32(i);
ret = rte_hash_add_key(h, (void *) &key);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Unable to add entry %u "
"in hash table\n", i);
}
printf("Hash table: Adding keys\n");
}*/
unsigned long hash_function(char* str) {
unsigned long i = 0;
for (int j=0; str[j]; j++)
i += str[j];
return i % CAPACITY;
}
typedef struct Ht_item Ht_item;
// Define the Hash Table Item here
struct Ht_item {
char* key;
char* value;
};
typedef struct HashTable HashTable;
// Define the Hash Table here
struct HashTable {
// Contains an array of pointers
// to items
Ht_item** items;
int size;
int count;
};
Ht_item* create_item(char* key, char* value) {
// Creates a pointer to a new hash table item
Ht_item* item = (Ht_item*) malloc (sizeof(Ht_item));
item->key = (char*) malloc (strlen(key) + 1);
item->value = (char*) malloc (strlen(value) + 1);
strcpy(item->key, key);
strcpy(item->value, value);
return item;
}
HashTable* create_table(int size) {
// Creates a new HashTable
HashTable* table = (HashTable*) malloc (sizeof(HashTable));
table->size = size;
table->count = 0;
table->items = (Ht_item**) calloc (table->size, sizeof(Ht_item*));
for (int i=0; i<table->size; i++)
table->items[i] = NULL;
return table;
}
void free_item(Ht_item* item) {
// Frees an item
free(item->key);
free(item->value);
free(item);
}
void free_table(HashTable* table) {
// Frees the table
for (int i=0; i<table->size; i++) {
Ht_item* item = table->items[i];
if (item != NULL)
free_item(item);
}
free(table->items);
free(table);
}
void handle_collision(HashTable* table, unsigned long index, Ht_item* item) {
}
void ht_insert(HashTable* table, char* key, char* value) {
// Create the item
Ht_item* item = create_item(key, value);
// Compute the index
unsigned long index = hash_function(key);
Ht_item* current_item = table->items[index];
if (current_item == NULL) {
// Key does not exist.
if (table->count == table->size) {
// Hash Table Full
printf("Insert Error: Hash Table is full\n");
// Remove the create item
free_item(item);
return;
}
// Insert directly
table->items[index] = item;
table->count++;
}
else {
// Scenario 1: We only need to update value
if (strcmp(current_item->key, key) == 0) {
strcpy(table->items[index]->value, value);
return;
}
else {
// Scenario 2: Collision
// We will handle case this a bit later
handle_collision(table, index, item);
return;
}
}
}
char* ht_search(HashTable* table, char* key) {
// Searches the key in the hashtable
// and returns NULL if it doesn't exist
int index = hash_function(key);
Ht_item* item = table->items[index];
// Ensure that we move to a non NULL item
if (item != NULL) {
if (strcmp(item->key, key) == 0)
return item->value;
}
return NULL;
}
void print_search(HashTable* table, char* key) {
char* val;
if ((val = ht_search(table, key)) == NULL) {
printf("Key:%s does not exist\n", key);
return;
}
else {
printf("Key:%s, Value:%s\n", key, val);
}
}
void print_table(HashTable* table) {
printf("\nHash Table\n-------------------\n");
for (int i=0; i<table->size; i++) {
if (table->items[i]) {
printf("Index:%d, Key:%s, Value:%s\n", i, table->items[i]->key, table->items[i]->value);
}
}
printf("-------------------\n\n");
}
static void
l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid)
{
struct rte_ether_hdr *eth;
void *tmp;
//struct pkt_data *data;
eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
/* 02:00:00:00:00:xx */
/* 0c:42:a1:df:ac:40 41 */
tmp = &eth->d_addr.addr_bytes[0];
// @rinku
//*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
*((uint64_t *)tmp) = 0x40acdfa1420c + ((uint64_t)dest_portid << 56);
/* src addr */
rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->s_addr);
// @rinku
struct rte_ipv4_hdr *ipv4_hdr;
if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
uint32_t tmp_dst;
tmp_dst = ipv4_hdr->src_addr;
ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
ipv4_hdr->dst_addr = tmp_dst;
}
// @rinku
struct rte_udp_hdr *udp;
struct pkt_data *data;
if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
udp = (struct rte_udp_hdr *)((unsigned char *)ipv4_hdr + sizeof(struct rte_ipv4_hdr));
uint16_t port_dst = udp->dst_port;
udp->dst_port = udp->src_port;
udp->src_port = port_dst;
//printf("len= %d ", ntohs(udp->dgram_len));
data = (struct pkt_data *) ((unsigned char *)udp + sizeof(struct rte_udp_hdr));
if ((data != NULL) && (ntohs(data->type)==4)) {
//if (data != NULL) {
//printf("len= %d ", udp->dgram_len);
//printf("%x %x %x %x %d %x %x %x %d \n",ntohs(data->type), ntohs(data->sep1), ntohs(data->sep2), ntohs(data->sep3), ntohl(data->key), ntohs(data->sep4), ntohs(data->sep5), ntohs(data->sep6),ntohl(data->val));
//printf("key= %d val= %d \n",ntohl(data->key),ntohs(data->val));
char k[6];
sprintf(k, "%d", ntohl(data->key));
print_search(ht, k);
}
}
}
static void
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
{
unsigned dst_port;
int sent;
struct rte_eth_dev_tx_buffer *buffer;
dst_port = l2fwd_dst_ports[portid];
//printf("DEST PORT = %u", dst_port);
//@rinku
/*if (dst_port == 0)
dst_port = 1;
else if (dst_port == 1)
dst_port = 0;*/
if (mac_updating)
l2fwd_mac_updating(m, dst_port);
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
/* main processing loop */
static void
l2fwd_main_loop(void)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
ht = create_table(CAPACITY);
for (int i=0; i<CAPACITY; i++){
char k[6], v[6];
int val = i+1;
sprintf(k, "%d", i);
sprintf(v, "%d", val);
ht_insert(ht,k,v);
}
print_search(ht, "1234");
/*print_search(ht, "1");
print_search(ht, "2");
print_search(ht, "3");
print_table(ht);
free_table(ht);*/
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on main core */
if (lcore_id == rte_get_main_lcore()) {
print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid);
}
}
}
}
static int
l2fwd_launch_one_lcore(__rte_unused void *dummy)
{
l2fwd_main_loop();
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n"
" --portmap: Configure forwarding port pair mapping\n"
" Default: alternate port pairs\n\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
return pm;
}
static int
l2fwd_parse_port_pair_config(const char *q_arg)
{
enum fieldnames {
FLD_PORT1 = 0,
FLD_PORT2,
_NUM_FLD
};
unsigned long int_fld[_NUM_FLD];
const char *p, *p0 = q_arg;
char *str_fld[_NUM_FLD];
unsigned int size;
char s[256];
char *end;
int i;
nb_port_pair_params = 0;
while ((p = strchr(p0, '(')) != NULL) {
++p;
p0 = strchr(p, ')');
if (p0 == NULL)
return -1;
size = p0 - p;
if (size >= sizeof(s))
return -1;
memcpy(s, p, size);
s[size] = '\0';
if (rte_strsplit(s, sizeof(s), str_fld,
_NUM_FLD, ',') != _NUM_FLD)
return -1;
for (i = 0; i < _NUM_FLD; i++) {
errno = 0;
int_fld[i] = strtoul(str_fld[i], &end, 0);
if (errno != 0 || end == str_fld[i] ||
int_fld[i] >= RTE_MAX_ETHPORTS)
return -1;
}
if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
printf("exceeded max number of port pair params: %hu\n",
nb_port_pair_params);
return -1;
}
port_pair_params_array[nb_port_pair_params].port[0] =
(uint16_t)int_fld[FLD_PORT1];
port_pair_params_array[nb_port_pair_params].port[1] =
(uint16_t)int_fld[FLD_PORT2];
++nb_port_pair_params;
}
port_pair_params = port_pair_params_array;
return 0;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
#define CMD_LINE_OPT_PORTMAP_CONFIG "portmap"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
CMD_LINE_OPT_PORTMAP_NUM,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
port_pair_params = NULL;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case CMD_LINE_OPT_PORTMAP_NUM:
ret = l2fwd_parse_port_pair_config(optarg);
if (ret) {
fprintf(stderr, "Invalid config\n");
l2fwd_usage(prgname);
return -1;
}
break;
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/*
* Check port pair config with enabled port mask,
* and for valid port pair combinations.
*/
static int
check_port_pair_config(void)
{
uint32_t port_pair_config_mask = 0;
uint32_t port_pair_mask = 0;
uint16_t index, i, portid;
for (index = 0; index < nb_port_pair_params; index++) {
port_pair_mask = 0;
for (i = 0; i < NUM_PORTS; i++) {
portid = port_pair_params[index].port[i];
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("port %u is not enabled in port mask\n",
portid);
return -1;
}
if (!rte_eth_dev_is_valid_port(portid)) {
printf("port %u is not present on the board\n",
portid);
return -1;
}
port_pair_mask |= 1 << portid;
}
if (port_pair_config_mask & port_pair_mask) {
printf("port %u is used in other port pairs\n", portid);
return -1;
}
port_pair_config_mask |= port_pair_mask;
}
l2fwd_enabled_port_mask &= port_pair_config_mask;
return 0;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
int ret;
char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
ret = rte_eth_link_get_nowait(portid, &link);
if (ret < 0) {
all_ports_up = 0;
if (print_flag == 1)
printf("Port %u link get failed: %s\n",
portid, rte_strerror(-ret));
continue;
}
/* print link status if flag set */
if (print_flag == 1) {
rte_eth_link_to_str(link_status_text,
sizeof(link_status_text), &link);
printf("Port %d %s\n", portid,
link_status_text);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
main(int argc, char **argv)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
if (port_pair_params != NULL) {
if (check_port_pair_config() < 0)
rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
}
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/* populate destination port details */
if (port_pair_params != NULL) {
uint16_t idx, p;
for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
p = idx & 1;
portid = port_pair_params[idx >> 1].port[p];
l2fwd_dst_ports[portid] =
port_pair_params[idx >> 1].port[p ^ 1];
}
} else {
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
} else {
last_port = portid;
}
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
portid, l2fwd_dst_ports[portid]);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
ret = rte_eth_dev_info_get(portid, &dev_info);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
portid, strerror(-ret));
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_macaddr_get(portid,
&l2fwd_ports_eth_addr[portid]);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot get MAC address: err=%d, port=%u\n",
ret, portid);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
0);
if (ret < 0)
printf("Port %u, Failed to disable Ptype parsing\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
ret = rte_eth_promiscuous_enable(portid);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"rte_eth_promiscuous_enable:err=%s, port=%u\n",
rte_strerror(-ret), portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
RTE_LCORE_FOREACH_WORKER(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
ret = rte_eth_dev_stop(portid);
if (ret != 0)
printf("rte_eth_dev_stop: err=%d, port=%d\n",
ret, portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
print_table(ht);
free_table(ht);
return ret;
}
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2016 Intel Corporation
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_string_fns.h>
#include <rte_udp.h>
#include <rte_ip.h>
#include <rte_hash.h>
#define CAPACITY 50000 // Size of the Hash Table
static volatile bool force_quit;
/* MAC updating enabled by default */
static int mac_updating = 1;
#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
#define MAX_PKT_BURST 128 //64 //32
#define BURST_TX_DRAIN_US 50 //100 // TX drain every ~100us
#define MEMPOOL_CACHE_SIZE 512 //256
/*
* Configurable number of RX/TX ring descriptors
*/
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/* ethernet addresses of ports */
static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;
/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
struct port_pair_params {
#define NUM_PORTS 2
uint16_t port[NUM_PORTS];
} __rte_cache_aligned;
static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2];
static struct port_pair_params *port_pair_params;
static uint16_t nb_port_pair_params;
static unsigned int l2fwd_rx_queue_per_lcore = 1;
#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf {
unsigned n_rx_port;
unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
} __rte_cache_aligned;
struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
/* Per-port statistics struct */
struct l2fwd_port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
static uint64_t timer_period = 10; /* default period is 10 seconds */
struct pkt_data {
uint16_t type;
uint16_t sep1;
uint16_t sep2;
uint16_t sep3;
uint32_t key;
uint16_t sep4;
uint16_t sep5;
uint16_t sep6;
uint32_t val;
//char pad1[8];
};
struct HashTable* ht;
/* Print out statistics on packets dropped */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
unsigned portid;
total_packets_dropped = 0;
total_packets_tx = 0;
total_packets_rx = 0;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
/* Clear screen and move to top left */
printf("%s%s", clr, topLeft);
printf("\nPort statistics ====================================");
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
/* skip disabled ports */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
"\nPackets sent: %24"PRIu64
"\nPackets received: %20"PRIu64
"\nPackets dropped: %21"PRIu64,
portid,
port_statistics[portid].tx,
port_statistics[portid].rx,
port_statistics[portid].dropped);
total_packets_dropped += port_statistics[portid].dropped;
total_packets_tx += port_statistics[portid].tx;
total_packets_rx += port_statistics[portid].rx;
}
printf("\nAggregate statistics ==============================="
"\nTotal packets sent: %18"PRIu64
"\nTotal packets received: %14"PRIu64
"\nTotal packets dropped: %15"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
fflush(stdout);
}
unsigned long hash_function(char* str) {
unsigned long i = 0;
for (int j=0; str[j]; j++)
i += str[j];
return i % CAPACITY;
}
typedef struct Ht_item Ht_item;
// Define the Hash Table Item here
struct Ht_item {
char* key;
char* value;
};
typedef struct LinkedList LinkedList;
// Define the Linkedlist here
struct LinkedList {
Ht_item* item;
LinkedList* next;
};
typedef struct HashTable HashTable;
// Define the Hash Table here
struct HashTable {
// Contains an array of pointers
// to items
Ht_item** items;
LinkedList** overflow_buckets;
int size;
int count;
};
static LinkedList* allocate_list () {
// Allocates memory for a Linkedlist pointer
LinkedList* list = (LinkedList*) malloc (sizeof(LinkedList));
return list;
}
static LinkedList* linkedlist_insert(LinkedList* list, Ht_item* item) {
// Inserts the item onto the Linked List
if (!list) {
LinkedList* head = allocate_list();
head->item = item;
head->next = NULL;
list = head;
return list;
}
else if (list->next == NULL) {
LinkedList* node = allocate_list();
node->item = item;
node->next = NULL;
list->next = node;
return list;
}
LinkedList* temp = list;
// @rinku
while (temp->next) { //->next) {
temp = temp->next;
}
LinkedList* node = allocate_list();
node->item = item;
node->next = NULL;
temp->next = node;
return list;
}
static Ht_item* linkedlist_remove(LinkedList* list) {
// Removes the head from the linked list
// and returns the item of the popped element
if (!list)
return NULL;
if (!list->next)
return NULL;
LinkedList* node = list->next;
LinkedList* temp = list;
temp->next = NULL;
list = node;
Ht_item* it = NULL;
memcpy(temp->item, it, sizeof(Ht_item));
free(temp->item->key);
free(temp->item->value);
free(temp->item);
free(temp);
return it;
}
static void free_linkedlist(LinkedList* list) {
LinkedList* temp = list;
while (list) {
temp = list;
list = list->next;
free(temp->item->key);
free(temp->item->value);
free(temp->item);
free(temp);
}
}
static LinkedList** create_overflow_buckets(HashTable* table) {
// Create the overflow buckets; an array of linkedlists
LinkedList** buckets = (LinkedList**) calloc (table->size, sizeof(LinkedList*));
for (int i=0; i<table->size; i++)
buckets[i] = NULL;
return buckets;
}
static void free_overflow_buckets(HashTable* table) {
// Free all the overflow bucket lists
LinkedList** buckets = table->overflow_buckets;
for (int i=0; i<table->size; i++)
free_linkedlist(buckets[i]);
free(buckets);
}
Ht_item* create_item(char* key, char* value) {
// Creates a pointer to a new hash table item
Ht_item* item = (Ht_item*) malloc (sizeof(Ht_item));
item->key = (char*) malloc (strlen(key) + 1);
item->value = (char*) malloc (strlen(value) + 1);
strcpy(item->key, key);
strcpy(item->value, value);
return item;
}
HashTable* create_table(int size) {
// Creates a new HashTable
HashTable* table = (HashTable*) malloc (sizeof(HashTable));
table->size = size;
table->count = 0;
table->items = (Ht_item**) calloc (table->size, sizeof(Ht_item*));
for (int i=0; i<table->size; i++)
table->items[i] = NULL;
table->overflow_buckets = create_overflow_buckets(table);
return table;
}
void free_item(Ht_item* item) {
// Frees an item
free(item->key);
free(item->value);
free(item);
}
void free_table(HashTable* table) {
// Frees the table
for (int i=0; i<table->size; i++) {
Ht_item* item = table->items[i];
if (item != NULL)
free_item(item);
}
free_overflow_buckets(table);
free(table->items);
free(table);
}
void handle_collision(HashTable* table, unsigned long index, Ht_item* item) {
LinkedList* head = table->overflow_buckets[index];
if (head == NULL) {
// We need to create the list
head = allocate_list();
head->item = item;
table->overflow_buckets[index] = head;
return;
}
else {
// Insert to the list
table->overflow_buckets[index] = linkedlist_insert(head, item);
return;
}
}
void ht_insert(HashTable* table, char* key, char* value) {
// Create the item
Ht_item* item = create_item(key, value);
// Compute the index
unsigned long index = hash_function(key);
Ht_item* current_item = table->items[index];
//if (strcmp(key,"1234") == 0)
// printf("%s %s %ld \n", key, value, index);
if (current_item == NULL) {
// Key does not exist.
if (table->count == table->size) {
// Hash Table Full
printf("Insert Error: Hash Table is full\n");
// Remove the create item
free_item(item);
return;
}
// Insert directly
table->items[index] = item;
table->count++;
}
else {
// Scenario 1: We only need to update value
if (strcmp(current_item->key, key) == 0) {
strcpy(table->items[index]->value, value);
return;
}
else {
// Scenario 2: Collision
handle_collision(table, index, item);
return;
}
}
}
char* ht_search(HashTable* table, char* key) {
// Searches the key in the hashtable
// and returns NULL if it doesn't exist
int index = hash_function(key);
Ht_item* item = table->items[index];
LinkedList* head = table->overflow_buckets[index];
// Ensure that we move to items which are not NULL
while (item != NULL) {
if (strcmp(item->key, key) == 0)
return item->value;
if (head == NULL)
return NULL;
item = head->item;
head = head->next;
}
return NULL;
}
void ht_delete(HashTable* table, char* key) {
// Deletes an item from the table
int index = hash_function(key);
Ht_item* item = table->items[index];
LinkedList* head = table->overflow_buckets[index];
if (item == NULL) {
// Does not exist. Return
return;
}
else {
if (head == NULL && strcmp(item->key, key) == 0) {
// No collision chain. Remove the item
// and set table index to NULL
table->items[index] = NULL;
free_item(item);
table->count--;
return;
}
else if (head != NULL) {
// Collision Chain exists
if (strcmp(item->key, key) == 0) {
// Remove this item and set the head of the list
// as the new item
free_item(item);
LinkedList* node = head;
head = head->next;
node->next = NULL;
table->items[index] = create_item(node->item->key, node->item->value);
free_linkedlist(node);
table->overflow_buckets[index] = head;
return;
}
LinkedList* curr = head;
LinkedList* prev = NULL;
while (curr) {
if (strcmp(curr->item->key, key) == 0) {
if (prev == NULL) {
// First element of the chain. Remove the chain
free_linkedlist(head);
table->overflow_buckets[index] = NULL;
return;
}
else {
// This is somewhere in the chain
prev->next = curr->next;
curr->next = NULL;
free_linkedlist(curr);
table->overflow_buckets[index] = head;
return;
}
}
curr = curr->next;
prev = curr;
}
}
}
}
void print_search(HashTable* table, char* key) {
char* val;
if ((val = ht_search(table, key)) == NULL) {
printf("%s does not exist\n", key);
return;
}
else {
printf("Key:%s, Value:%s\n", key, val);
}
}
char* return_search(HashTable* table, char* key) {
char* val;
if ((val = ht_search(table, key)) == NULL) {
//printf("%s does not exist\n", key);
return "0";
}
else {
//printf("Key:%s, Value:%s\n", key, val);
return val;
}
}
void print_table(HashTable* table) {
printf("\n-------------------\n");
for (int i=0; i<table->size; i++) {
if (table->items[i]) {
printf("Index:%d, Key:%s, Value:%s", i, table->items[i]->key, table->items[i]->value);
if (table->overflow_buckets[i]) {
printf(" => Overflow Bucket => ");
LinkedList* head = table->overflow_buckets[i];
while (head) {
printf("Key:%s, Value:%s ", head->item->key, head->item->value);
head = head->next;
}
}
printf("\n");
}
}
printf("-------------------\n");
}
static void
l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid)
{
struct rte_ether_hdr *eth;
void *tmp;
//struct pkt_data *data;
eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
/* 02:00:00:00:00:xx */
/* 0c:42:a1:df:ac:40 41 */
tmp = &eth->d_addr.addr_bytes[0];
// @rinku
//*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
*((uint64_t *)tmp) = 0x40acdfa1420c + ((uint64_t)dest_portid << 56);
/* src addr */
rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->s_addr);
// @rinku
struct rte_ipv4_hdr *ipv4_hdr;
if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
uint32_t tmp_dst;
tmp_dst = ipv4_hdr->src_addr;
ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
ipv4_hdr->dst_addr = tmp_dst;
}
// @rinku
struct rte_udp_hdr *udp;
struct pkt_data *data;
if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
udp = (struct rte_udp_hdr *)((unsigned char *)ipv4_hdr + sizeof(struct rte_ipv4_hdr));
uint16_t port_dst = udp->dst_port;
udp->dst_port = udp->src_port;
udp->src_port = port_dst;
//printf("len= %d ", ntohs(udp->dgram_len));
data = (struct pkt_data *) ((unsigned char *)udp + sizeof(struct rte_udp_hdr));
if ((data != NULL) && (ntohs(data->type)==4)) {
//if (data != NULL) {
//printf("len= %d ", udp->dgram_len);
//printf("%x %x %x %x %d %x %x %x %d \n",ntohs(data->type), ntohs(data->sep1), ntohs(data->sep2), ntohs(data->sep3), ntohl(data->key), ntohs(data->sep4), ntohs(data->sep5), ntohs(data->sep6),ntohl(data->val));
//printf("key= %d val= %d \n",ntohl(data->key),ntohs(data->val));
char k[6]; // v[6];
sprintf(k, "%d", ntohl(data->key));
char* v = return_search(ht, k);
uint32_t tmp_val = atoi(v);
//sprintf(tmp_val, "%s", v);
data->val = htons(tmp_val);
//sprintf(data->pad1, "%d", 12345678);
}
}
}
static void
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
{
unsigned dst_port;
int sent;
struct rte_eth_dev_tx_buffer *buffer;
dst_port = l2fwd_dst_ports[portid];
//printf("DEST PORT = %u", dst_port);
//@rinku
/*if (dst_port == 0)
dst_port = 1;
else if (dst_port == 1)
dst_port = 0;*/
if (mac_updating)
l2fwd_mac_updating(m, dst_port);
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
// @rinku
// Function to convert integer to
// character array
/* char* convertIntegerToChar(int N)
{
// Count digits in number N
int m = N;
int digit = 0;
while (m) {
// Increment number of digits
digit++;
// Truncate the last
// digit from the number
m /= 10;
}
// Declare char array for result
char* arr;
// Declare duplicate char array
char arr1[digit];
// Memory allocaton of array
arr = (char*)malloc(digit);
// Separating integer into digits and
// accomodate it to character array
int index = 0;
while (N) {
// Separate last digit from
// the number and add ASCII
// value of character '0' is 48
arr1[++index] = N % 10 + '0';
// Truncate the last
// digit from the number
N /= 10;
}
// Reverse the array for result
int i;
for (i = 0; i < index; i++) {
arr[i] = arr1[index - i];
}
// Char array truncate by null
arr[i] = '\0';
// Return char array
return (char*)arr;
}*/
/* main processing loop */
static void
l2fwd_main_loop(void)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
ht = create_table(CAPACITY);
//ht_insert(ht,"1234","1235");
for (int i=0; i<CAPACITY; i++){
char k[7], v[7];
int val = i+1;
sprintf(k, "%d", i);
sprintf(v, "%d", val);
ht_insert(ht,k,v);
}
print_search(ht, "1234");
/*print_search(ht, "1");
print_search(ht, "2");
print_search(ht, "3");
print_table(ht);
free_table(ht);*/
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on main core */
if (lcore_id == rte_get_main_lcore()) {
print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid);
}
}
}
}
static int
l2fwd_launch_one_lcore(__rte_unused void *dummy)
{
l2fwd_main_loop();
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n"
" --portmap: Configure forwarding port pair mapping\n"
" Default: alternate port pairs\n\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
return pm;
}
static int
l2fwd_parse_port_pair_config(const char *q_arg)
{
enum fieldnames {
FLD_PORT1 = 0,
FLD_PORT2,
_NUM_FLD
};
unsigned long int_fld[_NUM_FLD];
const char *p, *p0 = q_arg;
char *str_fld[_NUM_FLD];
unsigned int size;
char s[256];
char *end;
int i;
nb_port_pair_params = 0;
while ((p = strchr(p0, '(')) != NULL) {
++p;
p0 = strchr(p, ')');
if (p0 == NULL)
return -1;
size = p0 - p;
if (size >= sizeof(s))
return -1;
memcpy(s, p, size);
s[size] = '\0';
if (rte_strsplit(s, sizeof(s), str_fld,
_NUM_FLD, ',') != _NUM_FLD)
return -1;
for (i = 0; i < _NUM_FLD; i++) {
errno = 0;
int_fld[i] = strtoul(str_fld[i], &end, 0);
if (errno != 0 || end == str_fld[i] ||
int_fld[i] >= RTE_MAX_ETHPORTS)
return -1;
}
if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
printf("exceeded max number of port pair params: %hu\n",
nb_port_pair_params);
return -1;
}
port_pair_params_array[nb_port_pair_params].port[0] =
(uint16_t)int_fld[FLD_PORT1];
port_pair_params_array[nb_port_pair_params].port[1] =
(uint16_t)int_fld[FLD_PORT2];
++nb_port_pair_params;
}
port_pair_params = port_pair_params_array;
return 0;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
#define CMD_LINE_OPT_PORTMAP_CONFIG "portmap"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
CMD_LINE_OPT_PORTMAP_NUM,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
port_pair_params = NULL;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case CMD_LINE_OPT_PORTMAP_NUM:
ret = l2fwd_parse_port_pair_config(optarg);
if (ret) {
fprintf(stderr, "Invalid config\n");
l2fwd_usage(prgname);
return -1;
}
break;
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/*
* Check port pair config with enabled port mask,
* and for valid port pair combinations.
*/
static int
check_port_pair_config(void)
{
uint32_t port_pair_config_mask = 0;
uint32_t port_pair_mask = 0;
uint16_t index, i, portid;
for (index = 0; index < nb_port_pair_params; index++) {
port_pair_mask = 0;
for (i = 0; i < NUM_PORTS; i++) {
portid = port_pair_params[index].port[i];
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("port %u is not enabled in port mask\n",
portid);
return -1;
}
if (!rte_eth_dev_is_valid_port(portid)) {
printf("port %u is not present on the board\n",
portid);
return -1;
}
port_pair_mask |= 1 << portid;
}
if (port_pair_config_mask & port_pair_mask) {
printf("port %u is used in other port pairs\n", portid);
return -1;
}
port_pair_config_mask |= port_pair_mask;
}
l2fwd_enabled_port_mask &= port_pair_config_mask;
return 0;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
int ret;
char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
ret = rte_eth_link_get_nowait(portid, &link);
if (ret < 0) {
all_ports_up = 0;
if (print_flag == 1)
printf("Port %u link get failed: %s\n",
portid, rte_strerror(-ret));
continue;
}
/* print link status if flag set */
if (print_flag == 1) {
rte_eth_link_to_str(link_status_text,
sizeof(link_status_text), &link);
printf("Port %d %s\n", portid,
link_status_text);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
main(int argc, char **argv)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
if (port_pair_params != NULL) {
if (check_port_pair_config() < 0)
rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
}
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/* populate destination port details */
if (port_pair_params != NULL) {
uint16_t idx, p;
for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
p = idx & 1;
portid = port_pair_params[idx >> 1].port[p];
l2fwd_dst_ports[portid] =
port_pair_params[idx >> 1].port[p ^ 1];
}
} else {
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
} else {
last_port = portid;
}
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
portid, l2fwd_dst_ports[portid]);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
ret = rte_eth_dev_info_get(portid, &dev_info);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
portid, strerror(-ret));
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_macaddr_get(portid,
&l2fwd_ports_eth_addr[portid]);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot get MAC address: err=%d, port=%u\n",
ret, portid);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
0);
if (ret < 0)
printf("Port %u, Failed to disable Ptype parsing\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
ret = rte_eth_promiscuous_enable(portid);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"rte_eth_promiscuous_enable:err=%s, port=%u\n",
rte_strerror(-ret), portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
RTE_LCORE_FOREACH_WORKER(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
ret = rte_eth_dev_stop(portid);
if (ret != 0)
printf("rte_eth_dev_stop: err=%d, port=%d\n",
ret, portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
//print_table(ht);
free_table(ht);
return ret;
}
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2017 Intel Corporation
# meson file, for building this example as part of a main DPDK build.
#
# To build this example as a standalone application with an already-installed
# DPDK instance, use 'make'
# Enable experimental API flag as l2fwd uses rte_ethdev_set_ptype API
allow_experimental_apis = true
sources = files(
'main.c'
)
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2014 Intel Corporation
# binary name
APP = l2fwd
# all source are stored in SRCS-y
SRCS-y := main.c
# Build using pkg-config variables if possible
ifneq ($(shell pkg-config --exists libdpdk && echo 0),0)
$(error "no installation of DPDK found")
endif
all: shared
.PHONY: shared static
shared: build/$(APP)-shared
ln -sf $(APP)-shared build/$(APP)
static: build/$(APP)-static
ln -sf $(APP)-static build/$(APP)
PKGCONF ?= pkg-config
PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null)
CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk)
# Add flag to allow experimental API as l2fwd uses rte_ethdev_set_ptype API
CFLAGS += -DALLOW_EXPERIMENTAL_API
LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)
LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk)
build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)
build:
@mkdir -p $@
.PHONY: clean
clean:
rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
test -d build && rmdir -p build || true
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2016 Intel Corporation
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_string_fns.h>
#include <rte_udp.h>
#include <rte_ip.h>
static volatile bool force_quit;
/* MAC updating enabled by default */
static int mac_updating = 1;
#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
#define MEMPOOL_CACHE_SIZE 256
/*
* Configurable number of RX/TX ring descriptors
*/
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/* ethernet addresses of ports */
static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;
/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
struct port_pair_params {
#define NUM_PORTS 2
uint16_t port[NUM_PORTS];
} __rte_cache_aligned;
static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2];
static struct port_pair_params *port_pair_params;
static uint16_t nb_port_pair_params;
static unsigned int l2fwd_rx_queue_per_lcore = 1;
#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf {
unsigned n_rx_port;
unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
} __rte_cache_aligned;
struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
/* Per-port statistics struct */
struct l2fwd_port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
static uint64_t timer_period = 10; /* default period is 10 seconds */
/* Print out statistics on packets dropped */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
unsigned portid;
total_packets_dropped = 0;
total_packets_tx = 0;
total_packets_rx = 0;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
/* Clear screen and move to top left */
printf("%s%s", clr, topLeft);
printf("\nPort statistics ====================================");
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
/* skip disabled ports */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("\nStatistics for port %u ------------------------------"
"\nPackets sent: %24"PRIu64
"\nPackets received: %20"PRIu64
"\nPackets dropped: %21"PRIu64,
portid,
port_statistics[portid].tx,
port_statistics[portid].rx,
port_statistics[portid].dropped);
total_packets_dropped += port_statistics[portid].dropped;
total_packets_tx += port_statistics[portid].tx;
total_packets_rx += port_statistics[portid].rx;
}
printf("\nAggregate statistics ==============================="
"\nTotal packets sent: %18"PRIu64
"\nTotal packets received: %14"PRIu64
"\nTotal packets dropped: %15"PRIu64,
total_packets_tx,
total_packets_rx,
total_packets_dropped);
printf("\n====================================================\n");
fflush(stdout);
}
static void
l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid)
{
struct rte_ether_hdr *eth;
void *tmp;
eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
/* 02:00:00:00:00:xx */
/* 0c:42:a1:df:ac:40 41 */
tmp = &eth->d_addr.addr_bytes[0];
// @rinku
//*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
*((uint64_t *)tmp) = 0x40acdfa1420c + ((uint64_t)dest_portid << 56);
/* src addr */
rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->s_addr);
// @rinku
struct rte_ipv4_hdr *ipv4_hdr;
if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
uint32_t tmp_dst;
tmp_dst = ipv4_hdr->src_addr;
ipv4_hdr->src_addr = ipv4_hdr->dst_addr;
ipv4_hdr->dst_addr = tmp_dst;
}
// @rinku
struct rte_udp_hdr *udp;
if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
udp = (struct rte_udp_hdr *)((unsigned char *)ipv4_hdr + sizeof(struct rte_ipv4_hdr));
uint16_t port_dst = udp->dst_port;
udp->dst_port = udp->src_port;
udp->src_port = port_dst;
}
}
static void
l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
{
unsigned dst_port;
int sent;
struct rte_eth_dev_tx_buffer *buffer;
dst_port = l2fwd_dst_ports[portid];
//printf("DEST PORT = %u", dst_port);
//@rinku
/*if (dst_port == 0)
dst_port = 1;
else if (dst_port == 1)
dst_port = 0;*/
if (mac_updating)
l2fwd_mac_updating(m, dst_port);
buffer = tx_buffer[dst_port];
sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
if (sent)
port_statistics[dst_port].tx += sent;
}
/* main processing loop */
static void
l2fwd_main_loop(void)
{
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
struct rte_mbuf *m;
int sent;
unsigned lcore_id;
uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
unsigned i, j, portid, nb_rx;
struct lcore_queue_conf *qconf;
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
BURST_TX_DRAIN_US;
struct rte_eth_dev_tx_buffer *buffer;
prev_tsc = 0;
timer_tsc = 0;
lcore_id = rte_lcore_id();
qconf = &lcore_queue_conf[lcore_id];
if (qconf->n_rx_port == 0) {
RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
return;
}
RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
portid);
}
while (!force_quit) {
cur_tsc = rte_rdtsc();
/*
* TX burst queue drain
*/
diff_tsc = cur_tsc - prev_tsc;
if (unlikely(diff_tsc > drain_tsc)) {
for (i = 0; i < qconf->n_rx_port; i++) {
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
if (sent)
port_statistics[portid].tx += sent;
}
/* if timer is enabled */
if (timer_period > 0) {
/* advance the timer */
timer_tsc += diff_tsc;
/* if timer has reached its timeout */
if (unlikely(timer_tsc >= timer_period)) {
/* do this only on main core */
if (lcore_id == rte_get_main_lcore()) {
print_stats();
/* reset the timer */
timer_tsc = 0;
}
}
}
prev_tsc = cur_tsc;
}
/*
* Read packet from RX queues
*/
for (i = 0; i < qconf->n_rx_port; i++) {
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_rx_burst(portid, 0,
pkts_burst, MAX_PKT_BURST);
port_statistics[portid].rx += nb_rx;
for (j = 0; j < nb_rx; j++) {
m = pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m, void *));
l2fwd_simple_forward(m, portid);
}
}
}
}
static int
l2fwd_launch_one_lcore(__rte_unused void *dummy)
{
l2fwd_main_loop();
return 0;
}
/* display usage */
static void
l2fwd_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -q NQ: number of queue (=ports) per lcore (default is 1)\n"
" -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
" --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
" When enabled:\n"
" - The source MAC address is replaced by the TX port MAC address\n"
" - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n"
" --portmap: Configure forwarding port pair mapping\n"
" Default: alternate port pairs\n\n",
prgname);
}
static int
l2fwd_parse_portmask(const char *portmask)
{
char *end = NULL;
unsigned long pm;
/* parse hexadecimal string */
pm = strtoul(portmask, &end, 16);
if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
return pm;
}
static int
l2fwd_parse_port_pair_config(const char *q_arg)
{
enum fieldnames {
FLD_PORT1 = 0,
FLD_PORT2,
_NUM_FLD
};
unsigned long int_fld[_NUM_FLD];
const char *p, *p0 = q_arg;
char *str_fld[_NUM_FLD];
unsigned int size;
char s[256];
char *end;
int i;
nb_port_pair_params = 0;
while ((p = strchr(p0, '(')) != NULL) {
++p;
p0 = strchr(p, ')');
if (p0 == NULL)
return -1;
size = p0 - p;
if (size >= sizeof(s))
return -1;
memcpy(s, p, size);
s[size] = '\0';
if (rte_strsplit(s, sizeof(s), str_fld,
_NUM_FLD, ',') != _NUM_FLD)
return -1;
for (i = 0; i < _NUM_FLD; i++) {
errno = 0;
int_fld[i] = strtoul(str_fld[i], &end, 0);
if (errno != 0 || end == str_fld[i] ||
int_fld[i] >= RTE_MAX_ETHPORTS)
return -1;
}
if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
printf("exceeded max number of port pair params: %hu\n",
nb_port_pair_params);
return -1;
}
port_pair_params_array[nb_port_pair_params].port[0] =
(uint16_t)int_fld[FLD_PORT1];
port_pair_params_array[nb_port_pair_params].port[1] =
(uint16_t)int_fld[FLD_PORT2];
++nb_port_pair_params;
}
port_pair_params = port_pair_params_array;
return 0;
}
static unsigned int
l2fwd_parse_nqueue(const char *q_arg)
{
char *end = NULL;
unsigned long n;
/* parse hexadecimal string */
n = strtoul(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return 0;
if (n == 0)
return 0;
if (n >= MAX_RX_QUEUE_PER_LCORE)
return 0;
return n;
}
static int
l2fwd_parse_timer_period(const char *q_arg)
{
char *end = NULL;
int n;
/* parse number string */
n = strtol(q_arg, &end, 10);
if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
return -1;
if (n >= MAX_TIMER_PERIOD)
return -1;
return n;
}
static const char short_options[] =
"p:" /* portmask */
"q:" /* number of queues */
"T:" /* timer period */
;
#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
#define CMD_LINE_OPT_PORTMAP_CONFIG "portmap"
enum {
/* long options mapped to a short option */
/* first long only option value must be >= 256, so that we won't
* conflict with short options */
CMD_LINE_OPT_MIN_NUM = 256,
CMD_LINE_OPT_PORTMAP_NUM,
};
static const struct option lgopts[] = {
{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
{NULL, 0, 0, 0}
};
/* Parse the argument given in the command line of the application */
static int
l2fwd_parse_args(int argc, char **argv)
{
int opt, ret, timer_secs;
char **argvopt;
int option_index;
char *prgname = argv[0];
argvopt = argv;
port_pair_params = NULL;
while ((opt = getopt_long(argc, argvopt, short_options,
lgopts, &option_index)) != EOF) {
switch (opt) {
/* portmask */
case 'p':
l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
if (l2fwd_enabled_port_mask == 0) {
printf("invalid portmask\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* nqueue */
case 'q':
l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
if (l2fwd_rx_queue_per_lcore == 0) {
printf("invalid queue number\n");
l2fwd_usage(prgname);
return -1;
}
break;
/* timer period */
case 'T':
timer_secs = l2fwd_parse_timer_period(optarg);
if (timer_secs < 0) {
printf("invalid timer period\n");
l2fwd_usage(prgname);
return -1;
}
timer_period = timer_secs;
break;
/* long options */
case CMD_LINE_OPT_PORTMAP_NUM:
ret = l2fwd_parse_port_pair_config(optarg);
if (ret) {
fprintf(stderr, "Invalid config\n");
l2fwd_usage(prgname);
return -1;
}
break;
default:
l2fwd_usage(prgname);
return -1;
}
}
if (optind >= 0)
argv[optind-1] = prgname;
ret = optind-1;
optind = 1; /* reset getopt lib */
return ret;
}
/*
* Check port pair config with enabled port mask,
* and for valid port pair combinations.
*/
static int
check_port_pair_config(void)
{
uint32_t port_pair_config_mask = 0;
uint32_t port_pair_mask = 0;
uint16_t index, i, portid;
for (index = 0; index < nb_port_pair_params; index++) {
port_pair_mask = 0;
for (i = 0; i < NUM_PORTS; i++) {
portid = port_pair_params[index].port[i];
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("port %u is not enabled in port mask\n",
portid);
return -1;
}
if (!rte_eth_dev_is_valid_port(portid)) {
printf("port %u is not present on the board\n",
portid);
return -1;
}
port_pair_mask |= 1 << portid;
}
if (port_pair_config_mask & port_pair_mask) {
printf("port %u is used in other port pairs\n", portid);
return -1;
}
port_pair_config_mask |= port_pair_mask;
}
l2fwd_enabled_port_mask &= port_pair_config_mask;
return 0;
}
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status(uint32_t port_mask)
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
uint16_t portid;
uint8_t count, all_ports_up, print_flag = 0;
struct rte_eth_link link;
int ret;
char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
printf("\nChecking link status");
fflush(stdout);
for (count = 0; count <= MAX_CHECK_TIME; count++) {
if (force_quit)
return;
all_ports_up = 1;
RTE_ETH_FOREACH_DEV(portid) {
if (force_quit)
return;
if ((port_mask & (1 << portid)) == 0)
continue;
memset(&link, 0, sizeof(link));
ret = rte_eth_link_get_nowait(portid, &link);
if (ret < 0) {
all_ports_up = 0;
if (print_flag == 1)
printf("Port %u link get failed: %s\n",
portid, rte_strerror(-ret));
continue;
}
/* print link status if flag set */
if (print_flag == 1) {
rte_eth_link_to_str(link_status_text,
sizeof(link_status_text), &link);
printf("Port %d %s\n", portid,
link_status_text);
continue;
}
/* clear all_ports_up flag if any link down */
if (link.link_status == ETH_LINK_DOWN) {
all_ports_up = 0;
break;
}
}
/* after finally printing all link status, get out */
if (print_flag == 1)
break;
if (all_ports_up == 0) {
printf(".");
fflush(stdout);
rte_delay_ms(CHECK_INTERVAL);
}
/* set the print_flag if all ports up or timeout */
if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
print_flag = 1;
printf("done\n");
}
}
}
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
force_quit = true;
}
}
int
main(int argc, char **argv)
{
struct lcore_queue_conf *qconf;
int ret;
uint16_t nb_ports;
uint16_t nb_ports_available = 0;
uint16_t portid, last_port;
unsigned lcore_id, rx_lcore_id;
unsigned nb_ports_in_mask = 0;
unsigned int nb_lcores = 0;
unsigned int nb_mbufs;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* parse application arguments (after the EAL ones) */
ret = l2fwd_parse_args(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
/* convert to number of cycles */
timer_period *= rte_get_timer_hz();
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0)
rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
if (port_pair_params != NULL) {
if (check_port_pair_config() < 0)
rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
}
/* check port mask to possible port mask */
if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
(1 << nb_ports) - 1);
/* reset l2fwd_dst_ports */
for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
l2fwd_dst_ports[portid] = 0;
last_port = 0;
/* populate destination port details */
if (port_pair_params != NULL) {
uint16_t idx, p;
for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
p = idx & 1;
portid = port_pair_params[idx >> 1].port[p];
l2fwd_dst_ports[portid] =
port_pair_params[idx >> 1].port[p ^ 1];
}
} else {
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
if (nb_ports_in_mask % 2) {
l2fwd_dst_ports[portid] = last_port;
l2fwd_dst_ports[last_port] = portid;
} else {
last_port = portid;
}
nb_ports_in_mask++;
}
if (nb_ports_in_mask % 2) {
printf("Notice: odd number of ports in portmask.\n");
l2fwd_dst_ports[last_port] = last_port;
}
}
rx_lcore_id = 0;
qconf = NULL;
/* Initialize the port/queue configuration of each logical core */
RTE_ETH_FOREACH_DEV(portid) {
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
/* get the lcore_id for this port */
while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
lcore_queue_conf[rx_lcore_id].n_rx_port ==
l2fwd_rx_queue_per_lcore) {
rx_lcore_id++;
if (rx_lcore_id >= RTE_MAX_LCORE)
rte_exit(EXIT_FAILURE, "Not enough cores\n");
}
if (qconf != &lcore_queue_conf[rx_lcore_id]) {
/* Assigned a new logical core in the loop above. */
qconf = &lcore_queue_conf[rx_lcore_id];
nb_lcores++;
}
qconf->rx_port_list[qconf->n_rx_port] = portid;
qconf->n_rx_port++;
printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
portid, l2fwd_dst_ports[portid]);
}
nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
/* create the mbuf pool */
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
rte_socket_id());
if (l2fwd_pktmbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
/* Initialise each port */
RTE_ETH_FOREACH_DEV(portid) {
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
struct rte_eth_conf local_port_conf = port_conf;
struct rte_eth_dev_info dev_info;
/* skip ports that are not enabled */
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
printf("Skipping disabled port %u\n", portid);
continue;
}
nb_ports_available++;
/* init port */
printf("Initializing port %u... ", portid);
fflush(stdout);
ret = rte_eth_dev_info_get(portid, &dev_info);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
portid, strerror(-ret));
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
&nb_txd);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot adjust number of descriptors: err=%d, port=%u\n",
ret, portid);
ret = rte_eth_macaddr_get(portid,
&l2fwd_ports_eth_addr[portid]);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot get MAC address: err=%d, port=%u\n",
ret, portid);
/* init one RX queue */
fflush(stdout);
rxq_conf = dev_info.default_rxconf;
rxq_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid),
&rxq_conf,
l2fwd_pktmbuf_pool);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* init one TX queue on each port */
fflush(stdout);
txq_conf = dev_info.default_txconf;
txq_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid),
&txq_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
ret, portid);
/* Initialize TX buffers */
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
if (tx_buffer[portid] == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
portid);
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
if (ret < 0)
rte_exit(EXIT_FAILURE,
"Cannot set error callback for tx buffer on port %u\n",
portid);
ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
0);
if (ret < 0)
printf("Port %u, Failed to disable Ptype parsing\n",
portid);
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, portid);
printf("done: \n");
ret = rte_eth_promiscuous_enable(portid);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"rte_eth_promiscuous_enable:err=%s, port=%u\n",
rte_strerror(-ret), portid);
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
portid,
l2fwd_ports_eth_addr[portid].addr_bytes[0],
l2fwd_ports_eth_addr[portid].addr_bytes[1],
l2fwd_ports_eth_addr[portid].addr_bytes[2],
l2fwd_ports_eth_addr[portid].addr_bytes[3],
l2fwd_ports_eth_addr[portid].addr_bytes[4],
l2fwd_ports_eth_addr[portid].addr_bytes[5]);
/* initialize port stats */
memset(&port_statistics, 0, sizeof(port_statistics));
}
if (!nb_ports_available) {
rte_exit(EXIT_FAILURE,
"All available ports are disabled. Please set portmask.\n");
}
check_all_ports_link_status(l2fwd_enabled_port_mask);
ret = 0;
/* launch per-lcore init on every lcore */
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
RTE_LCORE_FOREACH_WORKER(lcore_id) {
if (rte_eal_wait_lcore(lcore_id) < 0) {
ret = -1;
break;
}
}
RTE_ETH_FOREACH_DEV(portid) {
if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
continue;
printf("Closing port %d...", portid);
ret = rte_eth_dev_stop(portid);
if (ret != 0)
printf("rte_eth_dev_stop: err=%d, port=%d\n",
ret, portid);
rte_eth_dev_close(portid);
printf(" Done\n");
}
printf("Bye...\n");
return ret;
}
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2017 Intel Corporation
# meson file, for building this example as part of a main DPDK build.
#
# To build this example as a standalone application with an already-installed
# DPDK instance, use 'make'
# Enable experimental API flag as l2fwd uses rte_ethdev_set_ptype API
allow_experimental_apis = true
sources = files(
'main.c'
)
#include "client.h"
#define NO_EPOCH 6
#define INST_ARR_LEN 300
#define INST_PERIOD 10 // period in secs
struct _threadArgs {
int threadId;
int num_threads;
};
struct _srcPortArgs {
int startingPort;
int endingPort;
int numPorts;
};
int flowWeight; // Number of messages send for encryption/decryption per connection
vector<unsigned long long> num_req_per_thread_P, num_req_per_thread_G, num_req_per_thread;
vector<unsigned long long> response_time_P, response_time_G, response_time;
struct timeval start; // Simulation start time
time_t endTime; // Simulation end time
long mtime, useconds, seconds; //For resp time calc
double num_ue_inst[INST_ARR_LEN] = {0}; // Enough to store 50 min data if captured after every 10 sec
double resp_time_inst[INST_ARR_LEN] = {0}; // Enough to store 50 min data if captured after every 10 sec
int instIndex = 0; // Index to remember number of entries in instr arrays
time_t inst_endTime; //End time of instrumenting current period (10sec)
unsigned long long prev_tpt = 0; //To remember tpt till previous period
unsigned long long prev_lat = 0; //To remember lat till previous period
/// DYNAMIC LOAD GENERATOR VARIABLES START HERE ///
std::mutex traffic_mtx;
std::mutex inst_mtx;
std::mutex lat_mtx;
int traffic_shape_size = NO_EPOCH;
//0---5:95
//1---10_80
//2---18_82
//3---25_75
//4---50_50
//5---66_34
//6---75_25
//7---100_1
//traffic_shape[][] = {{time,mix_num}}
int traffic_shape[10][2] = {{5,1},{5,0},{5,7},{6,2},{5,0},{5,5},{5,4},{6,1}};
//int traffic_shape[5][2] = {{5,0},{5,6},{5,0},{6,6}};
//int traffic_shape[5][2] = {{2,0},{2,1},{2,2},{2,3}};
int curr_mix_index=0;
bool dynLoad = true;
bool instrumentTptLat = true; //Instrument num_ue and response_time every 10 sec
int mix_num=0; //choose the traffix mix from above traffic_options -> {0,1,2}
time_t mix_endTime; //End time of current traffic mix
float tpt[NO_EPOCH] = {0};
float lat[NO_EPOCH] = {0};
unsigned long long num_req_per_epoch[NO_EPOCH] = {0};
unsigned long long response_time_per_epoch[NO_EPOCH] = {0};
/// DYNAMIC LOAD GENERATOR VARIABLES END HERE ///
bool putFlag = true;
//int put_percent = 100; //out of 1000 eg. 100 = 10%
//nPut & nGet are used to generate varied load as put:get
//0---1:20---5% put
//1---1:10---10% put
//2---1:5---18%
//3---1:3---25%
//4---1:1---50%
//5---2:1---66%
//6---3:1---75%
//7---1:0---100%
int nPut = 1;
int nGet = 20;
// Thread function for each simulated UE
void* multithreading_func(void *arg){
struct _threadArgs *args = (struct _threadArgs *)arg;
int threadId = args->threadId;
int maxThreads = args->num_threads;
Network user(threadId+1);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
time_t curTime;
time(&curTime);
struct timeval start1, end1; //Used to find time between request send n response received // response time metrics
int key = 1; // key is used for the key
while(curTime < endTime){
do {
UserEquipment ue(threadId+1);
gettimeofday(&start, NULL);
int step = 1; //threadId * flowWeight;
/*if((putFlag) && (threadId==0)){
for (int k=0; k<flowWeight; k++){
gettimeofday(&start1, NULL);
putG(user,ue,k+step,k+1);
//usleep(1);
num_req_per_thread_P[threadId]++;
num_req_per_thread[threadId]++;
//////PRINT CONN RESP TIME TO ARRAY////
gettimeofday(&end1, NULL);
seconds = end1.tv_sec - start1.tv_sec;
useconds = end1.tv_usec - start1.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
response_time_P[threadId] += mtime;
response_time[threadId] += mtime;
}
//sleep(1);
putFlag=false;
}*/
//int step = threadId * flowWeight;
//cout<<"Step= " <<step<<endl;
int max = (threadId+1)*1000;
key = threadId * 1000;
//for (int i=0; i<flowWeight; i++){
//for (int k=0; k < nPut; k++){
for (int k=0; k < 10000; k++){
//PUT CODE
gettimeofday(&start1, NULL);
//putG(user,ue,key+step,key+1);
putG(user,ue,key,key+1);
//usleep(1);
//sleep(60);
key= (key+1) % max;
num_req_per_thread_P[threadId]++;
num_req_per_thread[threadId]++;
//////PRINT CONN RESP TIME TO ARRAY////
gettimeofday(&end1, NULL);
seconds = end1.tv_sec - start1.tv_sec;
useconds = end1.tv_usec - start1.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
response_time_P[threadId] += mtime;
response_time[threadId] += mtime;
}
/*for (int k=0; k < nGet; k++){
//GET CODE
gettimeofday(&start1, NULL);
get(user,ue,key+step);
//usleep(1);
num_req_per_thread_G[threadId]++;
num_req_per_thread[threadId]++;
//////PRINT CONN RESP TIME TO ARRAY////
gettimeofday(&end1, NULL);
seconds = end1.tv_sec - start1.tv_sec;
useconds = end1.tv_usec - start1.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
response_time_G[threadId] += mtime;
response_time[threadId] += mtime;
}*/
/*if (key < flowWeight){ //i is used for key
key++;
} else
{ key = 0;
}*/
//usleep(1000);
//Terminate the connection
gettimeofday(&start1, NULL);
//////PRINT CONN RESP TIME TO ARRAY////
gettimeofday(&end1, NULL);
seconds = end1.tv_sec - start1.tv_sec;
useconds = end1.tv_usec - start1.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
time(&curTime);
////// DYNAMIC LOAD GENERATION CODE STARTS HERE /////////////////////////////////////////////////////////
if(dynLoad){
traffic_mtx.lock();
if(curTime >= mix_endTime) {
lat_mtx.lock();
for(int i=0; i<maxThreads; i++){
num_req_per_epoch[curr_mix_index] = num_req_per_epoch[curr_mix_index] + num_req_per_thread[i];
response_time_per_epoch[curr_mix_index] = response_time_per_epoch[curr_mix_index] + response_time[i];
}
lat_mtx.unlock();
if ( curr_mix_index > 0){
int i = curr_mix_index;
while (i > 0) {
num_req_per_epoch[curr_mix_index] = num_req_per_epoch[curr_mix_index] - num_req_per_epoch[i-1];
response_time_per_epoch[curr_mix_index] = response_time_per_epoch[curr_mix_index] - response_time_per_epoch[i-1];
i--;
}
}
float tmp_tpt = (num_req_per_epoch[curr_mix_index]*1.0)/(traffic_shape[curr_mix_index][0] * 60);
float tmp_lat = (response_time_per_epoch[curr_mix_index]*0.001)/num_req_per_epoch[curr_mix_index];
tpt[curr_mix_index] = tmp_tpt;
lat[curr_mix_index] = tmp_lat;
if(curr_mix_index < traffic_shape_size){
curr_mix_index++;
}
mix_num = traffic_shape[curr_mix_index][1];
setMix(mix_num);
int tmp1 = traffic_shape[curr_mix_index][0] * 60;
mix_endTime = curTime + (int) tmp1;
cout<<"mix="<<mix_num<<endl;
}
traffic_mtx.unlock();
}
////// DYNAMIC LOAD GENERATION CODE ENDS HERE /////////////////////////////////////////////////////////
////// INSTRUMENTATION CODE STARTS HERE /////////////////////////////////////////////////////////
if(instrumentTptLat){
inst_mtx.lock();
time(&curTime);
if(curTime >= inst_endTime) {
//cout<<"start time="<<curTime<<endl;
lat_mtx.lock();
//num_ue_inst[instIndex] = attNo + detNo + sreqNo;
for(int i=0; i<maxThreads; i++){
num_ue_inst[instIndex] = num_ue_inst[instIndex] + num_req_per_thread[i];
resp_time_inst[instIndex] = resp_time_inst[instIndex] + response_time[i];
}
lat_mtx.unlock();
float prev_t = num_ue_inst[instIndex];
float prev_l = resp_time_inst[instIndex];
num_ue_inst[instIndex] = num_ue_inst[instIndex] - prev_tpt; //Get current period val
resp_time_inst[instIndex] = resp_time_inst[instIndex] - prev_lat;
resp_time_inst[instIndex] = (resp_time_inst[instIndex]*0.001)/num_ue_inst[instIndex]; //Keep it bfor num_ue_inst update coz we need total number and not throughtput
num_ue_inst[instIndex] = (num_ue_inst[instIndex]*1.0)/INST_PERIOD;
prev_tpt = prev_t;
prev_lat = prev_l;
instIndex++;
inst_endTime = curTime + (int) INST_PERIOD;
}
inst_mtx.unlock();
}
////// INSTRUMENTATION CODE ENDS HERE /////////////////////////////////////////////////////////
}while(curTime < endTime); //end do-while
} //end while
free(args);
pthread_exit(NULL);
}
int main(int argc, char *args[]){
long maxThreads = 0;
int status;
stringstream ss;
string data = "";
std::ofstream outfile;
std::ofstream delayfile;
std::ofstream instfile;
if(argc != 4){
fprintf(stderr,"Usage: %s <max-threads> <program-run-time(in mins)> <num-msg per connection(thin/fat flow)> \n", args[0]);
exit(0);
}
maxThreads = atoi(args[1]);
if(maxThreads <= 0){
printf("Number of threads should be greater than 0\n");
exit(0);
}
double tmp;
ss << args[2];
ss >> tmp;
if(tmp <= 0.0){
printf("Run time of each threads should be greater than 0.0\n");
exit(0);
}
flowWeight = atoi(args[3]);
//cout<<flowWeight;
if(flowWeight < 1){
printf("Connection size should be atleast 1 packet\n");
exit(0);
}
num_req_per_thread_P.resize(maxThreads, 0);
num_req_per_thread_G.resize(maxThreads, 0);
num_req_per_thread.resize(maxThreads,0);
response_time_P.resize(maxThreads, 0);
response_time_G.resize(maxThreads, 0);
response_time.resize(maxThreads, 0);
cout<<"***************STARTING NOW***************"<<endl;
tmp = tmp * 60;
time_t curTime;
time(&curTime);
if(DO_DEBUG){
cout<<"start time="<<curTime<<endl;
}
endTime = curTime + (int) tmp;
if(DO_DEBUG){
cout<<"end time="<<endTime<<endl;
}
int simulationTime = (int) tmp;
pthread_t tid[maxThreads];
///////// DYNAMIC LOAD GEN in MAIN STARTS ///////////////
if (dynLoad){
cout<<"start time="<<curTime<<endl;
int tmp1 = traffic_shape[curr_mix_index][0] * 60;
mix_endTime = curTime + (int) tmp1;
mix_num = traffic_shape[curr_mix_index][1];
setMix(mix_num);
cout<<"mix="<<mix_num<<endl;
}
///////// DYNAMIC LOAD GEN in MAIN ENDS ///////////////
///// INSTRUMENTATION CODE STARTS /////////
if (instrumentTptLat){
int tmp2 = INST_PERIOD;
inst_endTime = curTime + (int) tmp2;
}
///// INSTRUMENTATION CODE ENDS /////////
// Create UE threads
for(int i = 0;i<maxThreads;i++){
struct _threadArgs * args = (struct _threadArgs *)malloc(sizeof(struct _threadArgs));
args->threadId = i;
args->num_threads = maxThreads;
status = pthread_create(&tid[i], NULL, multithreading_func, args);
report_error(status);
}
// Sleep for the specified simulation time
usleep(simulationTime * 1000000); // 1sec
/* Wake up and cancel/join all the UE threads to end simulation */
for(int i=0;i<maxThreads;i++){
if(DO_DEBUG){
cout<<"******* ENDING THREAD - "<<i<<endl;
}
pthread_cancel(tid[i]);
pthread_join(tid[i],NULL);
}
if(DO_DEBUG){
cout<<"************ENDED!!!************"<<endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* Calculate and display various metrics */
string s = "";
int total_G = 0;
int total_P = 0;
unsigned long long total_response_time_P = 0;
unsigned long long total_response_time_G = 0;
unsigned long long total_conn_response_time = 0;
double average_response_time_P = 0.0;
double average_response_time_G = 0.0;
double average_response_time = 0.0;
double throughput = 0.0, throughput_P = 0.0, throughput_G = 0.0;
double percentP = 0.0;
time_t actual_endTime;
time(&actual_endTime);
for(int i=0;i<maxThreads;i++){
total_P += num_req_per_thread_P[i];
total_G += num_req_per_thread_G[i];
total_response_time_P += response_time_P[i];
total_response_time_G += response_time_G[i];
cout<<"num_req_per_thread_P["<<i<<"] "<<num_req_per_thread_P[i]<<endl;
cout<<"num_req_per_thread_G["<<i<<"] "<<num_req_per_thread_G[i]<<endl;
cout<<"put response_time["<<i<<"] "<<((response_time_P[i]*1.0)/num_req_per_thread_P[i])<<" us"<<endl;
cout<<"get response_time["<<i<<"] "<<((response_time_G[i]*1.0)/num_req_per_thread_G[i])<<" us"<<endl;
}
average_response_time_P = (total_response_time_P*1.0)/(total_P*1.0);
average_response_time_G = (total_response_time_G*1.0)/(total_G*1.0);
average_response_time = ((total_response_time_P + total_response_time_G)*1.0)/((total_P + total_G)*1.0);
throughput_P = ((total_P)*1.0)/(actual_endTime - curTime);
throughput_G = ((total_G)*1.0)/(actual_endTime - curTime);
throughput = ((total_P + total_G)*1.0)/(actual_endTime - curTime);
percentP = (throughput_P/throughput)*100;
cout<<"***************************************STATISTICS***************************************"<<endl;
double averageReqPerThread = (((total_P + total_G)*1.0)/maxThreads);
averageReqPerThread = roundf(averageReqPerThread * 100) / 100;
ostringstream strsR;
strsR << averageReqPerThread;
string avReq = strsR.str();
ostringstream strsC;
printf("Total Number of Threads=%ld\n", maxThreads);
printf("Total Number of Puts=%d\n", total_P);
printf("Total Number of Gets=%d\n", total_G);
cout<<"Average Number of Requests per Thread="<<averageReqPerThread<<endl;
printf("Total Execution Time=%ld sec\n", (actual_endTime - curTime));
average_response_time = average_response_time/1000000.0;
cout<<"Average Request Latency = "<<average_response_time<<" secs"<<endl;
cout<<"Put Throughput="<<throughput_P<<" requests/sec"<<endl;
cout<<"Get Throughput="<<throughput_G<<" requests/sec"<<endl;
cout<<"Total Throughput="<<throughput<<" requests/sec"<<endl;
cout<<"Put Percent="<<percentP<<endl;
if (instrumentTptLat) {
instfile.open(INST_FILE, std::ios_base::app);
data = "";
if (instfile.is_open()){
//cout<<"inst_index="<<instIndex<<endl;
for(int i = 0; i < instIndex; i++){
float t = num_ue_inst[i];
float l = resp_time_inst[i];
data.append(to_string(t)).append(COMMA).append(to_string(l)).append("\n");
}
instfile << data;
instfile.close();
}
}
/* Write the metrics to the statistics file */
if(!fileExists(STATISTIC_FILE)){
data.append("#MaxThreads").append(COMMA);
data.append("FlowWeight").append(COMMA).append("ExecutionTime").append(COMMA);
data.append("#Gets").append(COMMA).append("#Puts").append(COMMA);
data.append("GetResponseTime").append(COMMA);
data.append("PutResponseTime").append(COMMA);
data.append("GetTpt").append(COMMA);
data.append("PutTpt").append(COMMA);
data.append("AvgRequestLatency").append(COMMA).append("AvgThroughput");
data.append(COMMA).append("Put%");
data.append("\n");
}
outfile.open(STATISTIC_FILE, std::ios_base::app);
if (outfile.is_open()){
data.append(to_string(maxThreads)).append(COMMA).append(to_string(flowWeight)).append(COMMA).append(to_string(tmp).append(COMMA));
data.append(to_string(total_G)).append(COMMA);
data.append(to_string(total_P)).append(COMMA);
data.append(to_string(average_response_time_G)).append(COMMA);
data.append(to_string(average_response_time_P)).append(COMMA);
//data.append(to_string(total_G + total_P)).append(COMMA);
data.append(to_string(throughput_G)).append(COMMA);
data.append(to_string(throughput_P)).append(COMMA);
data.append(to_string(average_response_time)).append(COMMA);
data.append(to_string(throughput)).append(COMMA);
data.append(to_string(percentP));
}
data.append("\n");
outfile << data;
outfile.close();
exit(0);
return 0;
}
inline bool fileExists (const std::string& name) {
struct stat buffer;
return (stat (name.c_str(), &buffer) == 0);
}
void get(Network &user,UserEquipment &ue, int key){
return ue.get(user,key);
}
void put(Network &user,UserEquipment &ue, int key, int val){
return ue.put(user,key,val);
}
void getG(Network &user,UserEquipment &ue, int key){
return ue.getG(user,key);
}
void putG(Network &user,UserEquipment &ue, int key, int val){
return ue.putG(user,key,val);
}
void setMix(int traffic_type){
//nPut & nGet are used to generate varied load as put:get
//0---1:20---5% put
//1---1:10---10% put
//2---1:5---18%
//3---1:3---25%
//4---1:1---50%
//5---2:1---66%
//6---3:1---75%
//7---1:0---100%
switch(traffic_type){
case 0:
nPut=1;
nGet=20;
break;
case 1:
nPut=1;
nGet=10;
break;
case 2:
nPut=1;
nGet=5;
break;
case 3:
nPut=1;
nGet=3;
break;
case 4:
nPut=1;
nGet=1;
break;
case 5:
nPut=2;
nGet=1;
break;
case 6:
nPut=3;
nGet=1;
break;
case 7:
nPut=1;
nGet=0;
break;
default:
cout<<"Incorrect traffic type"<<endl;
break;
}
}
#include "ue.h"
#include "utils.h"
// Thread function for each UE
void* multithreading_func(void*);
void get(Network&,UserEquipment&,int);
void put(Network&,UserEquipment&,int,int);
void getG(Network&,UserEquipment&,int);
void putG(Network&,UserEquipment&,int,int);
inline bool fileExists (const std::string&);
void setMix(int);
25428.000000,0.187694
16728.199219,0.190937
15381.000000,0.192013
15286.099609,0.193308
13028.700195,0.187651
10884.599609,0.181128
14615.400391,0.282102
12454.599609,0.284142
9205.299805,0.260110
8437.200195,0.233873
8024.600098,0.245885
8480.500000,0.232647
14092.799805,0.133125
15608.900391,0.125049
14706.700195,0.132965
15171.400391,0.128858
22904.599609,0.168836
23514.900391,0.166994
20675.199219,0.174134
14949.299805,0.197522
14959.099609,0.197415
8900.299805,0.192785
25924.000000,0.151526
24990.199219,0.148216
23135.300781,0.128011
20938.400391,0.135729
20816.099609,0.120420
20189.300781,0.104460
22609.099609,0.172755
22630.199219,0.165605
19244.400391,0.154879
19873.199219,0.152041
16872.400391,0.140997
15135.500000,0.128922
12770.900391,0.365437
2677.100098,1.034232
5392.899902,0.383199
3517.000000,0.582586
2353.300049,0.535475
5000.000000,0.250500
5000.000000,0.250501
5000.000000,0.249650
5000.000000,0.251881
10000.000000,0.101549
10000.000000,0.101497
10000.000000,0.101372
10000.000000,0.101449
10000.000000,0.101501
20054.599609,0.143136
15646.299805,0.125783
15478.200195,0.129734
13396.299805,0.130019
9000.000000,0.112075
18893.099609,0.203768
14833.400391,0.201728
14799.500000,0.202068
12382.500000,0.195880
10610.099609,0.190871
25358.800781,0.156851
25519.199219,0.156733
27429.400391,0.157607
24092.599609,0.158162
24969.199219,0.152184
21528.599609,0.200482
15957.599609,0.200924
15921.200195,0.200489
14149.700195,0.200932
11921.299805,0.201255
19969.599609,0.144780
13990.400391,0.141818
13957.700195,0.146047
26573.199219,0.151906
21307.900391,0.149899
20895.500000,0.148847
18813.699219,0.151349
10439.700195,0.190038
10188.700195,0.195399
27588.599609,0.151053
25066.400391,0.144967
12424.799805,0.165251
11837.900391,0.159651
10864.900391,0.172589
19436.000000,0.157061
9980.000000,0.197959
24272.400391,0.114264
27040.900391,0.110309
28006.599609,0.109475
33637.500000,0.124675
31639.400391,0.122455
27352.400391,0.108127
27478.900391,0.107734
29262.800781,0.119911
24717.300781,0.112505
18220.500000,0.109712
31612.900391,0.122583
29278.599609,0.116684
25068.699219,0.115422
28464.900391,0.109554
28492.099609,0.105585
23049.099609,0.115809
9246.000000,0.108822
9000.000000,0.116574
24914.599609,0.113062
25871.000000,0.118098
all: client
CLIENT_P = client.cpp client.h utils.cpp utils.h network.cpp network.h ue.cpp ue.h
CLIENT_R = g++ client.cpp client.h utils.cpp utils.h network.cpp network.h ue.cpp ue.h -std=c++11 -o client -lpthread -lcrypto
client: $(CLIENT_P)
$(CLIENT_R)
clean:
rm -f client *~
/*************************************************************************
* * This file contains all the socket level functions that is used by UE. *************************************************************************/
#include "network.h"
//Below are the files included for raw packets
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h> //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/ip.h> //Provides declarations for ip header
#include <unistd.h> //Used to get PID of current process
#include<netinet/ip_icmp.h> //Provides declarations for icmp header
//#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/tcp.h> //Provides declarations for tcp header
//#include<netinet/ip.h> //Provides declarations for ip header
#include<netinet/if_ether.h> //For ETH_P_ALL
#include<net/ethernet.h> //For ether_header
//#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<sys/time.h>
#include<sys/types.h>
//#include<unistd.h>
Network::Network(int ID){
tID=2000+ID; //use global tID to distinguish between threads
//cout<<"TID= "<<tID<<endl;
//Create a raw socket of type IPPROTO
client_socket = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
if(MY_DEBUG){
cout << "Raw Send Socket created"<<endl;
}
//client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(client_socket < 0){
cout << "ERROR opening UDP socket" << endl;
exit(1);
}
sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
if(MY_DEBUG){
cout << "Raw Receive Socket created"<<endl;
}
//int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
//setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth1" , strlen("eth1")+ 1 );
if(sock_raw < 0)
{
//Print the error with proper message
perror("Socket Error");
//return 1;
}
}
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
/*
Generic checksum calculation function
*/
unsigned short csum(unsigned short *ptr,int nbytes)
{
register long sum;
unsigned short oddbyte;
register short answer;
sum=0;
while(nbytes>1) {
sum+=*ptr++;
nbytes-=2;
}
if(nbytes==1) {
oddbyte=0;
*((u_char*)&oddbyte)=*(u_char*)ptr;
sum+=oddbyte;
}
sum = (sum>>16)+(sum & 0xffff);
sum = sum + (sum>>16);
answer=(short)~sum;
return(answer);
}
/*
* This function configures the port number and IP address of the created socket.
*/
void Network::input_server_details(int server_port, const char *server_address){
int status;
this->server_port = server_port;
this->server_address = server_address;
bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(server_port);
// Store this IP address in server_sock_addr; pton supports IPv6 while aton does not
status = inet_pton(AF_INET, server_address, &(server_sock_addr.sin_addr));
if(status == 0){
cout<<"ERROR: Invalid IP address"<<endl;
exit(EXIT_FAILURE);
}
}
/*
* This function reads from the UDP socket.
*/
void Network::read_data(){
int status=0;
unsigned char* my_buffer;
//Receive a packet
int c=0;
while(status!=17 || !tflag ){
bzero(client_buffer, BUFFER_SIZE);
data_size = recvfrom(sock_raw, client_buffer , BUFFER_SIZE-1 , 0 , &saddr , (socklen_t*)&saddr_size);
status=ProcessPacket((unsigned char*)client_buffer , data_size);
}
}
int Network::ProcessPacket(unsigned char* buffer, int size)
{
int tcp=0,udp=0,icmp=0,others=0,igmp=0,total=0,i,j;
++total;
//Get the IP Header part of this packet , excluding the ethernet header
struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
switch (iph->protocol) //Check the Protocol and do accordingly...
{
case 17: //UDP Protocol
//cout<<"Inside process packet:UDP"<<endl;
//++udp;
print_udp_packet(buffer , size);
return(17);
break;
default: //Some Other Protocol like ARP etc.
//cout<<"Inside process packet:others";
//++others;
return(0);
break;
}
}
void Network::print_ip_header(unsigned char* Buffer, int Size)
{
//print_ethernet_header(Buffer , Size);
unsigned short iphdrlen;
struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr) );
iphdrlen =iph->ihl*4;
memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = iph->saddr;
memset(&dest, 0, sizeof(dest));
dest.sin_addr.s_addr = iph->daddr;
}
void Network::print_udp_packet(unsigned char *Buffer , int Size)
{
unsigned short iphdrlen;
struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr));
iphdrlen = iph->ihl*4;
struct udphdr *udph = (struct udphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));
int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof udph;
print_ip_header(Buffer,Size);
if ((int)ntohs(udph->dest) == tID) {
tflag=true;
}
else
tflag=false;
strcpy(client_buffer, (const char*) Buffer + header_size);
}
void Network::write_data2(int data_len){
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//UDP header
struct udphdr *udph = (struct udphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in server_sock_addr;
struct pseudo_header psh;
//Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
if(MY_DEBUG){
cout<<"data len = "<<data_len<<endl;
}
memcpy (data, client_buffer, data_len);
bzero(client_buffer, BUFFER_SIZE);
if(MY_DEBUG){
cout<<"SENDING - "<<data<<endl;
}
//cout<<"Thread ID- "<<tID<<endl;
/*int c = 0;
while (client_buffer[c] != '\0') {
data[c] = client_buffer[c];
c++;
}
data[c] = '\0';*/
//some address resolution
strcpy(source_ip , CLIENT_IP); //Source IP
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(gw_port);
server_sock_addr.sin_addr.s_addr = inet_addr(DGW_IP); //Dest IP
//Bind the client socket to UDP port
//bind(client_socket, (struct sockaddr *)& server_sock_addr, sizeof(server_sock_addr));
//Tell the kernel that we build our own packets
/*int one = 1;
const int *val = &one;
if(setsockopt(client_socket, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0){
perror("setsockopt() error");
exit(-1);
}*/
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = stoi("1")*4; //16;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + data_len;
iph->id = htonl(0); //htonl (12345); //Id of this packet
iph->frag_off = 0;
// iph->ttl = 255;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0; //Set to 0 before calculating checksum
iph->saddr = inet_addr(source_ip); //Spoof the source ip address
iph->daddr = server_sock_addr.sin_addr.s_addr;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//int pid = getpid();
//int parentsPID = getppid();
//UDP header
//udph->source = htons (RAN_UDP_PORT);
udph->source = htons (tID);
udph->dest = htons (gw_port);// htons(stoi(msg_id)+2000);
udph->len = htons(8 + data_len); //tcp header size
udph->check = 0; //leave checksum 0 now, filled later by pseudo header
//Now the UDP checksum using the pseudo header
psh.source_address = inet_addr( source_ip );
psh.dest_address = server_sock_addr.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + data_len );
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + data_len;
pseudogram =(char*) malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + data_len);
udph->check = csum( (unsigned short*) pseudogram , psize);
int status;
status = sendto(client_socket, datagram, iph->tot_len, 0 , (struct sockaddr*) &server_sock_addr, sizeof(server_sock_addr));
report_error(status);
}
/*
* This function writes to the UDP socket.
//We pass msg_id to write_data to set IPToS field
*/
void Network::write_data(string msg_id){
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//UDP header
struct udphdr *udph = (struct udphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in server_sock_addr;
struct pseudo_header psh;
//Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
strcpy(data , client_buffer);
bzero(client_buffer, BUFFER_SIZE);
if(MY_DEBUG){
cout<<"SENDING - "<<data<<endl;
}
//some address resolution
strcpy(source_ip , CLIENT_IP); //Source IP
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(gw_port);
server_sock_addr.sin_addr.s_addr = inet_addr(DGW_IP); //Dest IP
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = stoi(msg_id)*4; //16;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
iph->id = htonl(0); //htonl (12345); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
iph->check = 0; //Set to 0 before calculating checksum
iph->saddr = inet_addr(source_ip); //Spoof the source ip address
iph->daddr = server_sock_addr.sin_addr.s_addr;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//UDP header
//udph->source = htons (RAN_UDP_PORT);
udph->source = htons (tID);
udph->dest = htons (gw_port);// htons(stoi(msg_id)+2000);
udph->len = htons(8 + strlen(data)); //tcp header size
udph->check = 0; //leave checksum 0 now, filled later by pseudo header
//Now the UDP checksum using the pseudo header
psh.source_address = inet_addr( source_ip );
psh.dest_address = server_sock_addr.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
pseudogram =(char*) malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + strlen(data));
udph->check = csum( (unsigned short*) pseudogram , psize);
int status;
status = sendto(client_socket, datagram, iph->tot_len, 0 , (struct sockaddr*) &server_sock_addr, sizeof(server_sock_addr));
report_error(status);
}
/*
* This function reads from the UDP socket in the form of unsigned char.
*/
void Network::read_byte(){
int status;
bzero(client_byte_buffer, BUFFER_SIZE);
status = recvfrom(client_socket, client_byte_buffer, BUFFER_SIZE-1, 0, NULL, NULL);
report_error(status);
}
/*
* This function writes to the UDP socket in the form of unsigned char.
*/
void Network::write_byte(){
int status;
status = sendto(client_socket, client_byte_buffer, strlen((char*)client_byte_buffer), 0,(struct sockaddr*)&server_sock_addr, sizeof(server_sock_addr));
report_error(status);
}
// Destructor: Close the UDP client socket
Network::~Network(){
close(client_socket);
close(sock_raw);
}
#ifndef UTILS_H
#define UTILS_H
#include <fcntl.h>
#include "utils.h"
#endif
class Network{
public:
int tID;
int client_socket;
char client_buffer[BUFFER_SIZE];
char write_client_buffer[BUFFER_SIZE];
char write_client_byte_buffer[BUFFER_SIZE];
int sock_raw; //To receive raw packets
int saddr_size , data_size;
struct sockaddr saddr;
// Byte array in C++
unsigned char client_byte_buffer[BUFFER_SIZE];
int server_port;
const char *server_address;
struct sockaddr_in server_sock_addr;
struct sockaddr_in source,dest;
//bool flag=false; //flag to test the right dest IP for rcv data
bool tflag=false; //flag to test dest UDP port for demux of packets
// Constructor
Network(int);
// Socket methods
void input_server_details(int,const char*);
void read_data();
void write_data(string);
void write_data2(int);
void read_byte();
void write_byte();
int sendUEData(int, string, string, int, int, int, string, size_t);
// Utility functions
string GetStdoutFromCommand(string cmd);
string runIperfCommand(string cmd,string srcIp);
//Raw packet functions
int ProcessPacket(unsigned char* , int);
void print_ip_header(unsigned char* , int);
void print_udp_packet(unsigned char * , int );
// Destructor
~Network();
};
sudo route add -net 192.168.3.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.4.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.5.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.6.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.7.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.8.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.9.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
sudo route add -net 192.168.10.0 netmask 255.255.255.0 gw 192.168.1.2 dev eth1
12770.900391,0.365437
2677.100098,1.034232
5392.899902,0.383199
3517.000000,0.582586
2353.300049,0.535475
#MaxThreads,FlowWeight,ExecutionTime,#Gets,#Puts,GetResponseTime,PutResponseTime,GetTpt,PutTpt,AvgRequestLatency,AvgThroughput,Put%
4,1,60.000000,0,296928,nan,453.192370,0.000000,4948.800000,0.000453,4948.800000,100.000000
5000.000000,0.250500
5000.000000,0.250501
5000.000000,0.249650
5000.000000,0.251881
1,1,60.000000,0,244525,nan,245.083443,0.000000,4075.416667,0.000245,4075.416667,100.000000
10000.000000,0.101549
10000.000000,0.101497
10000.000000,0.101372
10000.000000,0.101449
10000.000000,0.101501
1,1,60.000000,0,589653,nan,101.455861,0.000000,9827.550000,0.000101,9827.550000,100.000000
2,1,60.000000,0,87165,nan,111.031653,0.000000,1452.750000,0.000111,1452.750000,100.000000
4,1,6.000000,0,148511,nan,155.959969,0.000000,24751.833333,0.000156,24751.833333,100.000000
20054.599609,0.143136
15646.299805,0.125783
15478.200195,0.129734
13396.299805,0.130019
9000.000000,0.112075
4,1,60.000000,0,819535,nan,128.644840,0.000000,13658.916667,0.000129,13658.916667,100.000000
8,1,6.000000,0,94553,nan,223.085222,0.000000,15758.833333,0.000223,15758.833333,100.000000
6,1,6.000000,0,128340,nan,195.318389,0.000000,21390.000000,0.000195,21390.000000,100.000000
18893.099609,0.203768
14833.400391,0.201728
14799.500000,0.202068
12382.500000,0.195880
10610.099609,0.190871
6,1,60.000000,0,808249,nan,198.777890,0.000000,13470.816667,0.000199,13470.816667,100.000000
25358.800781,0.156851
25519.199219,0.156733
27429.400391,0.157607
24092.599609,0.158162
24969.199219,0.152184
#### 2 QUEUES
4,1,60.000000,0,1408391,nan,155.270227,0.000000,23473.183333,0.000155,23473.183333,100.000000
21528.599609,0.200482
15957.599609,0.200924
15921.200195,0.200489
14149.700195,0.200932
11921.299805,0.201255
6,1,60.000000,0,895084,nan,200.783456,0.000000,14673.508197,0.000201,14673.508197,100.000000
19969.599609,0.144780
13990.400391,0.141818
13957.700195,0.146047
#### 6 QUEUES
4,1,30.000000,0,479904,nan,144.220271,0.000000,15480.774194,0.000144,15480.774194,100.000000
26573.199219,0.151906
21307.900391,0.149899
20895.500000,0.148847
18813.699219,0.151349
10439.700195,0.190038
10188.700195,0.195399
4,1,60.000000,0,1082663,nan,158.573467,0.000000,18044.383333,0.000159,18044.383333,100.000000
27588.599609,0.151053
25066.400391,0.144967
12424.799805,0.165251
11837.900391,0.159651
10864.900391,0.172589
4,1,60.000000,0,921223,nan,157.320314,0.000000,15353.716667,0.000157,15353.716667,100.000000
19436.000000,0.157061
9980.000000,0.197959
4,1,30.000000,0,394022,nan,175.833393,0.000000,13134.066667,0.000176,13134.066667,100.000000
24272.400391,0.114264
27040.900391,0.110309
28006.599609,0.109475
4,1,30.000000,0,800178,nan,111.153595,0.000000,26672.600000,0.000111,26672.600000,100.000000
33637.500000,0.124675
31639.400391,0.122455
4,1,30.000000,0,973877,nan,123.065053,0.000000,32462.566667,0.000123,32462.566667,100.000000
27352.400391,0.108127
27478.900391,0.107734
4,1,30.000000,0,840234,nan,107.064149,0.000000,28007.800000,0.000107,28007.800000,100.000000
29262.800781,0.119911
24717.300781,0.112505
18220.500000,0.109712
4,1,30.000000,0,725058,nan,114.768152,0.000000,24168.600000,0.000115,24168.600000,100.000000
31612.900391,0.122583
29278.599609,0.116684
25068.699219,0.115422
4,1,30.000000,0,861042,nan,118.457599,0.000000,28701.400000,0.000118,28701.400000,100.000000
28464.900391,0.109554
28492.099609,0.105585
4,1,30.000000,0,762393,nan,107.451678,0.000000,25413.100000,0.000107,25413.100000,100.000000
23049.099609,0.115809
9246.000000,0.108822
9000.000000,0.116574
4,1,60.000000,0,452292,nan,113.807584,0.000000,7538.200000,0.000114,7538.200000,100.000000
24914.599609,0.113062
25871.000000,0.118098
4,1,30.000000,0,782060,nan,114.854963,0.000000,26068.666667,0.000115,26068.666667,100.000000
/********************************************************************
* This file contains all the functionalities associated with a UE. *
********************************************************************/
#include "ue.h"
#include <time.h>
/* Message codes */
//Message from client to Switch/LB/Server
string GET = "1";
string GETG = "2";
string PUT = "3";
string PUTG = "4";
//Message from Server to Controller LB
//string SERVERSTATS = "5";
//Reply from LB to Client(ACK)
string SERVERFOUND = "6";
//string FIN = "7";
char SEPARATOR[] = "@:##:@";
/*
* Constructor: Create a UE object.
*/
UserEquipment::UserEquipment(int ue_num){
}
void UserEquipment::get(Network &user, int key){
string send, receive;
vector<string> tmpArray;
time_t curTime;
time(&curTime);
send = GET + SEPARATOR + to_string(key);
bzero(user.client_buffer, BUFFER_SIZE);
sprintf(user.client_buffer,"%s",send.c_str());
user.write_data(GET); //We pass msg_id to write_data to set IPToS field
time(&curTime);
// Receive reply from LB
user.read_data();
time(&curTime);
receive = (string) (user.client_buffer);
if (receive.find(SEPARATOR) != std::string::npos) {
tmpArray = split(user.client_buffer, SEPARATOR);
if(tmpArray[0] == SERVERFOUND){
if(DO_DEBUG){
cout <<"VALUE : "<<tmpArray[1]<<endl;
}
}
//cout <<"VALUE : "<<tmpArray[1]<<endl;
//<<"VALUE: "<<tmpArray[2]<<endl;
//cout<<"Received"<<endl;
}
}
void UserEquipment::getG(Network &user, int key){
string send, receive;
vector<string> tmpArray;
time_t curTime;
////////////////// Global GET /////////////////
time(&curTime);
send = GETG + SEPARATOR + to_string(key);
bzero(user.client_buffer, BUFFER_SIZE);
sprintf(user.client_buffer,"%s",send.c_str());
user.write_data(GETG); //We pass msg_id to write_data to set IPToS field
time(&curTime);
// Receive reply from KV
user.read_data();
time(&curTime);
receive = (string) (user.client_buffer);
if (receive.find(SEPARATOR) != std::string::npos) {
tmpArray = split(user.client_buffer, SEPARATOR);
if(tmpArray[0] == SERVERFOUND){
if(DO_DEBUG){
cout <<"VALUE : "<<tmpArray[1]<<endl;
}
}
//cout <<"VALUE : "<<tmpArray[1]<<endl;
//<<"VALUE: "<<tmpArray[2]<<endl;
//cout<<"Received"<<endl;
}
///////////////// Global GET ends ////////////////
}
void UserEquipment::put(Network &user, int key, int val){
string send, receive;
vector<string> tmpArray;
time_t curTime;
time(&curTime);
send = PUT + SEPARATOR + to_string(key) + SEPARATOR + to_string(val);
bzero(user.client_buffer, BUFFER_SIZE);
sprintf(user.client_buffer,"%s",send.c_str());
user.write_data(PUT);
time(&curTime);
// Receive reply from KV
user.read_data();
time(&curTime);
receive = (string) (user.client_buffer);
if (receive.find(SEPARATOR) != std::string::npos) {
tmpArray = split(user.client_buffer, SEPARATOR);
if(tmpArray[0] == SERVERFOUND){
if(DO_DEBUG){
cout <<"PUT COMPLETE : "<<tmpArray[0]<<endl;
}
}
}
}
void UserEquipment::putG(Network &user, int key, int val){
string send, receive;
vector<string> tmpArray;
time_t curTime;
////////// Global PUT ////////////////////////////
time(&curTime);
//send = PUTG + SEPARATOR + to_string(key) + SEPARATOR + to_string(val);
uint16_t type = htons(0x4);
uint16_t sep1 = htons(0x403A);
uint16_t sep2 = htons(0x2323);
uint16_t sep3 = htons(0x3A40);
uint32_t k = htonl(key);
uint32_t v = htonl(val);
bzero(user.client_buffer, BUFFER_SIZE);
int len = 0;
memcpy(user.client_buffer, &type, 2);
len=len+2;
memcpy(user.client_buffer+len, &sep1, 2);
len=len+2;
memcpy(user.client_buffer+len, &sep2, 2);
len=len+2;
memcpy(user.client_buffer+len, &sep3, 2);
len=len+2;
memcpy(user.client_buffer+len, &k, sizeof(int));
len=len+sizeof(int);
memcpy(user.client_buffer+len, &sep1, 2);
len=len+2;
memcpy(user.client_buffer+len, &sep2, 2);
len=len+2;
memcpy(user.client_buffer+len, &sep3, 2);
len=len+2;
memcpy(user.client_buffer+len, &v, sizeof(int));
len=len+sizeof(int);
//memcpy(user.client_buffer+len, &type, 2);
//len=len+2;
//sprintf(user.client_buffer,"%s",send.c_str());
user.write_data2(len);
time(&curTime);
// Receive reply from LB
user.read_data();
time(&curTime);
receive = (string) (user.client_buffer);
/*if (receive.find(SEPARATOR) != std::string::npos) {
tmpArray = split(user.client_buffer, SEPARATOR);
if(tmpArray[0] == SERVERFOUND){
if(DO_DEBUG){
cout <<"GLOBAL PUT COMPLETE : "<<tmpArray[0]<<endl;
}
}
}*/
////////// Global PUT ENDS ////////////////////////////
}
UserEquipment::~UserEquipment(){
// Dummy destructor
}
#include "network.h"
class UserEquipment{
public:
// Constructor
UserEquipment(int);
/* Functions */
void get(Network&, int);
void put(Network&, int, int);
void getG(Network&, int);
void putG(Network&, int, int);
// Destructor
~UserEquipment();
};
/****************************************************************************************
* This file contains all the utility functions such as integrity and cipher functions. *
****************************************************************************************/
#include "utils.h"
#include <random>
mutex mtx;
//int base_thread_ID=1;
//int gw_port = 9876;
int gw_port = 5858;
const char *gw_address = DGW_IP; // Packets should reach the default switch, so setting its IP to that of default switch
default_random_engine generator;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> att(0, 1);
std::uniform_real_distribution<> serv(0, 1);
int get_mix(vector<int> weights){
int sum = 0;
for(int i=0;i<weights.size();i++){
sum+=weights[i];
}
int rnd = rand()%sum+1;
if(DO_DEBUG)
cout<<"RANDOM "<<rnd<<endl;
for(int i=0; i<weights.size(); i++) {
if(rnd <= weights[i])
return i;
rnd -= weights[i];
}
//assert(!"should never get here");
return 15;
}
int my_rand(){
int num;
/* initialize random seed: */
srand (time(NULL));
/* generate secret number between 1 and 1000: */
num = rand() % 200 + 1;
return(num);
}
void report_error(int arg){
if(arg < 0){
perror("ERROR");
exit(EXIT_FAILURE);
}
}
void print_message(string message){
cout<<"***********************"<<endl;
cout<<message<<endl;
cout<<"***********************"<<endl;
}
void print_message(string message, int arg){
cout<<"***********************"<<endl;
cout<<message<<" "<<arg<<endl;
cout<<"***********************"<<endl;
}
void print_message(string message, unsigned long long arg){
cout<<"***********************"<<endl;
cout<<message<<" "<<arg<<endl;
cout<<"***********************"<<endl;
}
const char* to_char_array(unsigned long long arg){
string tem;
stringstream out;
out<<arg;
tem = out.str();
const char *ans = tem.c_str();
return ans;
}
string longToString(unsigned long long arg){
stringstream out;
out<<arg;
return out.str();
}
void trim(string& s){
s.erase(s.find_last_not_of(" \n\r\t")+1);
}
vector<string> split(char *str, const char *delim){
vector<string> ans;
string s(str);
string delimiter(delim);
size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
ans.push_back(token);
s.erase(0, pos + delimiter.length());
}
ans.push_back(s);
return ans;
}
//To delete entries from delay file: sed -i '/^pattern/d' delay.csv
//(C++) Operations: Input/Output
#include <iostream>
#include <math.h>
//(C++) STL Operations: String, Vector, String stream
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <queue>
#include <mutex>
// For integrity protection (NAS Signalling)
#include <openssl/hmac.h>
// For encryption/decryption (AES)
#include <openssl/aes.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
//(C) Operations: Input/Output, String, Standard libraries(like atoi, malloc)
#include <stdio.h>
#include <random>
#include <string.h>
#include <stdlib.h>
#include <thread>
//(C) Operations: Socket programming
#include <sys/timeb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
//(C) Operations: Multithreading
#include <pthread.h>
// Raw socket
#include <linux/if_packet.h>
#include <sys/ioctl.h>
#include <bits/ioctls.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ether.h>
//Tun device
#include <linux/if_tun.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <stdarg.h>
//Writing file
#include <fstream>
//#include <atomic>
using namespace std;
#define DO_DEBUG 0
#define MY_DEBUG 0
#define WANT_DELAY_CDF 0
#define UE_PER_THREAD 1000000
/**************************************** Configurable parameters **********************************************/
#define DEFAULT_IF "p0" // Default network interface name *
#define DGW_IP "192.168.220.34" // IP address of DGW machine
#define CLIENT_IP "192.168.220.39" // IP address of RAN machine
#define SINK_SERVER_NETMASK "/16" // Sink subnet netmask
/***************************************************************************************************************/
#define BUFFER_SIZE 300 // Maximum packet size
#define MAX_PACKET_SIZE 2048
#define LINK_MTU 1500 // MTU value for iperf3
#define RAN_UDP_PORT 5858
#define SINK_UDP_PORT 7891
#define COMMA ","
#define STATISTIC_FILE "stats.csv"
#define DELAY_FILE "delay.csv"
#define INST_FILE "inst.csv" //STORES PER PERIOD TPT & LAT
extern int gw_port;
extern const char *gw_address;
/* Utility functions */
int my_rand();
bool att_prob(float);
bool serv_prob(float);
void report_error(int);
void print_message(string);
void print_message(string,int);
void print_message(string,unsigned long long);
const char* to_char_array(unsigned long long);
string longToString(unsigned long long);
void trim(string& );
vector<string> split(char *, const char *);
int get_mix(vector<int>);
#! /usr/bin/env python
#import os
#os.sys.path.append('/usr/local/lib/python2.7/site-packages')
#print os.sys.path
from scapy.all import *
from time import *
def QoS_ping(host, count=10):
packet = Ether(dst="0c:42:a1:df:ac:49")/IP(dst=host)
#packet = Ether(dst="0c:42:a1:df:ac:49")/IP(dst=host)/UDP(dport=4321)/Raw(load="abc")
#packet = Ether()/IP(dst=host)/ICMP()
t=0.0
for x in range(count):
#t1=time()
ans,unans=srp(packet,iface="p0", verbose=0)
#t2=time()
rx = ans[0][1]
tx = ans[0][0]
delta = rx.time-tx.sent_time
#t+=t2-t1
t+=delta
return (t/count)*1000
if __name__=="__main__":
total = QoS_ping('192.168.220.34')
print "TOTAL", total
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment