summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdoc/AnalyticsWebReport.py24
-rwxr-xr-xdoc/TRexDataAnalysis.py181
-rw-r--r--doc/images/topology.pngbin0 -> 61332 bytes
-rwxr-xr-xdoc/trex_analytics.asciidoc80
-rwxr-xr-xdoc/trex_book.asciidoc27
-rw-r--r--doc/trex_toc.asciidoc2
-rw-r--r--doc/visio_drawings/topology.vsdbin0 -> 1317888 bytes
-rwxr-xr-xdoc/ws_main.py9
-rwxr-xr-xlinux/ws_main.py2
-rwxr-xr-xlinux_dpdk/ws_main.py1
-rwxr-xr-xscripts/automation/regression/aggregate_results.py63
-rwxr-xr-xsrc/bp_sim.cpp20
-rwxr-xr-xsrc/bp_sim.h52
-rwxr-xr-xsrc/common/Network/Packet/MacAddress.h128
-rwxr-xr-xsrc/common/basic_utils.cpp7
-rwxr-xr-xsrc/common/basic_utils.h1
-rw-r--r--src/gtest/client_cfg_test.cpp186
-rw-r--r--src/main_dpdk.cpp230
-rw-r--r--src/pre_test.cpp627
-rw-r--r--src/pre_test.h78
-rw-r--r--src/stateful_rx_core.cpp60
-rw-r--r--src/stateful_rx_core.h7
-rw-r--r--src/trex_client_config.cpp265
-rw-r--r--src/trex_client_config.h304
-rwxr-xr-xsrc/tuple_gen.cpp94
-rwxr-xr-xsrc/tuple_gen.h18
-rw-r--r--src/utl_ip.cpp121
-rw-r--r--src/utl_ip.h246
-rwxr-xr-xsrc/utl_yaml.cpp75
-rwxr-xr-xsrc/utl_yaml.h1
30 files changed, 2157 insertions, 752 deletions
diff --git a/doc/AnalyticsWebReport.py b/doc/AnalyticsWebReport.py
index 9bf186bd..182d8367 100755
--- a/doc/AnalyticsWebReport.py
+++ b/doc/AnalyticsWebReport.py
@@ -5,14 +5,20 @@ import TRexDataAnalysis as tr
import time
-def main():
- analytics = ac.initialize_analyticsreporting()
- # print 'retrieving data from Google Analytics'
- current_date = time.strftime("%Y-%m-%d")
- response = ac.get_report(analytics, '2016-11-06', current_date)
- ga_all_data_dict, setups = ac.export_to_tuples(response)
- tr.create_all_data(ga_all_data_dict, setups, '2016-11-06', current_date, save_path=os.getcwd() + '/images/',
- add_stats='yes')
+def main(verbose = False):
+ if verbose:
+ print('Retrieving data from Google Analytics')
+ analytics = ac.initialize_analyticsreporting()
+ current_date = time.strftime("%Y-%m-%d")
+ response = ac.get_report(analytics, '2016-11-06', current_date)
+ ga_all_data_dict, setups = ac.export_to_tuples(response)
+ dest_path = os.path.join(os.getcwd(), 'build', 'images')
+ if verbose:
+ print('Saving data to %s' % dest_path)
+ tr.create_all_data(ga_all_data_dict, setups, '2016-11-06', current_date, save_path = dest_path,
+ add_stats='yes')
+ if verbose:
+ print('Done without errors.')
if __name__ == "__main__":
- main()
+ main()
diff --git a/doc/TRexDataAnalysis.py b/doc/TRexDataAnalysis.py
index 3561b0f1..3155f16c 100755
--- a/doc/TRexDataAnalysis.py
+++ b/doc/TRexDataAnalysis.py
@@ -6,131 +6,90 @@ matplotlib.use('Agg')
from matplotlib import pyplot as plt
import os
-PATH_FOR_GRAPHS = 'Z:/trex/trex-doc/images/'
-
-
-def convert_dict_to_dframe(data, categories, index=''):
- data_input = {}
- for category in categories:
- data_input[category] = data[category]
- if index:
- df = pd.DataFrame(data_input, index=data[index])
- else:
- df = pd.DataFrame(data_input)
- return df
-
-
-def plot_bar_by_category(data_frame, category, index='', graph_name='graph.png', show='', gtitle='', save_path=''):
- if index:
- data_frame = data_frame.sort_index(by=index)
- print data_frame[index]
- else:
- print data_frame
- data_frame = pd.DataFrame(data_frame[category], columns=category).astype(float)
- data_frame.plot(kind='bar')
- plt.xticks(rotation='horizontal')
- plt.title(gtitle)
- if save_path:
- plt.savefig(save_path + graph_name)
- if show:
- plt.show()
-
-
-def generate_csv(data_frame, file_name, save_path=(os.getcwd() + "/")):
- f = open(save_path + file_name, 'w')
- data_frame.to_csv(f)
- f.close()
-
-
-# category is an array of category names that will appear as metrics
-def plot_bar_by_test_name(data_frame, test_name, category, graph_name='graph.png', show='', gtitle='', save_path=''):
- data_frame = data_frame[data_frame['Test_name'] == test_name]
- plot_bar_by_category(data_frame, category, 'Test_name', graph_name, show, gtitle=test_name, save_path=save_path)
-
def generate_dframe_for_test(test_name, test_data):
- test_results = []
- test_mins = set()
- test_maxs = set()
- for query in test_data:
- test_results.append(float(query[3]))
- test_mins.add(float(query[4]))
- test_maxs.add(float(query[5]))
- df = pd.DataFrame({test_name: test_results})
- stats = tuple([float(df.mean()), min(test_mins), max(test_maxs)]) # stats = (avg_mpps,min,max)
- return df, stats
+ test_results = []
+ test_mins = set()
+ test_maxs = set()
+ for query in test_data:
+ test_results.append(float(query[3]))
+ test_mins.add(float(query[4]))
+ test_maxs.add(float(query[5]))
+ df = pd.DataFrame({test_name: test_results})
+ stats = tuple([float(df.mean()), min(test_mins), max(test_maxs)]) # stats = (avg_mpps,min,max)
+ return df, stats
def generate_dframe_arr_and_stats_of_tests_per_setup(date, setup_name, setup_dict):
- dframe_arr_trend = []
- stats_arr = []
- dframe_arr_latest = []
- test_names = setup_dict.keys()
- for test in test_names:
- df, stats = generate_dframe_for_test(test, setup_dict[test])
- dframe_arr_trend.append(df)
- stats_arr.append(stats)
- df_latest = float(setup_dict[test][-1][3])
- dframe_arr_latest.append(df_latest)
- dframe_arr_latest = pd.DataFrame({'Date': [date] * len(dframe_arr_latest),
- 'Setup': [setup_name],
- 'Test Name': test_names,
- 'MPPS': dframe_arr_latest},
- index=range(1, len(dframe_arr_latest) + 1))
- stats_df = pd.DataFrame(stats_arr, index=setup_dict.keys(), columns=['Avg MPPS', 'Golden Min', 'Golden Max'])
- stats_df.index.name = 'Test Name'
- return dframe_arr_trend, stats_df, dframe_arr_latest
+ dframe_arr_trend = []
+ stats_arr = []
+ dframe_arr_latest = []
+ test_names = setup_dict.keys()
+ for test in test_names:
+ df, stats = generate_dframe_for_test(test, setup_dict[test])
+ dframe_arr_trend.append(df)
+ stats_arr.append(stats)
+ df_latest = float(setup_dict[test][-1][3])
+ dframe_arr_latest.append(df_latest)
+ dframe_arr_latest = pd.DataFrame({'Date': [date] * len(dframe_arr_latest),
+ 'Setup': [setup_name],
+ 'Test Name': test_names,
+ 'MPPS': dframe_arr_latest},
+ index=range(1, len(dframe_arr_latest) + 1))
+ stats_df = pd.DataFrame(stats_arr, index=setup_dict.keys(), columns=['Avg MPPS', 'Golden Min', 'Golden Max'])
+ stats_df.index.name = 'Test Name'
+ return dframe_arr_trend, stats_df, dframe_arr_latest
def create_plot_for_dframe_arr(dframe_arr, setup_name, start_date, end_date, show='no', save_path='',
- file_name='trend_graph'):
- dframe_all = pd.concat(dframe_arr, axis=1)
- dframe_all = dframe_all.astype(float)
- dframe_all.plot()
- plt.legend(fontsize='small', loc='best')
- plt.ylabel('MPPS')
- plt.title('Setup: ' + setup_name)
- plt.tick_params(
- axis='x',
- which='both',
- bottom='off',
- top='off',
- labelbottom='off')
- plt.xlabel('Time Period: ' + start_date + ' - ' + end_date)
- if save_path:
- plt.savefig(save_path + setup_name + file_name + '.png')
- if show == 'yes':
- plt.show()
+ file_name='trend_graph'):
+ dframe_all = pd.concat(dframe_arr, axis=1)
+ dframe_all = dframe_all.astype(float)
+ dframe_all.plot()
+ plt.legend(fontsize='small', loc='best')
+ plt.ylabel('MPPS')
+ plt.title('Setup: ' + setup_name)
+ plt.tick_params(
+ axis='x',
+ which='both',
+ bottom='off',
+ top='off',
+ labelbottom='off')
+ plt.xlabel('Time Period: ' + start_date + ' - ' + end_date)
+ if save_path:
+ plt.savefig(os.path.join(save_path, setup_name + file_name + '.png'))
+ if show == 'yes':
+ plt.show()
def create_bar_plot_for_latest_runs_per_setup(dframe_all_tests_latest, setup_name, show='no', save_path=''):
- plt.figure()
- dframe_all_tests_latest['MPPS'].plot(kind='bar', legend=False)
- dframe_all_tests_latest = dframe_all_tests_latest[['Test Name', 'Setup', 'Date', 'MPPS']]
- plt.xticks(rotation='horizontal')
- plt.xlabel('Index of Tests')
- plt.ylabel('MPPS')
- plt.title("Test Runs for Setup: " + setup_name)
- if save_path:
- plt.savefig(save_path + setup_name + '_latest_test_runs.png')
- dframe_all_tests_latest = dframe_all_tests_latest.round(2)
- dframe_all_tests_latest.to_csv(save_path + setup_name + '_latest_test_runs_stats.csv')
- if show == 'yes':
- plt.show()
+ plt.figure()
+ dframe_all_tests_latest['MPPS'].plot(kind='bar', legend=False)
+ dframe_all_tests_latest = dframe_all_tests_latest[['Test Name', 'Setup', 'Date', 'MPPS']]
+ plt.xticks(rotation='horizontal')
+ plt.xlabel('Index of Tests')
+ plt.ylabel('MPPS')
+ plt.title("Test Runs for Setup: " + setup_name)
+ if save_path:
+ plt.savefig(os.path.join(save_path, setup_name + '_latest_test_runs.png'))
+ dframe_all_tests_latest = dframe_all_tests_latest.round(2)
+ dframe_all_tests_latest.to_csv(os.path.join(save_path, setup_name + '_latest_test_runs_stats.csv'))
+ if show == 'yes':
+ plt.show()
def create_all_data_per_setup(setup_dict, setup_name, start_date, end_date, show='no', save_path='', add_stats=''):
- dframe_arr, stats_arr, dframe_latest_arr = generate_dframe_arr_and_stats_of_tests_per_setup(end_date, setup_name,
- setup_dict)
- create_bar_plot_for_latest_runs_per_setup(dframe_latest_arr, setup_name, show=show, save_path=save_path)
- create_plot_for_dframe_arr(dframe_arr, setup_name, start_date, end_date, show, save_path)
- if add_stats:
- stats_arr = stats_arr.round(2)
- stats_arr.to_csv(save_path + setup_name + '_trend_stats.csv')
- plt.close('all')
+ dframe_arr, stats_arr, dframe_latest_arr = generate_dframe_arr_and_stats_of_tests_per_setup(end_date, setup_name,
+ setup_dict)
+ create_bar_plot_for_latest_runs_per_setup(dframe_latest_arr, setup_name, show=show, save_path=save_path)
+ create_plot_for_dframe_arr(dframe_arr, setup_name, start_date, end_date, show, save_path)
+ if add_stats:
+ stats_arr = stats_arr.round(2)
+ stats_arr.to_csv(os.path.join(save_path, setup_name + '_trend_stats.csv'))
+ plt.close('all')
def create_all_data(ga_data, setup_names, start_date, end_date, save_path='', add_stats=''):
- for setup_name in setup_names:
- create_all_data_per_setup(ga_data[setup_name], setup_name, start_date, end_date, show='no', save_path=save_path,
- add_stats=add_stats)
+ for setup_name in setup_names:
+ create_all_data_per_setup(ga_data[setup_name], setup_name, start_date, end_date, show='no', save_path=save_path,
+ add_stats=add_stats)
diff --git a/doc/images/topology.png b/doc/images/topology.png
new file mode 100644
index 00000000..4e2ee65b
--- /dev/null
+++ b/doc/images/topology.png
Binary files differ
diff --git a/doc/trex_analytics.asciidoc b/doc/trex_analytics.asciidoc
index 84946dfe..bfe0d4fc 100755
--- a/doc/trex_analytics.asciidoc
+++ b/doc/trex_analytics.asciidoc
@@ -22,6 +22,54 @@ endif::backend-xhtml11[]
= Analytics
+== Setup: TRex07
+.Setup Details
+[options='header',halign='center']
+|====================================================================================================================
+|Name |OS |NICs |Routers
+| trex07 | Fedora 18| 2x10G (X710) (8 interfaces), 1x10G (2 interfaces), 1x1G (4 interfaces) | Loopback on X710 + ASA 5520 + ASA 5512 + ASA 5585-ssp10
+|====================================================================================================================
+
+image:images/trex07_latest_test_runs.png[title="trex07 test runs",align="left",width={p_width}, link="images/trex07_latest_test_runs.png"]
+
+[format="csv", options="header",halign='center']
+|===
+include::build/images/trex07_latest_test_runs_stats.csv[]
+|===
+
+=== Trend: Analysis Over Time
+
+image:images/trex07trend_graph.png[title="trex07trend_graph",align="left",width={p_width}, link="images/trex07trend_graph.png"]
+
+[format="csv", options="header",halign='center']
+|===
+include::build/images/trex07_trend_stats.csv[]
+|===
+
+== Setup: TRex08
+.Setup Details
+[options='header',halign='center']
+|====================================================================================================================
+|Name |OS |NICs |Routers
+| trex08 | Fedora 18| 2x10G (X710) (8 interfaces), 1x10G (2 interfaces), 1x1G (4 interfaces) | Loopback on X710 + ASA 5520 + ASA 5512 + ASA 5585-ssp10
+|====================================================================================================================
+
+image:images/trex08_latest_test_runs.png[title="trex08 test runs",align="left",width={p_width}, link="images/trex08_latest_test_runs.png"]
+
+[format="csv", options="header",halign='center']
+|===
+include::build/images/trex08_latest_test_runs_stats.csv[]
+|===
+
+=== Trend: Analysis Over Time
+
+image:images/trex08trend_graph.png[title="trex08trend_graph",align="left",width={p_width}, link="images/trex08trend_graph.png"]
+
+[format="csv", options="header",halign='center']
+|===
+include::build/images/trex08_trend_stats.csv[]
+|===
+
== Setup: TRex09
.Setup Details
@@ -35,7 +83,7 @@ image:images/trex09_latest_test_runs.png[title="trex09 test runs",align="left",w
[format="csv", options="header",halign='center']
|===
-include::images/trex09_latest_test_runs_stats.csv[]
+include::build/images/trex09_latest_test_runs_stats.csv[]
|===
=== Trend: Analysis Over Time
@@ -44,7 +92,31 @@ image:images/trex09trend_graph.png[title="trex09trend_graph",align="left",width=
[format="csv", options="header",halign='center']
|===
-include::images/trex09_trend_stats.csv[]
+include::build/images/trex09_trend_stats.csv[]
+|===
+
+== Setup: TRex11
+.Setup Details
+[options='header',halign='center']
+|====================================================================================================================
+|Name |OS |NICs |Routers
+| trex11 | Fedora 18| 2x10G (X710) (8 interfaces), 1x10G (2 interfaces), 1x1G (4 interfaces) | Loopback on X710 + ASA 5520 + ASA 5512 + ASA 5585-ssp10
+|====================================================================================================================
+
+image:images/trex11_latest_test_runs.png[title="trex11 test runs",align="left",width={p_width}, link="images/trex11_latest_test_runs.png"]
+
+[format="csv", options="header",halign='center']
+|===
+include::build/images/trex11_latest_test_runs_stats.csv[]
+|===
+
+=== Trend: Analysis Over Time
+
+image:images/trex11trend_graph.png[title="trex11trend_graph",align="left",width={p_width}, link="images/trex11trend_graph.png"]
+
+[format="csv", options="header",halign='center']
+|===
+include::build/images/trex11_trend_stats.csv[]
|===
== Setup: Kiwi02
@@ -58,7 +130,7 @@ image:images/kiwi02_latest_test_runs.png[title="trex09 test runs",align="left",w
[format="csv", options="header",halign='center']
|===
-include::images/kiwi02_latest_test_runs_stats.csv[]
+include::build/images/kiwi02_latest_test_runs_stats.csv[]
|===
=== Trend: Analysis Over Time
@@ -67,7 +139,7 @@ image:images/kiwi02trend_graph.png[title="kiwi02trend_graph",align="left",width=
[format="csv", options="header",halign='center']
|===
-include::images/kiwi02_trend_stats.csv[]
+include::build/images/kiwi02_trend_stats.csv[]
|===
diff --git a/doc/trex_book.asciidoc b/doc/trex_book.asciidoc
index fc69bdf4..ec661908 100755
--- a/doc/trex_book.asciidoc
+++ b/doc/trex_book.asciidoc
@@ -874,7 +874,8 @@ This feature allows more detailed clustering of clients.
Let's look at the following topology:
-image:images/client_clustering_topology.png[title="Client Clustering"]
+.Topology Example
+image:images/topology.png[title="Client Clustering",width=850]
We would like to configure two clusters and direct traffic to them.
@@ -980,15 +981,27 @@ MACs will be allocated incrementaly, with a wrap around.
e.g.
-* 16.0.0.1 --> 00:00:00:01:00:00
-* 16.0.0.2 --> 00:00:00:01:00:01
-* 16.0.0.3 --> 00:00:00:01:00:02
-* 16.0.0.4 --> 00:00:00:01:00:03
-* 16.0.0.5 --> 00:00:00:01:00:00
-* 16.0.0.6 --> 00:00:00:01:00:01
+*Initiator side:*
+
+* 16.0.0.1 --> dst_mac: 00:00:00:01:00:00 valn: 100
+* 16.0.0.2 --> dst_mac: 00:00:00:01:00:01 valn: 100
+* 16.0.0.3 --> dst_mac: 00:00:00:01:00:02 valn: 100
+* 16.0.0.4 --> dst_mac: 00:00:00:01:00:03 valn: 100
+* 16.0.0.5 --> dst_mac: 00:00:00:01:00:00 valn: 100
+* 16.0.0.6 --> dst_mac: 00:00:00:01:00:01 valn: 100
+
+*responder side:*
+
+
+
+* server ->16.0.0.1 dst_mac(from responder) : "01:00:00:00:02:01" , valn:201
+* server ->16.0.0.2 dst_mac(from responder) : "01:00:00:00:02:02" , valn:201
and so on.
+With this model every client (e.g. 16.0.0.1) will always have the same path, e.g.
+c->s side will always have initiator VLAN and init-destination MAC and in the response side (s->c) alway responder-VLAN and responder-MAC
+
*Usage:*
[source,bash]
diff --git a/doc/trex_toc.asciidoc b/doc/trex_toc.asciidoc
index a41d707f..eecb883f 100644
--- a/doc/trex_toc.asciidoc
+++ b/doc/trex_toc.asciidoc
@@ -24,7 +24,7 @@ ifdef::backend-xhtml11[]
<!-- load the theme CSS file -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet"/>
- <link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
+ <link href="https://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
<!-- include the jQuery library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js">
diff --git a/doc/visio_drawings/topology.vsd b/doc/visio_drawings/topology.vsd
new file mode 100644
index 00000000..d076023e
--- /dev/null
+++ b/doc/visio_drawings/topology.vsd
Binary files differ
diff --git a/doc/ws_main.py b/doc/ws_main.py
index 9d2882c8..58f6e98f 100755
--- a/doc/ws_main.py
+++ b/doc/ws_main.py
@@ -292,7 +292,7 @@ TOC_HEAD = """
<!-- load the theme CSS file -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet"/>
- <link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
+ <link href="https://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
<!-- include the jQuery library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js">
@@ -891,9 +891,9 @@ def build_cp(bld,dir,root,callback):
def create_analytic_report(task):
try:
import AnalyticsWebReport as analytics
- analytics.main()
- except:
- raise Exception('Error importing or using AnalyticsWebReport script')
+ analytics.main(verbose = Logs.verbose)
+ except Exception as e:
+ raise Exception('Error importing or using AnalyticsWebReport script: %s' % e)
@@ -923,6 +923,7 @@ def build(bld):
if bld.options.performance:
bld(rule=create_analytic_report)
+ bld.add_group()
bld(rule=convert_to_html_toc_book, source='trex_analytics.asciidoc waf.css', target='trex_analytics.html',scan=ascii_doc_scan);
return
diff --git a/linux/ws_main.py b/linux/ws_main.py
index b835e4ce..31d6b979 100755
--- a/linux/ws_main.py
+++ b/linux/ws_main.py
@@ -97,6 +97,7 @@ bp_sim_gtest = SrcGroup(dir='src',
src_list=[
'bp_gtest.cpp',
'gtest/tuple_gen_test.cpp',
+ 'gtest/client_cfg_test.cpp',
'gtest/nat_test.cpp',
'gtest/trex_stateless_gtest.cpp'
])
@@ -118,6 +119,7 @@ main_src = SrcGroup(dir='src',
'time_histogram.cpp',
'utl_json.cpp',
'utl_cpuu.cpp',
+ 'utl_ip.cpp',
'msg_manager.cpp',
'trex_port_attr.cpp',
'publisher/trex_publisher.cpp',
diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py
index 7fd73f2e..eccb4089 100755
--- a/linux_dpdk/ws_main.py
+++ b/linux_dpdk/ws_main.py
@@ -137,6 +137,7 @@ main_src = SrcGroup(dir='src',
'time_histogram.cpp',
'os_time.cpp',
'utl_cpuu.cpp',
+ 'utl_ip.cpp',
'utl_json.cpp',
'utl_yaml.cpp',
'nat_check.cpp',
diff --git a/scripts/automation/regression/aggregate_results.py b/scripts/automation/regression/aggregate_results.py
index c7c61ea6..130e0545 100755
--- a/scripts/automation/regression/aggregate_results.py
+++ b/scripts/automation/regression/aggregate_results.py
@@ -8,10 +8,8 @@ import sys, os
from collections import OrderedDict
import copy
import datetime, time
-try:
- import cPickle as pickle
-except:
- import pickle
+import traceback
+import yaml
import subprocess, shlex
from ansi2html import Ansi2HTMLConverter
@@ -25,6 +23,15 @@ FUNCTIONAL_CATEGORY = 'Functional' # how to display those categories
ERROR_CATEGORY = 'Error'
+def try_write(file, text):
+ try:
+ file.write(text)
+ except:
+ try:
+ file.write(text.encode('utf-8'))
+ except:
+ file.write(text.decode('utf-8'))
+
def pad_tag(text, tag):
return '<%s>%s</%s>' % (tag, text, tag)
@@ -256,6 +263,7 @@ if __name__ == '__main__':
build_url = os.environ.get('BUILD_URL')
build_id = os.environ.get('BUILD_ID')
trex_repo = os.environ.get('TREX_CORE_REPO')
+ last_commit_info_file = os.environ.get('LAST_COMMIT_INFO')
python_ver = os.environ.get('PYTHON_VER')
if not scenario:
print('Warning: no environment variable SCENARIO, using default')
@@ -283,19 +291,25 @@ if __name__ == '__main__':
trex_last_commit_info = ''
trex_last_commit_hash = trex_info_dict.get('Git SHA')
- if trex_last_commit_hash and trex_repo:
+ if last_commit_info_file and os.path.exists(last_commit_info_file):
+ with open(last_commit_info_file) as f:
+ trex_last_commit_info = f.read().strip().replace('\n', '<br>\n')
+ elif trex_last_commit_hash and trex_repo:
try:
- print('Getting TRex commit with hash %s' % trex_last_commit_hash)
- command = 'git --git-dir %s show %s --quiet' % (trex_repo, trex_last_commit_hash)
+ command = 'git show %s -s' % trex_last_commit_hash
print('Executing: %s' % command)
- proc = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (trex_last_commit_info, stderr) = proc.communicate()
- print('Stdout:\n\t' + trex_last_commit_info.replace('\n', '\n\t'))
- print('Stderr:', stderr)
- print('Return code:', proc.returncode)
- trex_last_commit_info = trex_last_commit_info.replace('\n', '<br>')
+ proc = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.STDOUT, cwd = trex_repo)
+ (stdout, stderr) = proc.communicate()
+ stdout = stdout.decode('utf-8', errors = 'replace')
+ print('Stdout:\n\t' + stdout.replace('\n', '\n\t'))
+ if stderr or proc.returncode:
+ print('Return code: %s' % proc.returncode)
+ trex_last_commit_info = stdout.replace('\n', '<br>\n')
except Exception as e:
+ traceback.print_exc()
print('Error getting last commit: %s' % e)
+ else:
+ print('Could not find info about commit!')
##### get xmls: report_<setup name>.xml
@@ -520,7 +534,7 @@ if __name__ == '__main__':
# save html
with open(args.output_htmlfile, 'w') as f:
print('Writing output file: %s' % args.output_htmlfile)
- f.write(html_output)
+ try_write(f, html_output)
html_output = None
# mail report (only error tests, expanded)
@@ -596,7 +610,7 @@ if __name__ == '__main__':
else:
mail_output += add_category_of_tests(ERROR_CATEGORY, error_tests, expanded=True)
else:
- mail_output += '<table><tr style="font-size:120;color:green;font-family:arial"><td>☺</td><td style="font-size:20">All passed.</td></tr></table>\n'
+ mail_output += u'<table><tr style="font-size:120;color:green;font-family:arial"><td>☺</td><td style="font-size:20">All passed.</td></tr></table>\n'
mail_output += '\n</body>\n</html>'
##### save outputs
@@ -605,17 +619,17 @@ if __name__ == '__main__':
# mail content
with open(args.output_mailfile, 'w') as f:
print('Writing output file: %s' % args.output_mailfile)
- f.write(mail_output)
+ try_write(f, mail_output)
# build status
category_dict_status = {}
if os.path.exists(args.build_status_file):
print('Reading: %s' % args.build_status_file)
- with open(args.build_status_file, 'rb') as f:
+ with open(args.build_status_file, 'r') as f:
try:
- category_dict_status = pickle.load(f)
+ category_dict_status = yaml.safe_load(f.read())
except Exception as e:
- print('Error during pickle load: %s' % e)
+ print('Error during YAML load: %s' % e)
if type(category_dict_status) is not dict:
print('%s is corrupt, truncating' % args.build_status_file)
category_dict_status = {}
@@ -635,15 +649,15 @@ if __name__ == '__main__':
current_status = 'Fixed'
category_dict_status[scenario] = current_status
- with open(args.build_status_file, 'wb') as f:
+ with open(args.build_status_file, 'w') as f:
print('Writing output file: %s' % args.build_status_file)
- pickle.dump(category_dict_status, f)
+ yaml.dump(category_dict_status, f)
# last successful commit
- if (current_status in ('Successful', 'Fixed')) and trex_last_commit_hash and jobs_list > 0 and scenario == 'nightly':
+ if (current_status in ('Successful', 'Fixed')) and trex_last_commit_hash and len(jobs_list) > 0 and scenario == 'nightly':
with open(args.last_passed_commit, 'w') as f:
print('Writing output file: %s' % args.last_passed_commit)
- f.write(trex_last_commit_hash)
+ try_write(f, trex_last_commit_hash)
# mail title
mailtitle_output = scenario.capitalize()
@@ -653,7 +667,8 @@ if __name__ == '__main__':
with open(args.output_titlefile, 'w') as f:
print('Writing output file: %s' % args.output_titlefile)
- f.write(mailtitle_output)
+ try_write(f, mailtitle_output)
# exit
+ print('Status: %s' % current_status)
sys.exit(exit_status)
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index c1df72fc..80297c32 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -4577,6 +4577,22 @@ int CFlowGenList::load_client_config_file(std::string file_name) {
return (0);
}
+void CFlowGenList::set_client_config_tuple_gen_info(CTupleGenYamlInfo * tg) {
+ m_client_config_info.set_tuple_gen_info(tg);
+}
+
+void CFlowGenList::get_client_cfg_ip_list(std::vector<ClientCfgCompactEntry *> &ret) {
+ m_client_config_info.get_entry_list(ret);
+}
+
+void CFlowGenList::set_client_config_resolved_macs(CManyIPInfo &pretest_result) {
+ m_client_config_info.set_resolved_macs(pretest_result);
+}
+
+void CFlowGenList::dump_client_config(FILE *fd) {
+ m_client_config_info.dump(fd);
+}
+
int CFlowGenList::load_from_yaml(std::string file_name,
uint32_t num_threads){
uint8_t idx;
@@ -5232,11 +5248,11 @@ void CErfIF::add_vlan(uint16_t vlan_id) {
m_raw->pkt_len += 4;
}
-void CErfIF::apply_client_config(const ClientCfg *cfg, pkt_dir_t dir) {
+void CErfIF::apply_client_config(const ClientCfgBase *cfg, pkt_dir_t dir) {
assert(cfg);
uint8_t *p = (uint8_t *)m_raw->raw;
- const ClientCfgDir &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
+ const ClientCfgDirBase &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
/* dst mac */
if (cfg_dir.has_dst_mac_addr()) {
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 0cf77437..914a26d9 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -44,6 +44,7 @@ limitations under the License.
#include <common/bitMan.h>
#include <yaml-cpp/yaml.h>
#include "trex_defs.h"
+#include "utl_ip.h"
#include "os_time.h"
#include "pal_utl.h"
#include "rx_check_header.h"
@@ -72,12 +73,6 @@ class CGenNodePCAP;
#define FORCE_NO_INLINE __attribute__ ((noinline))
#define FORCE_INLINE __attribute__((always_inline))
-/* IP address, last 32-bits of IPv6 remaps IPv4 */
-typedef struct {
- uint16_t v6[6]; /* First 96-bits of IPv6 */
- uint32_t v4; /* Last 32-bits IPv6 overloads v4 */
-} ipaddr_t;
-
/* reserve both 0xFF and 0xFE , router will -1 FF */
#define TTL_RESERVE_DUPLICATE 0xff
#define TOS_TTL_RESERVE_DUPLICATE 0x1
@@ -175,38 +170,6 @@ typedef enum { VM_REPLACE_IP_OFFSET =0x12, /* fix ip at offset */
/* work only on x86 littel */
#define MY_B(b) (((int)b)&0xff)
-// Routine to create IPv4 address string
-inline int ip_to_str(uint32_t ip,char * str){
- uint32_t ipv4 = PKT_HTONL(ip);
- inet_ntop(AF_INET, (const char *)&ipv4, str, INET_ADDRSTRLEN);
- return(strlen(str));
-}
-
-inline std::string ip_to_str(uint32_t ip) {
- char tmp[INET_ADDRSTRLEN];
- ip_to_str(ip, tmp);
- return tmp;
-}
-
-// Routine to create IPv6 address string
-inline int ipv6_to_str(ipaddr_t *ip,char * str){
- int idx=0;
- uint16_t ipv6[8];
- for (uint8_t i=0; i<6; i++) {
- ipv6[i] = PKT_HTONS(ip->v6[i]);
- }
- uint32_t ipv4 = PKT_HTONL(ip->v4);
- ipv6[6] = ipv4 & 0xffff;
- ipv6[7] = ipv4 >> 16;
-
- str[idx++] = '[';
- inet_ntop(AF_INET6, (const char *)&ipv6, &str[1], INET6_ADDRSTRLEN);
- idx = strlen(str);
- str[idx++] = ']';
- str[idx] = 0;
- return(idx);
-}
-
class CFlowPktInfo ;
class CMiniVM {
@@ -694,19 +657,16 @@ class CPerPortIPCfg {
uint32_t get_mask() {return m_mask;}
uint32_t get_def_gw() {return m_def_gw;}
uint32_t get_vlan() {return m_vlan;}
- bool grat_arp_needed() {return m_grat_arp_needed;}
void set_ip(uint32_t val) {m_ip = val;}
void set_mask(uint32_t val) {m_mask = val;}
void set_def_gw(uint32_t val) {m_def_gw = val;}
void set_vlan(uint16_t val) {m_vlan = val;}
- void set_grat_arp_needed(bool val) {m_grat_arp_needed = val;}
private:
uint32_t m_def_gw;
uint32_t m_ip;
uint32_t m_mask;
uint16_t m_vlan;
- bool m_grat_arp_needed;
};
class CParserOption {
@@ -1564,7 +1524,7 @@ public:
uint32_t m_nat_tcp_seq_diff_server; // And some do seq num randomization for server->client also
uint16_t m_nat_external_port; // NAT client port
uint16_t m_nat_pad[1];
- const ClientCfg *m_client_cfg;
+ const ClientCfgBase *m_client_cfg;
uint32_t m_src_idx;
uint32_t m_dest_idx;
uint32_t m_end_of_cache_line[6];
@@ -1889,7 +1849,7 @@ typedef std::priority_queue<CGenNode *, std::vector<CGenNode *>,CGenNodeCompare>
class CErfIF : public CVirtualIF {
-
+ friend class basic_client_cfg_test1_Test;
public:
CErfIF(){
m_writer=NULL;
@@ -1928,7 +1888,7 @@ public:
protected:
void add_vlan(uint16_t vlan_id);
- void apply_client_config(const ClientCfg *cfg, pkt_dir_t dir);
+ void apply_client_config(const ClientCfgBase *cfg, pkt_dir_t dir);
virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir);
CFileWriterBase * m_writer;
@@ -4031,6 +3991,10 @@ public:
int load_from_yaml(std::string csv_file,uint32_t num_threads);
int load_client_config_file(std::string file_name);
+ void set_client_config_tuple_gen_info(CTupleGenYamlInfo * tg);
+ void get_client_cfg_ip_list(std::vector<ClientCfgCompactEntry *> &ret);
+ void set_client_config_resolved_macs(CManyIPInfo &pretest_result);
+ void dump_client_config(FILE *fd);
public:
void Dump(FILE *fd);
diff --git a/src/common/Network/Packet/MacAddress.h b/src/common/Network/Packet/MacAddress.h
index 7e872fd6..5dc4a9ea 100755
--- a/src/common/Network/Packet/MacAddress.h
+++ b/src/common/Network/Packet/MacAddress.h
@@ -29,7 +29,7 @@ public:
MacAddress()
{
- set(0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef);
+ set(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
};
MacAddress(uint8_t a0,
@@ -47,15 +47,15 @@ public:
a5);
};
- MacAddress(uint8_t macAddr[ETHER_ADDR_LEN])
- {
- set(macAddr[0],
- macAddr[1],
- macAddr[2],
- macAddr[3],
- macAddr[4],
- macAddr[5] );
- };
+ MacAddress(uint8_t macAddr[ETHER_ADDR_LEN])
+ {
+ set(macAddr[0],
+ macAddr[1],
+ macAddr[2],
+ macAddr[3],
+ macAddr[4],
+ macAddr[5] );
+ };
void set(uint8_t a0,
uint8_t a1,
@@ -81,50 +81,78 @@ public:
data[5]=val;
}
+ void set(uint64_t val) {
+ for (int i = 0; i < 6; i++) {
+ data[i] = ( val >> ((5 - i) * 8) ) & 0xFF;
+ }
+ }
+
+ bool isDefaultAddress() const
+ {
+ static MacAddress defaultMac;
+ return (*this == defaultMac);
+ }
+
+ bool isInvalidAddress() const
+ {
+ static MacAddress allZeros(0,0,0,0,0,0);
+ static MacAddress defaultMac;
+ return (*this == allZeros || *this == defaultMac);
+ }
+ void setIdentifierAsBogusAddr(uint32_t identifier)
+ {
+ *(uint32_t*)data = identifier;
+ }
+
+ uint32_t getIdentifierFromBogusAddr()
+ {
+ return *(uint32_t*)data;
+ }
+
+ MacAddress& operator+=(const int& val) {
+ uint64_t tmp = 0;
+
+ for (int i = 0; i < 6; i++) {
+ tmp <<= 8;
+ tmp |= data[i];
+ }
- bool isInvalidAddress() const
- {
- static MacAddress allZeros(0,0,0,0,0,0);
- static MacAddress cafeDeadBeef;
- return (*this == allZeros || *this == cafeDeadBeef);
- }
- void setIdentifierAsBogusAddr(uint32_t identifier)
- {
- *(uint32_t*)data = identifier;
- }
-
- uint32_t getIdentifierFromBogusAddr()
- {
- return *(uint32_t*)data;
- }
-
- bool operator == (const MacAddress& rhs) const
- {
- for(int i = 0; i < ETHER_ADDR_LEN; i++)
- {
- if(data[i] != rhs.data[i])
- return false;
- }
-
- return true;
- }
-
- uint8_t* GetBuffer()
- {
- return data;
- }
-
- const uint8_t* GetConstBuffer() const
- {
- return data;
- }
+ tmp += val;
+
+ for (int i = 0; i < 6; i++) {
+ data[i] = ( tmp >> ((5 - i) * 8) ) & 0xFF;
+ }
+
+ return *this;
+ }
+
+ bool operator == (const MacAddress& rhs) const
+ {
+ for(int i = 0; i < ETHER_ADDR_LEN; i++)
+ {
+ if(data[i] != rhs.data[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ uint8_t* GetBuffer()
+ {
+ return data;
+ }
+
+ const uint8_t* GetConstBuffer() const
+ {
+ return data;
+ }
void dump(FILE *fd) const;
- void copyToArray(uint8_t *arrayToFill) const
- {
+ void copyToArray(uint8_t *arrayToFill) const
+ {
((uint32_t*)arrayToFill)[0] = ((uint32_t*)data)[0];//Copy first 32bit
- ((uint16_t*)arrayToFill)[2] = ((uint16_t*)data)[2];//Copy last 16bit
- }
+ ((uint16_t*)arrayToFill)[2] = ((uint16_t*)data)[2];//Copy last 16bit
+ }
public:
uint8_t data[ETHER_ADDR_LEN];
diff --git a/src/common/basic_utils.cpp b/src/common/basic_utils.cpp
index dfd3b183..d8a95b53 100755
--- a/src/common/basic_utils.cpp
+++ b/src/common/basic_utils.cpp
@@ -178,6 +178,13 @@ void TestDump(void){
utl_DumpBuffer2(stdout,buffer,31,1,4,SHOW_BUFFER_ADDR_EN |SHOW_BUFFER_CHAR);
}
+std::string
+utl_macaddr_to_str(const uint8_t *mac) {
+ std::string tmp;
+ utl_macaddr_to_str(mac, tmp);
+ return tmp;
+}
+
void utl_macaddr_to_str(const uint8_t *macaddr, std::string &output) {
for (int i = 0; i < 6; i++) {
diff --git a/src/common/basic_utils.h b/src/common/basic_utils.h
index ab0ff1ec..ce2da691 100755
--- a/src/common/basic_utils.h
+++ b/src/common/basic_utils.h
@@ -85,6 +85,7 @@ inline void utl_swap(T& a, T& b) {
bool utl_is_file_exists (const std::string& name) ;
void utl_macaddr_to_str(const uint8_t *macaddr, std::string &output);
+std::string utl_macaddr_to_str(const uint8_t *macaddr);
std::string utl_macaddr_to_str(const uint8_t *macaddr);
bool utl_str_to_macaddr(const std::string &s, uint8_t *mac);
diff --git a/src/gtest/client_cfg_test.cpp b/src/gtest/client_cfg_test.cpp
new file mode 100644
index 00000000..1e84e1d5
--- /dev/null
+++ b/src/gtest/client_cfg_test.cpp
@@ -0,0 +1,186 @@
+/*
+ Ido Barnea
+
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+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
+
+ http://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.
+*/
+#include <stdio.h>
+#include "../bp_sim.h"
+#include <common/gtest.h>
+#include <common/basic_utils.h>
+
+class basic_client_cfg : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+ public:
+};
+
+TEST_F(basic_client_cfg, test1) {
+ uint32_t ip_start = 0x10010101;
+ uint32_t ip_end = 0x100101ff;
+ uint32_t next_hop_init = 0x01010101;
+ uint32_t next_hop_resp = 0x02020202;
+ uint16_t vlan_init = 5;
+ uint16_t vlan_resp = 7;
+ uint32_t dual_if_mask = 0x01000000;
+ uint32_t test_count = 2;
+ ClientCfgDB cfg_db;
+ ClientCfgDB test_db;
+ ClientCfgEntry cfg_ent;
+ ClientCfgExt cfg_ext;
+ std::vector<ClientCfgCompactEntry *> ent_list;
+ struct CTupleGenPoolYaml c_pool;
+
+ // Create tuple gen, so we can have ip->port translation
+ CTupleGenYamlInfo tg_yam_info;
+ struct CTupleGenPoolYaml s_pool;
+ s_pool.m_ip_start = ip_start;
+ s_pool.m_ip_end = ip_end;
+ s_pool.m_dual_interface_mask = dual_if_mask;
+ tg_yam_info.m_client_pool.push_back(s_pool);
+
+ CGlobalInfo::m_options.m_expected_portd = 4;
+ printf("Expected ports %d\n", CGlobalInfo::m_options.m_expected_portd);
+
+ std::string tmp_file_name = "/tmp/client_cfg_gtest.yaml";
+ FILE *fd = fopen(tmp_file_name.c_str(), "w");
+
+ if (fd == NULL) {
+ fprintf(stderr, "Failed opening %s file for write\n", tmp_file_name.c_str());
+ }
+
+ // We create config file with 3 groups (Should match 6 ports).
+ cfg_ext.m_initiator.set_next_hop(next_hop_init);
+ cfg_ext.m_responder.set_next_hop(next_hop_resp);
+ cfg_ext.m_initiator.set_vlan(vlan_init);
+ cfg_ext.m_responder.set_vlan(vlan_resp);
+
+ cfg_ent.set_params(ip_start, ip_end, test_count);
+ cfg_ent.set_cfg(cfg_ext);
+
+ // first group
+ cfg_db.set_vlan(true);
+ cfg_db.add_group(ip_start, cfg_ent);
+
+ //second group
+ cfg_ent.set_params(ip_start + dual_if_mask, ip_end + dual_if_mask
+ , test_count);
+ cfg_db.add_group(ip_start + dual_if_mask, cfg_ent);
+
+ // third group
+ cfg_ent.set_params(ip_start + 2 * dual_if_mask, ip_end + 2 * dual_if_mask
+ , test_count);
+ cfg_db.add_group(ip_start + dual_if_mask * 2, cfg_ent);
+
+ cfg_db.dump(fd);
+ fclose(fd);
+ test_db.load_yaml_file(tmp_file_name);
+ test_db.set_tuple_gen_info(&tg_yam_info);
+ test_db.get_entry_list(ent_list);
+
+
+ // We expect ports for first two groups to be found.
+ // This group addresses should not appear in the list, since
+ // we simulate system with only 4 ports
+ int i = 0;
+ for (std::vector<ClientCfgCompactEntry *>::iterator
+ it = ent_list.begin(); it != ent_list.end(); it++) {
+ uint8_t port = (*it)->get_port();
+ uint16_t vlan = (*it)->get_vlan();
+ uint32_t count = (*it)->get_count();
+ uint32_t dst_ip = (*it)->get_dst_ip();
+
+ assert(count == test_count);
+ switch(i) {
+ case 0:
+ case 2:
+ assert(port == i);
+ assert(vlan == vlan_init);
+ assert(dst_ip == next_hop_init);
+ break;
+ case 1:
+ case 3:
+ assert(port == i);
+ assert(vlan == vlan_resp);
+ assert(dst_ip == next_hop_resp);
+ break;
+ default:
+ fprintf(stderr, "Test failed. Too many entries returned\n");
+ exit(1);
+ }
+ i++;
+ delete *it;
+ }
+
+ // Simulate the pre test phase, and hand results to client config
+ CManyIPInfo many_ip;
+ MacAddress mac0, mac1, mac2, mac3;
+ mac0.set(0x0, 0x1, 0x2, 0x3, 0x4, 0);
+ mac1.set(0x0, 0x1, 0x2, 0x3, 0x4, 0x1);
+ mac2.set(0x0, 0x1, 0x2, 0x3, 0x4, 0x2);
+ mac3.set(0x0, 0x1, 0x2, 0x3, 0x4, 0x3);
+ COneIPv4Info ip0_1(next_hop_init, vlan_init, mac0, 0);
+ COneIPv4Info ip0_2(next_hop_init + 1, vlan_init, mac1, 0);
+ COneIPv4Info ip1_1(next_hop_resp, vlan_resp, mac2, 1);
+ COneIPv4Info ip1_2(next_hop_resp + 1, vlan_resp, mac3, 1);
+
+ many_ip.insert(ip0_1);
+ many_ip.insert(ip0_2);
+ many_ip.insert(ip1_1);
+ many_ip.insert(ip1_2);
+
+ test_db.set_resolved_macs(many_ip);
+
+ ClientCfgBase cfg0;
+
+ ClientCfgEntry *ent0 = test_db.lookup(ip_start);
+ ClientCfgEntry *ent1 = test_db.lookup(ip_start + dual_if_mask);
+
+ assert (ent0 != NULL);
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac0.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac1.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac2.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac3.GetConstBuffer(), ETHER_ADDR_LEN));
+
+ assert(ent1 != NULL);
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac0.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac1.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac2.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac3.GetConstBuffer(), ETHER_ADDR_LEN));
+
+}
+
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index e799a5bd..af6d8366 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -486,11 +486,11 @@ public:
private:
- virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id,
- uint16_t type, uint8_t ttl,
- uint16_t ip_id,
+ virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id,
+ uint16_t type, uint8_t ttl,
+ uint16_t ip_id,
uint8_t l4_proto,
- int queue,
+ int queue,
uint16_t stat_idx);
virtual int configure_rx_filter_rules_statfull(CPhyEthIF * _if);
@@ -1123,6 +1123,9 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
if ( opt_vlan_was_set ) {
po->preview.set_vlan_mode_enable(true);
}
+ if (CGlobalInfo::m_options.client_cfg_file != "") {
+ parse_err("Client config file is not supported with interactive (stateless) mode ");
+ }
if ( po->m_duration ) {
parse_err("Duration is not supported with interactive (stateless) mode ");
}
@@ -1970,7 +1973,7 @@ public:
__attribute__ ((noinline)) void handle_rx_queue();
__attribute__ ((noinline)) void handle_slowpath_features(CGenNode *node, rte_mbuf_t *m, uint8_t *p, pkt_dir_t dir);
- void apply_client_cfg(const ClientCfg *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p);
+ void apply_client_cfg(const ClientCfgBase *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p);
bool process_rx_pkt(pkt_dir_t dir,rte_mbuf_t * m);
@@ -2361,12 +2364,12 @@ int CCoreEthIFStateless::handle_slow_path_node(CGenNode * no) {
return (-1);
}
-void CCoreEthIF::apply_client_cfg(const ClientCfg *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p) {
+void CCoreEthIF::apply_client_cfg(const ClientCfgBase *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p) {
assert(cfg);
/* take the right direction config */
- const ClientCfgDir &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
+ const ClientCfgDirBase &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
/* dst mac */
if (cfg_dir.has_dst_mac_addr()) {
@@ -3181,74 +3184,162 @@ void CGlobalTRex::pre_test() {
CPretest pretest(m_max_ports);
bool resolve_needed = false;
uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
+ bool need_grat_arp[TREX_MAX_PORTS];
+
+ if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ std::vector<ClientCfgCompactEntry *> conf;
+ m_fl.get_client_cfg_ip_list(conf);
+
+ // If we got src MAC for port in global config, take it, otherwise use src MAC from DPDK
+ uint8_t port_macs[m_max_ports][ETHER_ADDR_LEN];
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
+ if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
+ rte_eth_macaddr_get(port_id,
+ (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
+ }
+ memcpy(port_macs[port_id], CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, ETHER_ADDR_LEN);
+ }
+
+ for (std::vector<ClientCfgCompactEntry *>::iterator it = conf.begin(); it != conf.end(); it++) {
+ uint8_t port = (*it)->get_port();
+ uint16_t vlan = (*it)->get_vlan();
+ uint32_t count = (*it)->get_count();
+ uint32_t dst_ip = (*it)->get_dst_ip();
+ uint32_t src_ip = (*it)->get_src_ip();
+
+ for (int i = 0; i < count; i++) {
+ //??? handle ipv6;
+ if ((*it)->is_ipv4()) {
+ pretest.add_next_hop(port, dst_ip + i, vlan);
+ }
+ }
+ if (!src_ip) {
+ src_ip = CGlobalInfo::m_options.m_ip_cfg[port].get_ip();
+ if (!src_ip) {
+ fprintf(stderr, "No matching src ip for port: %d ip:%s vlan: %d\n"
+ , port, ip_to_str(dst_ip).c_str(), vlan);
+ fprintf(stderr, "You must specify src_ip in client config file or in TRex config file\n");
+ exit(1);
+ }
+ }
+ pretest.add_ip(port, src_ip, vlan, port_macs[port]);
+ COneIPv4Info ipv4(src_ip, vlan, port_macs[port], port);
+ m_mg.add_grat_arp_src(ipv4);
+
+ delete *it;
+ }
+ if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
+ fprintf(stdout, "*******Pretest for client cfg********\n");
+ pretest.dump(stdout);
+ }
+ } else {
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
+ resolve_needed = true;
+ } else {
+ resolve_needed = false;
+ }
+ if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
+ rte_eth_macaddr_get(port_id,
+ (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
+ need_grat_arp[port_id] = true;
+ } else {
+ // If we got src MAC from config file, do not send gratuitous ARP for it
+ // (for compatibility with old behaviour)
+ need_grat_arp[port_id] = false;
+ }
+
+ pretest.add_ip(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip()
+ , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan()
+ , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
+
+ if (resolve_needed) {
+ pretest.add_next_hop(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw()
+ , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan());
+ }
+ }
+ }
for (int port_id = 0; port_id < m_max_ports; port_id++) {
CPhyEthIF *pif = &m_ports[port_id];
// Configure port to send all packets to software
CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, true);
- if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
- resolve_needed = true;
- } else {
- resolve_needed = false;
- }
- if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
- rte_eth_macaddr_get(port_id,
- (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
- CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(true);
- } else {
- // If we got src MAC from config file, do not send gratuitous ARP for it (for compatibility with old behaviour)
- CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(false);
- }
- pretest.set_port_params(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id]
- , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src
- , resolve_needed);
}
+
pretest.send_grat_arp_all();
bool ret;
int count = 0;
+ bool resolve_failed = false;
do {
ret = pretest.resolve_all();
count++;
} while ((ret != true) && (count < 10));
+ if (ret != true) {
+ resolve_failed = true;
+ }
- if ( CGlobalInfo::m_options.preview.getVMode() > 0) {
+ if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
+ fprintf(stdout, "*******Pretest after resolving ********\n");
pretest.dump(stdout);
}
- uint8_t mac[ETHER_ADDR_LEN];
- for (int port_id = 0; port_id < m_max_ports; port_id++) {
- if (! memcmp(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
- // we don't have dest MAC. Get it from what we resolved.
- uint32_t ip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
- if (! pretest.get_mac(port_id, ip, mac)) {
- fprintf(stderr, "Failed resolving dest MAC for default gateway:%d.%d.%d.%d on port %d\n"
- , (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, port_id);
- exit(1);
+
+ if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ CManyIPInfo pretest_result;
+ pretest.get_results(pretest_result);
+ if (resolve_failed) {
+ fprintf(stderr, "Resolution of following IPs failed. Exiting.\n");
+ for (const COneIPInfo *ip=pretest_result.get_next(); ip != NULL;
+ ip = pretest_result.get_next()) {
+ ip->dump(stderr);
}
- memcpy(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, mac, ETHER_ADDR_LEN);
-
- // if port is connected in loopback, no need to send gratuitous ARP. It will only confuse our ingress counters.
- if (pretest.is_loopback(port_id))
- CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(false);
+ exit(-1);
+ }
+ m_fl.set_client_config_resolved_macs(pretest_result);
+ if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
+ m_fl.dump_client_config(stdout);
}
- // update statistics baseline, so we can ignore what happened in pre test phase
- CPhyEthIF *pif = &m_ports[port_id];
- CPreTestStats pre_stats = pretest.get_stats(port_id);
- pif->set_ignore_stats_base(pre_stats);
-
- // Configure port back to normal mode. Only relevant packets handled by software.
- CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, false);
-
+ } else {
+ uint8_t mac[ETHER_ADDR_LEN];
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ if (! memcmp(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
+ // we don't have dest MAC. Get it from what we resolved.
+ uint32_t ip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
+ uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
+ if (! pretest.get_mac(port_id, ip, vlan, mac)) {
+ fprintf(stderr, "Failed resolving dest MAC for default gateway:%d.%d.%d.%d on port %d\n"
+ , (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, port_id);
+ exit(1);
+ }
+ memcpy(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, mac, ETHER_ADDR_LEN);
+ // if port is connected in loopback, no need to send gratuitous ARP. It will only confuse our ingress counters.
+ if (need_grat_arp[port_id] && (! pretest.is_loopback(port_id))) {
+ COneIPv4Info ipv4(CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip()
+ , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan()
+ , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src
+ , port_id);
+ m_mg.add_grat_arp_src(ipv4);
+ }
+ }
- /* set resolved IPv4 */
- uint32_t dg = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
- const uint8_t *dst_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest;
- if (dg) {
- m_ports[port_id].get_port_attr()->get_dest().set_dest_ipv4(dg, dst_mac);
- } else {
- m_ports[port_id].get_port_attr()->get_dest().set_dest_mac(dst_mac);
- }
+ // update statistics baseline, so we can ignore what happened in pre test phase
+ CPhyEthIF *pif = &m_ports[port_id];
+ CPreTestStats pre_stats = pretest.get_stats(port_id);
+ pif->set_ignore_stats_base(pre_stats);
+
+ // Configure port back to normal mode. Only relevant packets handled by software.
+ CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, false);
+
+ /* set resolved IPv4 */
+ uint32_t dg = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
+ const uint8_t *dst_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest;
+ if (dg) {
+ m_ports[port_id].get_port_attr()->get_dest().set_dest_ipv4(dg, dst_mac);
+ } else {
+ m_ports[port_id].get_port_attr()->get_dest().set_dest_mac(dst_mac);
+ }
}
@@ -4744,6 +4835,8 @@ int CGlobalTRex::start_master_statefull() {
exit(-1);
}
CGlobalInfo::m_options.preview.set_client_cfg_enable(true);
+ m_fl.set_client_config_tuple_gen_info(&m_fl.m_yaml_info.m_tuple_gen);
+ pre_test();
}
/* verify options */
@@ -5485,7 +5578,10 @@ int main_test(int argc , char * argv[]){
}
}
- g_trex.pre_test();
+ // in case of client config, we already run pretest
+ if (! CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ g_trex.pre_test();
+ }
// after doing all needed ARP resolution, we need to flush queues, and stop our drop queue
g_trex.ixgbe_rx_queue_flush();
@@ -6442,15 +6538,15 @@ void CTRexExtendedDriverBaseMlnx5G::update_configuration(port_cfg_t * cfg){
cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos=0x01;
cfg->m_port_conf.fdir_conf.mask.ipv6_mask.proto=0xff;
cfg->m_port_conf.fdir_conf.mask.ipv6_mask.tc=0x01;
-
+
}
-void CTRexExtendedDriverBaseMlnx5G::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type,
- uint8_t ttl,
- uint16_t ip_id,
- uint8_t l4_proto,
+void CTRexExtendedDriverBaseMlnx5G::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type,
+ uint8_t ttl,
+ uint16_t ip_id,
+ uint8_t l4_proto,
int queue, uint16_t stat_idx) {
- /* Mellanox card does not have TTL support,
+ /* Mellanox card does not have TTL support,
so we will replace it in low level with TOS */
int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
@@ -6520,8 +6616,8 @@ int CTRexExtendedDriverBaseMlnx5G::add_del_rx_flow_stat_rule(uint8_t port_id, en
int CTRexExtendedDriverBaseMlnx5G::configure_rx_filter_rules_statfull(CPhyEthIF * _if) {
uint32_t port_id = _if->get_port_id();
/* TTL==TOS */
-
- /*PID=1 ==> MASK TOS=0x1/0x1*/
+
+ /*PID=1 ==> MASK TOS=0x1/0x1*/
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 0x1, 1, 17, MAIN_DPDK_RX_Q, 0); /*TCP/UDP */
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, 0x1, 1, 6, MAIN_DPDK_RX_Q, 0);
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 0x1, 1, 132, MAIN_DPDK_RX_Q, 0); /*SCTP*/
@@ -6586,7 +6682,7 @@ void CTRexExtendedDriverBaseMlnx5G::get_extended_stats(CPhyEthIF * _if,CPhyEthIF
rte_eth_stats_get(_if->get_port_id(), &stats1);
stats->ipackets += stats1.ipackets - prev_stats->ipackets;
- stats->ibytes += stats1.ibytes - prev_stats->ibytes +
+ stats->ibytes += stats1.ibytes - prev_stats->ibytes +
+ (stats1.ipackets << 2) - (prev_stats->ipackets << 2);
stats->opackets += stats1.opackets - prev_stats->opackets;
stats->obytes += stats1.obytes - prev_stats->obytes
@@ -6760,7 +6856,7 @@ int CTRexExtendedDriverBaseVIC::configure_rx_filter_rules_statefull(CPhyEthIF *
return 0;
}
-extern "C" int enicpmd_dev_get_fw_support(int port_id,
+extern "C" int enicpmd_dev_get_fw_support(int port_id,
uint32_t *ver);
@@ -6771,7 +6867,7 @@ int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
if (ret==0) {
if (CGlobalInfo::m_options.preview.getVMode() >= 1) {
- printf("VIC port %d: FW support advanced filtering \n", port_id);
+ printf("VIC port %d: FW support advanced filtering \n", port_id);
}
}else{
printf("Error: VIC firmware should upgrade to support advanced filtering \n");
@@ -6807,7 +6903,7 @@ int CTRexExtendedDriverBaseVIC::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, ui
int CTRexExtendedDriverBaseVIC::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd)
{
//printf(" NOT supported yet \n");
- return (0);
+ return (0);
}
diff --git a/src/pre_test.cpp b/src/pre_test.cpp
index 76fa9a26..583427eb 100644
--- a/src/pre_test.cpp
+++ b/src/pre_test.cpp
@@ -29,80 +29,356 @@
#include "pkt_gen.h"
#include "pre_test.h"
-void CPretestPortInfo::set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed) {
- m_ip = port_cfg.get_ip();
- m_def_gw = port_cfg.get_def_gw();
- m_vlan = port_cfg.get_vlan();
- memcpy(&m_src_mac, src_mac, sizeof(m_src_mac));
- if (resolve_needed) {
- m_state = CPretestPortInfo::RESOLVE_NEEDED;
- } else {
- m_state = CPretestPortInfo::RESOLVE_NOT_NEEDED;
- }
+CPretestOnePortInfo::CPretestOnePortInfo() {
+ m_state = RESOLVE_NOT_NEEDED;
+ m_is_loopback = false;
+ m_stats.clear();
}
-void CPretestPortInfo::set_dst_mac(const uint8_t *dst_mac) {
- memcpy(&m_dst_mac, dst_mac, sizeof(m_dst_mac));
- m_state = CPretestPortInfo::RESOLVE_DONE;
+void CPretestOnePortInfo::add_src(uint32_t ip, uint16_t vlan, MacAddress mac) {
+ COneIPv4Info *one_ip = new COneIPv4Info(ip, vlan, mac);
+ assert(one_ip);
+ m_src_info.push_back(one_ip);
}
-void CPretestPortInfo::dump(FILE *fd) {
- if (m_state == INIT_NEEDED) {
- return;
- }
+void CPretestOnePortInfo::add_dst(uint32_t ip, uint16_t vlan) {
+ MacAddress default_mac;
+ COneIPv4Info *one_ip = new COneIPv4Info(ip, vlan, default_mac);
+ assert(one_ip);
+ m_dst_info.push_back(one_ip);
+ m_state = RESOLVE_NEEDED;
+}
- uint32_t ip = htonl(m_ip);
+void CPretestOnePortInfo::add_src(uint16_t ip[8], uint16_t vlan, MacAddress mac) {
+ COneIPv6Info *one_ip = new COneIPv6Info(ip, vlan, mac);
+ assert(one_ip);
+ m_src_info.push_back(one_ip);
+}
+
+void CPretestOnePortInfo::add_dst(uint16_t ip[8], uint16_t vlan) {
+ MacAddress default_mac;
+ COneIPv6Info *one_ip = new COneIPv6Info(ip, vlan, default_mac);
+ assert(one_ip);
+ m_dst_info.push_back(one_ip);
+ m_state = RESOLVE_NEEDED;
+}
- fprintf(fd, " ip:%d.%d.%d.%d", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
- ip = htonl(m_def_gw);
- fprintf(fd, " default gw:%d.%d.%d.%d\n", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
+void CPretestOnePortInfo::dump(FILE *fd, char *offset) {
+ std::string new_offset = std::string(offset) + " ";
- printf(" src MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", m_src_mac[0], m_src_mac[1], m_src_mac[2], m_src_mac[3]
- , m_src_mac[4], m_src_mac[5]);
- printf( " dst MAC: ");
- if (m_state == RESOLVE_DONE) {
- printf("%02x:%02x:%02x:%02x:%02x:%02x\n", m_dst_mac[0], m_dst_mac[1], m_dst_mac[2], m_dst_mac[3]
- , m_dst_mac[4], m_dst_mac[5]);
- } else {
- printf("Not resolved\n");
+ if (m_is_loopback) {
+ fprintf(fd, "%sPort connected in loopback\n", offset);
+ }
+ fprintf(fd, "%sSources:\n", offset);
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ (*it)->dump(fd, new_offset.c_str());
+ }
+ fprintf(fd, "%sDestinations:\n", offset);
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ (*it)->dump(fd, new_offset.c_str());
}
}
/*
- put in mac relevant dest MAC for port/ip pair.
- return false if no relevant info exists, true otherwise.
+ * Get appropriate source for given vlan and ip version.
*/
-bool CPretest::get_mac(uint16_t port_id, uint32_t ip, uint8_t *mac) {
- assert(port_id < TREX_MAX_PORTS);
+COneIPInfo *CPretestOnePortInfo::get_src(uint16_t vlan, uint8_t ip_ver) {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ if ((ip_ver == (*it)->ip_ver()) && (vlan == (*it)->get_vlan()))
+ return (*it);
+ }
+
+ return NULL;
+}
+
+COneIPv4Info *CPretestOnePortInfo::find_ip(uint32_t ip, uint16_t vlan) {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ if (((*it)->ip_ver() == COneIPInfo::IP4_VER) && ((*it)->get_vlan() == vlan) && (((COneIPv4Info *)(*it))->get_ip() == ip))
+ return (COneIPv4Info *) *it;
+ }
+
+ return NULL;
+}
+
+COneIPv4Info *CPretestOnePortInfo::find_next_hop(uint32_t ip, uint16_t vlan) {
+
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ if (((*it)->ip_ver() == COneIPInfo::IP4_VER) && ((*it)->get_vlan() == vlan) && (((COneIPv4Info *)(*it))->get_ip() == ip))
+ return (COneIPv4Info *) *it;
+ }
+
+ return NULL;
+}
+
+COneIPv6Info *CPretestOnePortInfo::find_ipv6(uint16_t ip[8], uint16_t vlan) {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ if (((*it)->ip_ver() == COneIPInfo::IP6_VER) && ((*it)->get_vlan() == vlan)
+ && (! memcmp((uint8_t *) ((COneIPv6Info *) (*it))->get_ipv6(), (uint8_t *)ip, 2*8 /* ???*/ ) ) )
+ return (COneIPv6Info *) *it;
+ }
+
+ return NULL;
+}
+
+bool CPretestOnePortInfo::get_mac(COneIPInfo *ip, uint8_t *mac) {
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ if (ip->ip_ver() != (*it)->ip_ver())
+ continue;
+
+ switch(ip->ip_ver()) {
+ case 4:
+ if (*((COneIPv4Info *) (*it)) != *((COneIPv4Info *) ip))
+ continue;
+ break;
+ case 6:
+ if (*((COneIPv6Info *) (*it)) != *((COneIPv6Info *) ip))
+ continue;
+ break;
+ default:
+ assert(0);
+ }
+
+ (*it)->get_mac(mac);
+ return true;
+ }
- if (m_port_info[port_id].m_state != CPretestPortInfo::RESOLVE_DONE) {
+ return false;
+}
+
+bool CPretestOnePortInfo::get_mac(uint32_t ip, uint16_t vlan, uint8_t *mac) {
+ COneIPv4Info one_ip(ip, vlan);
+
+ return get_mac(&one_ip, mac);
+}
+
+bool CPretestOnePortInfo::get_mac(uint16_t ip[8], uint16_t vlan, uint8_t *mac) {
+ COneIPv6Info one_ip(ip, vlan);
+
+ return get_mac(&one_ip, mac);
+}
+
+// return true if there are still any addresses to resolve on this port
+bool CPretestOnePortInfo::resolve_needed() {
+ if (m_state == RESOLVE_NOT_NEEDED)
return false;
+
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ if ((*it)->resolve_needed())
+ return true;
}
- memcpy(mac, &m_port_info[port_id].m_dst_mac, sizeof(m_port_info[port_id].m_dst_mac));
+ m_state = RESOLVE_NOT_NEEDED;
+ return false;
+}
- return true;
+void CPretestOnePortInfo::send_arp_req_all() {
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ rte_mbuf_t *m[1];
+ int num_sent;
+ int verbose = CGlobalInfo::m_options.preview.getVMode();
+
+ m[0] = CGlobalInfo::pktmbuf_alloc_small_by_port(m_port_id);
+ if ( unlikely(m[0] == 0) ) {
+ fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", m_port_id);
+ exit(1);
+ }
+
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], (*it)->get_arp_req_len());
+ // We need source on the same VLAN of the dest in order to send
+ COneIPInfo *sip = get_src((*it)->get_vlan(), (*it)->ip_ver());
+ if (sip == NULL) {
+ fprintf(stderr, "Failed finding matching source for - ");
+ (*it)->dump(stderr);
+ exit(1);
+ }
+ (*it)->fill_arp_req_buf(p, m_port_id, sip);
+
+ if (verbose >= 3) {
+ fprintf(stdout, "TX ARP request on port %d - " , m_port_id);
+ (*it)->dump(stdout, "");
+ }
+
+ num_sent = rte_eth_tx_burst(m_port_id, 0, m, 1);
+ if (num_sent < 1) {
+ fprintf(stderr, "Failed sending ARP to port:%d\n", m_port_id);
+ exit(1);
+ } else {
+ m_stats.m_tx_arp++;
+ }
+ }
+}
+
+void CPretestOnePortInfo::send_grat_arp_all() {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ rte_mbuf_t *m[1];
+ int num_sent;
+ int verbose = CGlobalInfo::m_options.preview.getVMode();
+
+ m[0] = CGlobalInfo::pktmbuf_alloc_small_by_port(m_port_id);
+ if ( unlikely(m[0] == 0) ) {
+ fprintf(stderr, "ERROR: Could not allocate mbuf for sending grat ARP on port:%d\n", m_port_id);
+ exit(1);
+ }
+
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], (*it)->get_grat_arp_len());
+ (*it)->fill_grat_arp_buf(p);
+
+
+ if (verbose >= 3) {
+ fprintf(stdout, "TX grat ARP on port %d - " , m_port_id);
+ (*it)->dump(stdout, "");
+ }
+
+ num_sent = rte_eth_tx_burst(m_port_id, 0, m, 1);
+ if (num_sent < 1) {
+ fprintf(stderr, "Failed sending grat ARP on port:%d\n", m_port_id);
+ exit(1);
+ } else {
+ m_stats.m_tx_arp++;
+ }
+ }
+}
+
+// IPv4 functions
+void CPretest::add_ip(uint16_t port, uint32_t ip, uint16_t vlan, MacAddress src_mac) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_src(ip, vlan, src_mac);
+}
+
+void CPretest::add_ip(uint16_t port, uint32_t ip, MacAddress src_mac) {
+ assert(port < m_max_ports);
+ add_ip(port, ip, 0, src_mac);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint32_t ip, uint16_t vlan) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_dst(ip, vlan);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint32_t ip) {
+ assert(port < m_max_ports);
+ add_next_hop(port, ip, 0);
+}
+
+// IPv6 functions
+void CPretest::add_ip(uint16_t port, uint16_t ip[8], uint16_t vlan, MacAddress src_mac) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_src(ip, vlan, src_mac);
+}
+
+void CPretest::add_ip(uint16_t port, uint16_t ip[8], MacAddress src_mac) {
+ assert(port < m_max_ports);
+ add_ip(port, ip, 0, src_mac);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint16_t ip[8], uint16_t vlan) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_dst(ip, vlan);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint16_t ip[8]) {
+ assert(port < m_max_ports);
+ add_next_hop(port, ip, 0);
+}
+
+// put in mac, the relevant mac address for the tupple port_id, ip, vlan
+bool CPretest::get_mac(uint16_t port_id, uint32_t ip, uint16_t vlan, uint8_t *mac) {
+ assert(port_id < m_max_ports);
+
+ return m_port_info[port_id].get_mac(ip, vlan, mac);
+}
+
+// IPv6 version of above
+bool CPretest::get_mac(uint16_t port_id, uint16_t ip[8], uint16_t vlan, uint8_t *mac) {
+ assert(port_id < m_max_ports);
+
+ return m_port_info[port_id].get_mac(ip, vlan, mac);
}
CPreTestStats CPretest::get_stats(uint16_t port_id) {
- assert(port_id < TREX_MAX_PORTS);
+ assert(port_id < m_max_ports);
- return m_port_info[port_id].m_stats;
+ return m_port_info[port_id].get_stats();
}
bool CPretest::is_loopback(uint16_t port) {
- assert(port < TREX_MAX_PORTS);
+ assert(port < m_max_ports);
- return m_port_info[port].m_is_loopback;
+ return m_port_info[port].is_loopback();
}
-void CPretest::set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed) {
- if (port_id >= m_max_ports)
- return;
+bool CPretest::resolve_all() {
+ uint16_t port;
+
+ // send ARP request on all ports
+ for (port = 0; port < m_max_ports; port++) {
+ m_port_info[port].send_arp_req_all();
+ }
- m_port_info[port_id].set_params(port_cfg, src_mac, resolve_needed);
+ int max_tries = 1000;
+ int i;
+ for (i = 0; i < max_tries; i++) {
+ bool all_resolved = true;
+ for (port = 0; port < m_max_ports; port++) {
+ if (m_port_info[port].resolve_needed()) {
+ // We need to stop reading packets only if all ports are resolved.
+ // If we are on loopback, We might get requests on port even after it is in RESOLVE_DONE state
+ all_resolved = false;
+ }
+ handle_rx(port, MAIN_DPDK_DATA_Q);
+ if (! CGlobalInfo::m_options.preview.get_vm_one_queue_enable())
+ handle_rx(port, MAIN_DPDK_RX_Q);
+ }
+ if (all_resolved) {
+ break;
+ } else {
+ delay(1);
+ }
+ }
+
+ if (i == max_tries) {
+ return false;
+ } else {
+ return true;
+ }
+
+ return true;
+}
+
+void CPretest::send_arp_req_all() {
+ for (uint16_t port = 0; port < m_max_ports; port++) {
+ m_port_info[port].send_arp_req_all();
+ }
}
+void CPretest::send_grat_arp_all() {
+ for (uint16_t port = 0; port < m_max_ports; port++) {
+ m_port_info[port].send_grat_arp_all();
+ }
+}
+
+bool CPretest::is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp, uint16_t &vlan_tag) {
+ EthernetHeader *m_ether = (EthernetHeader *)p;
+ vlan_tag = 0;
+
+ if ((pkt_size < 60) ||
+ ((m_ether->getNextProtocol() != EthernetHeader::Protocol::ARP)
+ && (m_ether->getNextProtocol() != EthernetHeader::Protocol::VLAN)))
+ return false;
+
+ if (m_ether->getNextProtocol() == EthernetHeader::Protocol::ARP) {
+ arp = (ArpHdr *)(p + 14);
+ } else {
+ if (m_ether->getVlanProtocol() != EthernetHeader::Protocol::ARP) {
+ return false;
+ } else {
+ vlan_tag = m_ether->getVlanTag();
+ arp = (ArpHdr *)(p + 18);
+ }
+ }
+
+ return true;
+}
int CPretest::handle_rx(int port_id, int queue_id) {
rte_mbuf_t * rx_pkts[32];
@@ -121,72 +397,89 @@ int CPretest::handle_rx(int port_id, int queue_id) {
int pkt_size = rte_pktmbuf_pkt_len(m);
uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *);
ArpHdr *arp;
- CPretestPortInfo *port = &m_port_info[port_id];
- if (is_arp(p, pkt_size, arp)) {
- m_port_info[port_id].m_stats.m_rx_arp++;
+ uint16_t vlan_tag;
+ CPretestOnePortInfo *port = &m_port_info[port_id];
+ if (is_arp(p, pkt_size, arp, vlan_tag)) {
+ port->m_stats.m_rx_arp++;
if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REQUEST)) {
if (verbose >= 3) {
- fprintf(stdout, "RX ARP request on port %d queue %d sip:0x%08x tip:0x%08x\n"
- , port_id, queue_id, ntohl(arp->m_arp_sip), ntohl(arp->m_arp_tip));
+ bool is_grat = false;
+ if (arp->m_arp_sip == arp->m_arp_tip) {
+ is_grat = true;
+ }
+ fprintf(stdout, "RX %s on port %d queue %d sip:%s tip:%s vlan:%d\n"
+ , is_grat ? "grat ARP" : "ARP request"
+ , port_id, queue_id
+ , ip_to_str(ntohl(arp->m_arp_sip)).c_str()
+ , ip_to_str(ntohl(arp->m_arp_tip)).c_str()
+ , vlan_tag);
}
// is this request for our IP?
- if (ntohl(arp->m_arp_tip) == port->m_ip) {
+ COneIPv4Info *src_addr;
+ COneIPv4Info *rcv_addr;
+ if ((src_addr = port->find_ip(ntohl(arp->m_arp_tip), vlan_tag))) {
// If our request(i.e. we are connected in loopback)
// , do a shortcut, and write info directly to asking port
uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9};
if (! memcmp((uint8_t *)&arp->m_arp_tha.data, magic, 5)) {
uint8_t sent_port_id = arp->m_arp_tha.data[5];
if ((sent_port_id < m_max_ports) &&
- (m_port_info[sent_port_id].m_def_gw == port->m_ip)) {
- memcpy(m_port_info[sent_port_id].m_dst_mac, port->m_src_mac, ETHER_ADDR_LEN);
- m_port_info[sent_port_id].m_state = CPretestPortInfo::RESOLVE_DONE;
+ (rcv_addr = m_port_info[sent_port_id].find_next_hop(ntohl(arp->m_arp_tip), vlan_tag))) {
+ uint8_t mac[ETHER_ADDR_LEN];
+ src_addr->get_mac(mac);
+ rcv_addr->set_mac(mac);
+ port->m_is_loopback = true;
m_port_info[sent_port_id].m_is_loopback = true;
}
} else {
// Not our request. Answer.
+ uint8_t src_mac[ETHER_ADDR_LEN];
free_pkt = false; // We use the same mbuf to send response. Don't free it twice.
arp->m_arp_op = htons(ArpHdr::ARP_HDR_OP_REPLY);
uint32_t tmp_ip = arp->m_arp_sip;
arp->m_arp_sip = arp->m_arp_tip;
arp->m_arp_tip = tmp_ip;
memcpy((uint8_t *)&arp->m_arp_tha, (uint8_t *)&arp->m_arp_sha, ETHER_ADDR_LEN);
- memcpy((uint8_t *)&arp->m_arp_sha, port->m_src_mac, ETHER_ADDR_LEN);
+ src_addr->get_mac(src_mac);
+ memcpy((uint8_t *)&arp->m_arp_sha, src_mac, ETHER_ADDR_LEN);
EthernetHeader *m_ether = (EthernetHeader *)p;
memcpy((uint8_t *)&m_ether->myDestination, (uint8_t *)&m_ether->mySource, ETHER_ADDR_LEN);
- memcpy((uint8_t *)&m_ether->mySource, (uint8_t *)port->m_src_mac, ETHER_ADDR_LEN);
+ memcpy((uint8_t *)&m_ether->mySource, src_mac, ETHER_ADDR_LEN);
int num_sent = rte_eth_tx_burst(port_id, 0, &m, 1);
if (num_sent < 1) {
fprintf(stderr, "Failed sending ARP reply to port:%d\n", port_id);
rte_pktmbuf_free(m);
} else {
- fprintf(stdout, "TX ARP reply on port:%d sip:0x%08x, tip:0x%08x\n"
- , port_id ,htonl(arp->m_arp_sip), htonl(arp->m_arp_tip));
+ if (verbose >= 3) {
+ fprintf(stdout, "TX ARP reply on port:%d sip:%s, tip:%s\n"
+ , port_id
+ , ip_to_str(ntohl(arp->m_arp_sip)).c_str()
+ , ip_to_str(ntohl(arp->m_arp_tip)).c_str());
+
+ }
m_port_info[port_id].m_stats.m_tx_arp++;
}
}
} else {
- // ARP request not to our IP.
- if ((ntohl(arp->m_arp_tip) == port->m_def_gw) && (ntohl(arp->m_arp_sip) == port->m_def_gw)) {
- // sip and tip equals def_gw, meaning we got gratitues ARP.
- port->set_dst_mac((uint8_t *)&arp->m_arp_sha);
+ // ARP request not to our IP. Check if this is gratitues ARP for something we need.
+ if ((arp->m_arp_tip == arp->m_arp_sip)
+ && (rcv_addr = port->find_next_hop(ntohl(arp->m_arp_tip), vlan_tag))) {
+ rcv_addr->set_mac((uint8_t *)&arp->m_arp_sha);
}
}
} else {
if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REPLY)) {
if (verbose >= 3) {
- bool is_grat = false;
- if (arp->m_arp_sip == arp->m_arp_tip) {
- is_grat = true;
- }
- fprintf(stdout, "RX %s on port %d queue %d sip:0x%08x tip:0x%08x\n"
- , is_grat ? "grat ARP" : "ARP reply"
+ fprintf(stdout, "RX ARP reply on port %d queue %d sip:%s tip:%s\n"
, port_id, queue_id
- , ntohl(arp->m_arp_sip)
- , ntohl(arp->m_arp_tip));
+ , ip_to_str(ntohl(arp->m_arp_sip)).c_str()
+ , ip_to_str(ntohl(arp->m_arp_tip)).c_str());
}
+
// If this is response to our request, update our tables
- if (port->m_def_gw == ntohl(arp->m_arp_sip)) {
- port->set_dst_mac((uint8_t *)&arp->m_arp_sha);
+ COneIPv4Info *addr;
+ if ((addr = port->find_next_hop(ntohl(arp->m_arp_sip), vlan_tag))) {
+ addr->set_mac((uint8_t *)&arp->m_arp_sha);
}
}
}
@@ -199,160 +492,86 @@ int CPretest::handle_rx(int port_id, int queue_id) {
return 0;
}
-/*
- Try to resolve def_gw address on all ports marked as needed.
- Return false if failed to resolve on one of the ports
- */
-bool CPretest::resolve_all() {
- uint16_t port;
-
- // send ARP request on all ports
- for (port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) {
- send_arp_req(port, false);
- }
- }
-
- int max_tries = 1000;
- int i;
- for (i = 0; i < max_tries; i++) {
- bool all_resolved = true;
- for (port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) {
- // We need to stop reading packets only if all ports are resolved.
- // If we are on loopback, We might get requests on port even after it is in RESOLVE_DONE state
- all_resolved = false;
+void CPretest::get_results(CManyIPInfo &resolved_ips) {
+ for (int port = 0; port < m_max_ports; port++) {
+ for (std::vector<COneIPInfo *>::iterator it = m_port_info[port].m_dst_info.begin()
+ ; it != m_port_info[port].m_dst_info.end(); ++it) {
+ uint8_t ip_type = (*it)->ip_ver();
+ switch(ip_type) {
+ case COneIPInfo::IP4_VER:
+ resolved_ips.insert(*(COneIPv4Info *)(*it));
+ break;
+#if 0
+ //??? fix for ipv6
+ case COneIPInfo::IP6_VER:
+ ipv6_tmp = (uint8_t *)((COneIPv6Info *)(*it))->get_ipv6();
+ memcpy((uint8_t *)ipv6, (uint8_t *)ipv6_tmp, 16);
+ v6_list.insert(std::pair<std::pair<uint16_t[8], uint16_t>, COneIPv6Info>
+ (std::pair<uint16_t[8], uint16_t>(ipv6, vlan), *(COneIPv6Info *)(*it)));
+ break;
+#endif
+ default:
+ break;
}
- handle_rx(port, MAIN_DPDK_DATA_Q);
- if (! CGlobalInfo::m_options.preview.get_vm_one_queue_enable())
- handle_rx(port, MAIN_DPDK_RX_Q);
- }
- if (all_resolved) {
- break;
- } else {
- delay(1);
}
}
-
- if (i == max_tries) {
- return false;
- } else {
- return true;
- }
}
void CPretest::dump(FILE *fd) {
+ fprintf(fd, "Pre test info start ===================\n");
for (int port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state != CPretestPortInfo::INIT_NEEDED) {
- fprintf(fd, "port %d:\n", port);
- m_port_info[port].dump(fd);
- }
- }
-}
-
-// Send ARP request for our default gateway on port
-// If is_grat is true - send gratuitous ARP.
-void CPretest::send_arp_req(uint16_t port_id, bool is_grat) {
- rte_mbuf_t *m[1];
- int num_sent;
- int verbose = CGlobalInfo::m_options.preview.getVMode();
-
- m[0] = CGlobalInfo::pktmbuf_alloc_small_by_port(port_id);
- if ( unlikely(m[0] == 0) ) {
- fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", port_id);
- exit(1);
- }
-
- uint32_t tip;
- uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], 60); // ARP packet is shorter than 60
- uint32_t sip = m_port_info[port_id].m_ip;
- uint8_t *src_mac = m_port_info[port_id].m_src_mac;
- uint16_t vlan = m_port_info[port_id].m_vlan;
- if (is_grat) {
- tip = sip;
- } else {
- tip = m_port_info[port_id].m_def_gw;
- }
-
- if (verbose >= 3) {
- fprintf(stdout, "TX %s port:%d sip:0x%08x, tip:0x%08x\n"
- , is_grat ? "grat ARP": "ARP request", port_id ,sip, tip);
- }
-
- CTestPktGen::create_arp_req(p, sip, tip, src_mac, vlan, port_id);
- num_sent = rte_eth_tx_burst(port_id, 0, m, 1);
- if (num_sent < 1) {
- fprintf(stderr, "Failed sending ARP to port:%d\n", port_id);
- exit(1);
- } else {
- m_port_info[port_id].m_stats.m_tx_arp++;
+ fprintf(fd, "Port %d:\n", port);
+ m_port_info[port].dump(fd, (char *)" ");
}
+ fprintf(fd, "Pre test info end ===================\n");
}
-/*
- Send gratuitous ARP on all ports
- */
-void CPretest::send_grat_arp_all() {
- for (uint16_t port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) {
- send_arp_req(port, true);
- }
- }
-}
-
-bool CPretest::is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp) {
- EthernetHeader *m_ether = (EthernetHeader *)p;
-
- if ((pkt_size < 60) ||
- ((m_ether->getNextProtocol() != EthernetHeader::Protocol::ARP)
- && (m_ether->getNextProtocol() != EthernetHeader::Protocol::VLAN)))
- return false;
-
- if (m_ether->getNextProtocol() == EthernetHeader::Protocol::ARP) {
- arp = (ArpHdr *)(p + 14);
- } else {
- if (m_ether->getVlanProtocol() != EthernetHeader::Protocol::ARP) {
- return false;
- } else {
- arp = (ArpHdr *)(p + 18);
- }
- }
-
- return true;
-}
-
-// Should be run on setup with two interfaces connected by loopback.
-// Before running, should put ports on receive all mode.
void CPretest::test() {
uint8_t found_mac[ETHER_ADDR_LEN];
uint8_t mac0[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd0};
uint8_t mac1[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd1};
- uint32_t ip0 = 0x0f000003;
- uint32_t ip1 = 0x0f000001;
-
- CPerPortIPCfg port_cfg0;
- CPerPortIPCfg port_cfg1;
- port_cfg0.set_ip(ip0);
- port_cfg0.set_def_gw(ip1);
- port_cfg0.set_vlan(0);
- port_cfg1.set_ip(ip1);
- port_cfg1.set_def_gw(ip0);
- port_cfg1.set_vlan(0);
-
- set_port_params(0, port_cfg0, mac0, true);
- set_port_params(1, port_cfg1, mac1, true);
+ uint8_t mac2[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd2};
+ uint32_t ip0 = 0x0f000002;
+ uint32_t ip01 = 0x0f000003;
+ uint32_t ip1 = 0x0f000001;
+ uint16_t ipv6_0[8] = {0x1234, 0x5678, 0xabcd, 0x0, 0x0, 0x0, 0x1111, 0x2220};
+ uint16_t ipv6_1[8] = {0x1234, 0x5678, 0xabcd, 0x0, 0x0, 0x0, 0x1111, 0x2221};
+ uint16_t vlan=1;
+ uint8_t port_0 = 0;
+ uint8_t port_1 = 3;
+
+ add_ip(port_0, ip0, vlan, mac0);
+ add_ip(port_0, ip01, vlan, mac1);
+ add_ip(port_0, ipv6_0, vlan, mac1);
+ add_next_hop(port_0, ip1, vlan);
+ add_next_hop(port_0, ipv6_1, vlan);
+
+ add_ip(port_1, ip1, vlan, mac2);
+ add_ip(port_1, ipv6_1, vlan, mac2);
+ add_next_hop(port_1, ip0, vlan);
+ add_next_hop(port_1, ip01, vlan);
+ add_next_hop(port_1, ipv6_0, vlan);
+
dump(stdout);
+ send_grat_arp_all();
resolve_all();
dump(stdout);
- get_mac(0, ip1, found_mac);
- if (memcmp(found_mac, mac1, ETHER_ADDR_LEN)) {
- fprintf(stderr, "Test failed: Could not resolve def gw on port 0\n");
+
+ if (!get_mac(port_0, ip1, vlan, found_mac)) {
+ fprintf(stderr, "Test failed: Could not find %x on port %d\n", ip1, port_0);
+ exit(1);
+ }
+ if (memcmp(found_mac, mac2, ETHER_ADDR_LEN)) {
+ fprintf(stderr, "Test failed: dest %x on port %d badly resolved\n", ip1, port_0);
exit(1);
}
- get_mac(1, ip0, found_mac);
+ if (!get_mac(port_1, ip0, vlan, found_mac)) {
+ fprintf(stderr, "Test failed: Could not find %x on port %d\n", ip0, port_1);
+ exit(1);
+ }
if (memcmp(found_mac, mac0, ETHER_ADDR_LEN)) {
- fprintf(stderr, "Test failed: Could not resolve def gw on port 1\n");
+ fprintf(stderr, "Test failed: dest %x on port %d badly resolved\n", ip0, port_1);
exit(1);
}
diff --git a/src/pre_test.h b/src/pre_test.h
index ad7608a6..9573ff02 100644
--- a/src/pre_test.h
+++ b/src/pre_test.h
@@ -24,6 +24,7 @@
#include <iostream>
#include <common/Network/Packet/Arp.h>
+#include <common/Network/Packet/MacAddress.h>
#include "bp_sim.h"
#include "trex_defs.h"
@@ -39,60 +40,79 @@ class CPreTestStats {
}
};
-class CPretestPortInfo {
+class CPretestOnePortInfo {
friend class CPretest;
-
- private:
- enum CPretestPortInfoStates {
- INIT_NEEDED,
+ enum CPretestOnePortInfoStates {
RESOLVE_NEEDED,
- RESOLVE_DONE,
RESOLVE_NOT_NEEDED,
};
- CPretestPortInfo() {
- m_state = INIT_NEEDED;
- m_is_loopback = false;
- m_stats.clear();
- }
- void dump(FILE *fd);
- uint8_t *create_arp_req(uint16_t &pkt_size, uint8_t port, bool is_grat);
- void set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed);
- void set_dst_mac(const uint8_t *dst_mac);
-
+ public:
+ CPretestOnePortInfo();
+ void add_src(uint32_t ip, uint16_t vlan, MacAddress mac);
+ void add_dst(uint32_t ip, uint16_t vlan);
+ void add_src(uint16_t ip[8], uint16_t vlan, MacAddress mac);
+ void add_dst(uint16_t ip[8], uint16_t vlan);
+ bool get_mac(uint32_t ip, uint16_t vlan, uint8_t *mac);
+ bool get_mac(uint16_t ip[8], uint16_t vlan, uint8_t *mac);
+ bool get_mac(COneIPInfo *ip, uint8_t *mac);
+ COneIPInfo *get_src(uint16_t vlan, uint8_t ip_ver);
+ void set_port_id(uint16_t port_id) {m_port_id = port_id;}
+ void dump(FILE *fd, char *offset);
+ bool is_loopback() {return m_is_loopback;}
+ CPreTestStats get_stats() {return m_stats;}
+ bool resolve_needed();
+ void send_grat_arp_all();
+ void send_arp_req_all();
+
+ private:
+ COneIPv4Info *find_ip(uint32_t ip, uint16_t vlan);
+ COneIPv4Info *find_next_hop(uint32_t ip, uint16_t vlan);
+ COneIPv6Info *find_ipv6(uint16_t *ip, uint16_t vlan);
+ bool get_mac(COneIPInfo *ip, uint16_t vlan, uint8_t *mac, uint8_t ip_ver);
+
private:
- uint32_t m_ip;
- uint32_t m_def_gw;
- uint16_t m_vlan;
- uint8_t m_src_mac[6];
- uint8_t m_dst_mac[6];
- enum CPretestPortInfoStates m_state;
bool m_is_loopback;
+ CPretestOnePortInfoStates m_state;
CPreTestStats m_stats;
+ uint16_t m_port_id;
+ std::vector<COneIPInfo *> m_src_info;
+ std::vector<COneIPInfo *> m_dst_info;
};
-
class CPretest {
public:
CPretest(uint16_t max_ports) {
m_max_ports = max_ports;
+ for (int i =0; i < max_ports; i++) {
+ m_port_info[i].set_port_id(i);
+ }
}
- bool get_mac(uint16_t port, uint32_t ip, uint8_t *mac);
+ void add_ip(uint16_t port, uint32_t ip, uint16_t vlan, MacAddress src_mac);
+ void add_ip(uint16_t port, uint32_t ip, MacAddress src_mac);
+ void add_next_hop(uint16_t port, uint32_t ip, uint16_t vlan);
+ void add_next_hop(uint16_t port, uint32_t ip);
+ void add_ip(uint16_t port, uint16_t ip[8], uint16_t vlan, MacAddress src_mac);
+ void add_ip(uint16_t port, uint16_t ip[8], MacAddress src_mac);
+ void add_next_hop(uint16_t port, uint16_t ip[8], uint16_t vlan);
+ void add_next_hop(uint16_t port, uint16_t ip[8]);
+ bool get_mac(uint16_t port, uint32_t ip, uint16_t vlan, uint8_t *mac);
+ bool get_mac(uint16_t port, uint16_t ip[8], uint16_t vlan, uint8_t *mac);
CPreTestStats get_stats(uint16_t port_id);
bool is_loopback(uint16_t port);
- void set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed);
bool resolve_all();
- void send_arp_req(uint16_t port, bool is_grat);
+ void send_arp_req_all();
void send_grat_arp_all();
- bool is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp);
+ bool is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp, uint16_t &vlan_tag);
+ void get_results(CManyIPInfo &resolved_ips);
void dump(FILE *fd);
void test();
-
+
private:
int handle_rx(int port, int queue_id);
private:
- CPretestPortInfo m_port_info[TREX_MAX_PORTS];
+ CPretestOnePortInfo m_port_info[TREX_MAX_PORTS];
uint16_t m_max_ports;
};
diff --git a/src/stateful_rx_core.cpp b/src/stateful_rx_core.cpp
index cbf62a17..7ee802df 100644
--- a/src/stateful_rx_core.cpp
+++ b/src/stateful_rx_core.cpp
@@ -588,32 +588,56 @@ void CLatencyManager::send_pkt_all_ports(){
}
}
-void CLatencyManager::send_grat_arp_all_ports() {
- for (int port_id = 0; port_id < m_max_ports; port_id++) {
- if (! CGlobalInfo::m_options.m_ip_cfg[port_id].grat_arp_needed())
- continue;
-
- CLatencyManagerPerPort * lp = &m_ports[port_id];
- rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id));
- assert(m);
- uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, 60); // ARP packet is shorter than 60
- uint32_t sip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip();
- uint8_t *src_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src;
- uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
- // gratuitous ARP. Requested IP is our source.
- CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id);
+double CLatencyManager::grat_arp_timeout() {
+ return (double)CGlobalInfo::m_options.m_arp_ref_per / m_arp_info.size();
+}
+
+void CLatencyManager::add_grat_arp_src(COneIPv4Info &ip) {
+ m_arp_info.insert(ip);
+}
+
+void CLatencyManager::send_one_grat_arp() {
+ const COneIPInfo *ip_info;
+ uint16_t port_id;
+ CLatencyManagerPerPort * lp;
+ rte_mbuf_t *m;
+ uint8_t src_mac[ETHER_ADDR_LEN];
+ uint16_t vlan;
+ uint32_t sip;
+
+ ip_info = m_arp_info.get_next();
+ if (!ip_info)
+ ip_info = m_arp_info.get_next();
+ // Two times NULL means there are no addresses
+ if (!ip_info)
+ return;
+ port_id = ip_info->get_port();
+ lp = &m_ports[port_id];
+ m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id));
+ assert(m);
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len());
+ ip_info->get_mac(src_mac);
+ vlan = ip_info->get_vlan();
+ switch(ip_info->ip_ver()) {
+ case COneIPInfo::IP4_VER:
+ sip = ((COneIPv4Info *)ip_info)->get_ip();
+ CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id);
if (CGlobalInfo::m_options.preview.getVMode() >= 3) {
- printf("Sending gratuitous ARP on port %d vlan:%d, sip:0x%08x\n", port_id, vlan, sip);
+ printf("Sending gratuitous ARP on port %d vlan:%d, sip:%s\n", port_id, vlan
+ , ip_to_str(sip).c_str());
utl_DumpBuffer(stdout, p, 60, 0);
}
-
if ( lp->m_io->tx(m) == 0 ) {
lp->m_port.m_ign_stats.m_tx_arp++;
lp->m_port.m_ign_stats.m_tot_bytes += 64; // mbuf size is smaller, but 64 bytes will be sent
} else {
lp->m_port.m_tx_pkt_err++;
}
+ break;
+ case COneIPInfo::IP6_VER:
+ //??? implement ipv6
+ break;
}
}
@@ -815,9 +839,9 @@ void CLatencyManager::start(int iter, bool activate_watchdog) {
case CGenNode::GRAT_ARP:
m_cpu_dp_u.start_work1();
- send_grat_arp_all_ports();
+ send_one_grat_arp();
m_p_queue.pop();
- node->m_time += (double)CGlobalInfo::m_options.m_arp_ref_per;
+ node->m_time += grat_arp_timeout();
m_p_queue.push(node);
m_cpu_dp_u.commit1();
break;
diff --git a/src/stateful_rx_core.h b/src/stateful_rx_core.h
index 3fa5892f..48fbeb97 100644
--- a/src/stateful_rx_core.h
+++ b/src/stateful_rx_core.h
@@ -24,6 +24,7 @@ limitations under the License.
#include "bp_sim.h"
#include "flow_stat.h"
+#include "utl_ip.h"
#define L_PKT_SUBMODE_NO_REPLY 1
#define L_PKT_SUBMODE_REPLY 2
@@ -346,11 +347,13 @@ public:
return ( &m_nat_check_manager );
}
CLatencyPktMode *c_l_pkt_mode;
+ void add_grat_arp_src(COneIPv4Info &ip);
private:
void tickle();
void send_pkt_all_ports();
- void send_grat_arp_all_ports();
+ double grat_arp_timeout();
+ void send_one_grat_arp();
void try_rx();
void try_rx_queues();
void run_rx_queue_msgs(uint8_t thread_id, CNodeRing * r);
@@ -374,7 +377,7 @@ private:
CCpuUtlDp m_cpu_dp_u;
CCpuUtlCp m_cpu_cp_u;
TrexMonitor m_monitor;
-
+ CManyIPInfo m_arp_info; // for grat ARP
volatile bool m_do_stop __rte_cache_aligned ;
};
diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp
index ad71d38e..548d097b 100644
--- a/src/trex_client_config.cpp
+++ b/src/trex_client_config.cpp
@@ -30,38 +30,200 @@ limitations under the License.
#include "common/basic_utils.h"
#include "bp_sim.h"
+void ClientCfgDirBase::dump(FILE *fd) const {
+ if (has_src_mac_addr()) {
+ fprintf(fd, " src_mac: %s\n", utl_macaddr_to_str(m_src_mac.GetConstBuffer()).c_str());
+ } else {
+ fprintf(fd, "# No src MAC\n");
+ }
+ if (has_dst_mac_addr()) {
+ fprintf(fd, " dst_mac: %s\n", utl_macaddr_to_str(m_dst_mac.GetConstBuffer()).c_str());
+ } else {
+ fprintf(fd, "# No dst MAC\n");
+ }
+ if (has_vlan()) {
+ fprintf(fd, " vlan: %d\n", m_vlan);
+ } else {
+ fprintf(fd, "# No vlan\n");
+ }
+}
+
+void ClientCfgDirBase::update(uint32_t index, const ClientCfgDirExt &cfg) {
+ if (has_src_mac_addr()) {
+ m_src_mac += index;
+ }
+
+ if (has_dst_mac_addr() || cfg.has_next_hop() || cfg.has_ipv6_next_hop()) {
+ m_dst_mac = cfg.get_resolved_mac(index);
+ m_bitfield |= HAS_DST_MAC;
+ }
+}
+
+bool ClientCfgDirExt::need_resolve() const {
+ if (has_next_hop() || has_ipv6_next_hop())
+ return true;
+ else
+ return false;
+}
+
+void ClientCfgDirExt::set_no_resolve_needed() {
+ m_bitfield &= ~(HAS_DST_MAC | HAS_IPV6_NEXT_HOP | HAS_NEXT_HOP);
+}
+
+void ClientCfgDirExt::dump(FILE *fd) const {
+ ClientCfgDirBase::dump(fd);
+
+ if (has_next_hop()) {
+ fprintf(fd, " next_hop: %s\n", ip_to_str(m_next_hop).c_str());
+ } else {
+ fprintf(fd, "# No next hop\n");
+ }
+ if (has_ipv6_next_hop()) {
+ fprintf(fd, " ipv6_next_hop: %s\n", ip_to_str((unsigned char *)m_ipv6_next_hop).c_str());
+ } else {
+ fprintf(fd, "# No IPv6 next hop\n");
+ }
+
+ if (m_resolved_macs.size() > 0) {
+ fprintf(fd, "# Resolved MAC list:\n");
+ for (int i = 0; i < m_resolved_macs.size(); i++) {
+ fprintf(fd, "# %s\n", utl_macaddr_to_str(m_resolved_macs[i].GetConstBuffer()).c_str());
+ }
+ }
+}
+
+void ClientCfgDirExt::set_resolved_macs(CManyIPInfo &pretest_result, uint16_t count) {
+ uint16_t vlan = has_vlan() ? m_vlan : 0;
+ MacAddress base_mac = m_dst_mac;
+ m_resolved_macs.resize(count);
+
+ for (int i = 0; i < count; i++) {
+ if (need_resolve()) {
+ if (has_next_hop()) {
+ if (!pretest_result.lookup(m_next_hop + i, vlan, m_resolved_macs[i])) {
+ fprintf(stderr, "Failed resolving ip:%x, vlan:%d - exiting\n", m_next_hop+i, vlan);
+ exit(1);
+ }
+ } else {
+ //??? handle ipv6
+ }
+ } else {
+ m_resolved_macs[i] = base_mac;
+ base_mac += 1;
+ }
+ }
+}
+
+void ClientCfgBase::update(uint32_t index, const ClientCfgExt *cfg) {
+ m_initiator.update(index, cfg->m_initiator);
+ m_responder.update(index, cfg->m_responder);
+}
+
void
-ClientCfgEntry::dump() const {
+ClientCfgEntry::dump(FILE *fd) const {
- std::cout << "IP start: " << ip_to_str(m_ip_start) << "\n";
- std::cout << "IP end: " << ip_to_str(m_ip_end) << "\n";
+ fprintf(fd, "- ip_start : %s\n", ip_to_str(m_ip_start).c_str());
+ fprintf(fd, " ip_end : %s\n", ip_to_str(m_ip_end).c_str());
+ m_cfg.dump(fd);
+ fprintf(fd, " count : %d\n", m_count);
+}
- //m_cfg.dump();
+void ClientCfgEntry::set_resolved_macs(CManyIPInfo &pretest_result) {
+ m_cfg.m_initiator.set_resolved_macs(pretest_result, m_count);
+ m_cfg.m_responder.set_resolved_macs(pretest_result, m_count);
+}
- #if 0
- std::cout << "Init. MAC addr: ";
- for (int i = 0; i < 6; i++) {
- printf("%lx:", ( (m_initiator.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
+void ClientCfgCompactEntry::fill_from_dir(ClientCfgDirExt cfg, uint8_t port_id) {
+ m_port = port_id;
+ if (cfg.has_next_hop()) {
+ m_next_hop_base.ip = cfg.m_next_hop;
+ if (cfg.has_src_ip()) {
+ m_src_ip.ip = cfg.m_src_ip;
+ } else {
+ m_src_ip.ip = 0;
+ }
+ m_is_ipv4 = true;
+ } else if (cfg.has_ipv6_next_hop()) {
+ memcpy(m_next_hop_base.ipv6, cfg.m_ipv6_next_hop, sizeof(m_next_hop_base.ipv6));
+ if (cfg.has_src_ipv6()) {
+ memcpy(m_src_ip.ipv6, cfg.m_src_ipv6, sizeof(m_src_ip.ipv6));
+ } else {
+ memset(m_src_ip.ipv6, 0, sizeof(m_src_ip.ipv6));
+ }
+ m_is_ipv4 = false;
}
- std::cout << "\n";
- std::cout << "Init. VLAN: " << m_initiator.m_vlan << "\n";
+ if (cfg.has_vlan()) {
+ m_vlan = cfg.m_vlan;
+ } else {
+ m_vlan = 0;
+ }
+}
- std::cout << "Res. MAC addr: ";
- for (int i = 0; i < 6; i++) {
- printf("%lx:", ( (m_responder.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
+void
+ClientCfgDB::dump(FILE *fd) {
+ //fprintf(fd, "#**********Client config file start*********\n");
+ fprintf(fd, "vlan: %s\n", m_under_vlan ? "true" : "false");
+ fprintf(fd, "groups:\n");
+
+ for (std::map<uint32_t, ClientCfgEntry>::iterator it = m_groups.begin(); it != m_groups.end(); ++it) {
+ fprintf(fd, "# ****%s:****\n", ip_to_str(it->first).c_str());
+ ((ClientCfgEntry)it->second).dump(fd);
}
- std::cout << "\n";
+ //fprintf(fd, "#**********Client config end*********\n");
+}
- std::cout << "Res. VLAN: " << m_responder.m_vlan << "\n";
- #endif
+void ClientCfgDB::set_resolved_macs(CManyIPInfo &pretest_result) {
+ std::map<uint32_t, ClientCfgEntry>::iterator it;
+ for (it = m_groups.begin(); it != m_groups.end(); it++) {
+ ClientCfgEntry &cfg = it->second;
+ cfg.set_resolved_macs(pretest_result);
+ }
}
+void ClientCfgDB::get_entry_list(std::vector<ClientCfgCompactEntry *> &ret) {
+ uint8_t port;
+ bool result;
+
+ assert(m_tg != NULL);
+ for (std::map<uint32_t, ClientCfgEntry>::iterator it = m_groups.begin(); it != m_groups.end(); ++it) {
+ ClientCfgEntry &cfg = it->second;
+ if (cfg.m_cfg.m_initiator.need_resolve() || cfg.m_cfg.m_initiator.need_resolve()) {
+ result = m_tg->find_port(cfg.m_ip_start, cfg.m_ip_end, port);
+ if (! result) {
+ fprintf(stderr, "Error in clinet config range %s - %s.\n"
+ , ip_to_str(cfg.m_ip_start).c_str(), ip_to_str(cfg.m_ip_end).c_str());
+ exit(-1);
+ }
+ if (port == UINT8_MAX) {
+ // if port not found, it means this adderss is not needed. Don't try to resolve.
+ cfg.m_cfg.m_initiator.set_no_resolve_needed();
+ cfg.m_cfg.m_responder.set_no_resolve_needed();
+ } else {
+ if (cfg.m_cfg.m_initiator.need_resolve()) {
+ ClientCfgCompactEntry *init_entry = new ClientCfgCompactEntry();
+ assert(init_entry);
+ init_entry->m_count = cfg.m_count;
+ init_entry->fill_from_dir(cfg.m_cfg.m_initiator, port);
+ ret.push_back(init_entry);
+ }
+
+ if (cfg.m_cfg.m_responder.need_resolve()) {
+ ClientCfgCompactEntry *resp_entry = new ClientCfgCompactEntry();
+ assert(resp_entry);
+ resp_entry->m_count = cfg.m_count;
+ resp_entry->fill_from_dir(cfg.m_cfg.m_responder, port + 1);
+ ret.push_back(resp_entry);
+ }
+ }
+ }
+ }
+}
/**
- * loads a YAML file containing
- * the client groups configuration
- *
+ * loads a YAML file containing
+ * the client groups configuration
+ *
*/
void
ClientCfgDB::load_yaml_file(const std::string &filename) {
@@ -93,7 +255,7 @@ ClientCfgDB::load_yaml_file(const std::string &filename) {
/**
* reads a single group of clients from YAML
- *
+ *
*/
void
ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node) {
@@ -116,7 +278,7 @@ ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &nod
parse_dir(parser, init, group.m_cfg.m_initiator);
parse_dir(parser, resp, group.m_cfg.m_responder);
-
+
group.m_count = parser.parse_uint(node, "count", 0, UINT64_MAX, 1);
/* add to map with copying */
@@ -124,12 +286,32 @@ ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &nod
}
-void
-ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDir &dir) {
+void
+ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDirExt &dir) {
+ if (node.FindValue("src_ip")) {
+ dir.set_src_ip(parser.parse_ip(node, "src_ip"));
+ }
+
+ if (node.FindValue("src_ipv6")) {
+ uint16_t ip_num[8];
+ parser.parse_ipv6(node, "src_ipv6", (unsigned char *)&ip_num);
+ dir.set_src_ipv6(ip_num);
+ }
+
+ if (node.FindValue("next_hop")) {
+ dir.set_next_hop(parser.parse_ip(node, "next_hop"));
+ }
+
+ if (node.FindValue("ipv6_next_hop")) {
+ uint16_t ip_num[8];
+ parser.parse_ipv6(node, "ipv6_next_hop", (unsigned char *)&ip_num);
+ dir.set_ipv6_next_hop(ip_num);
+ }
+
if (node.FindValue("src_mac")) {
dir.set_src_mac_addr(parser.parse_mac_addr(node, "src_mac"));
}
-
+
if (node.FindValue("dst_mac")) {
dir.set_dst_mac_addr(parser.parse_mac_addr(node, "dst_mac"));
}
@@ -141,11 +323,20 @@ ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, Client
parser.parse_err("VLAN config was disabled", node["vlan"]);
}
}
+
+ if ((dir.has_next_hop() || dir.has_ipv6_next_hop()) && (dir.has_dst_mac_addr() || dir.has_src_mac_addr())) {
+ parser.parse_err("Should not configure both next_hop/ipv6_next_hop and dst_mac or src_mac", node);
+ }
+
+ if (dir.has_next_hop() && dir.has_ipv6_next_hop()) {
+ parser.parse_err("Should not configure both next_hop and ipv6_next_hop", node);
+ }
+
}
/**
* sanity checks
- *
+ *
* @author imarom (28-Jun-16)
*/
void
@@ -154,7 +345,7 @@ ClientCfgDB::verify(const YAMLParserWrapper &parser) const {
uint32_t monotonic = 0;
/* check that no interval overlaps */
-
+
/* all intervals do not overloap iff when sorted each start/end dots are strong monotonic */
for (const auto &p : m_groups) {
const ClientCfgEntry &group = p.second;
@@ -169,13 +360,13 @@ ClientCfgDB::verify(const YAMLParserWrapper &parser) const {
}
/**
- * lookup function
- * should be fast
- *
+ * lookup function
+ * should be fast
+ *
*/
ClientCfgEntry *
ClientCfgDB::lookup(uint32_t ip) {
-
+
/* a cache to avoid constant search (usually its a range of IPs) */
if ( (m_cache_group) && (m_cache_group->contains(ip)) ) {
return m_cache_group;
@@ -185,7 +376,7 @@ ClientCfgDB::lookup(uint32_t ip) {
m_cache_group = NULL;
std::map<uint32_t ,ClientCfgEntry>::iterator it;
-
+
/* upper bound fetchs the first greater element */
it = m_groups.upper_bound(ip);
@@ -217,12 +408,12 @@ ClientCfgDB::lookup(uint32_t ip) {
/**
* for convenience - search by IP as string
- *
+ *
* @author imarom (28-Jun-16)
- *
- * @param ip
- *
- * @return ClientCfgEntry*
+ *
+ * @param ip
+ *
+ * @return ClientCfgEntry*
*/
ClientCfgEntry *
ClientCfgDB::lookup(const std::string &ip) {
@@ -231,5 +422,3 @@ ClientCfgDB::lookup(const std::string &ip) {
return lookup(addr);
}
-
-
diff --git a/src/trex_client_config.h b/src/trex_client_config.h
index a5bb83b3..257d354f 100644
--- a/src/trex_client_config.h
+++ b/src/trex_client_config.h
@@ -24,57 +24,56 @@ limitations under the License.
#include <stdint.h>
#include <string>
#include <map>
+#include "utl_ip.h"
+#include "common/Network/Packet/MacAddress.h"
class YAMLParserWrapper;
+struct CTupleGenYamlInfo;
+class ClientCfgDirExt;
-
+// To save memory, we use here the ClientCfgExt and ClientCfgDirExt,
+// and in tuple_gen the ClientCfgBase and ClientCfgDirBase
/**
* client configuration per direction
- *
+ *
* @author imarom (29-Jun-16)
*/
-class ClientCfgDir {
+class ClientCfgDirBase {
+ friend class ClientCfgCompactEntry;
-private:
+ protected:
enum {
- HAS_SRC_MAC = 0x1,
- HAS_DST_MAC = 0x2,
- HAS_VLAN = 0x4,
+ HAS_SRC_MAC = 0x1,
+ HAS_DST_MAC = 0x2,
+ HAS_VLAN = 0x4,
+ HAS_NEXT_HOP = 0x8,
+ HAS_IPV6_NEXT_HOP = 0x10,
+ HAS_SRC_IP = 0x20,
+ HAS_SRC_IPV6 = 0x40,
};
- uint8_t m_src_mac[6];
- uint8_t m_dst_mac[6];
+ MacAddress m_src_mac;
+ MacAddress m_dst_mac;
uint16_t m_vlan;
uint8_t m_bitfield;
-
-public:
- ClientCfgDir() {
+ public:
+ ClientCfgDirBase() {
m_bitfield = 0;
}
+ virtual void dump(FILE *fd) const;
bool has_src_mac_addr() const {
return (m_bitfield & HAS_SRC_MAC);
}
- bool has_dst_mac_addr() const {
- return (m_bitfield & HAS_DST_MAC);
- }
- bool has_vlan() const {
- return (m_bitfield & HAS_VLAN);
- }
-
void set_src_mac_addr(uint64_t mac_addr) {
- for (int i = 0; i < 6; i++) {
- m_src_mac[i] = ( mac_addr >> ((5 - i) * 8) ) & 0xFF;
- }
+ m_src_mac.set(mac_addr);
m_bitfield |= HAS_SRC_MAC;
}
void set_dst_mac_addr(uint64_t mac_addr) {
- for (int i = 0; i < 6; i++) {
- m_dst_mac[i] = ( mac_addr >> ((5 - i) * 8) ) & 0xFF;
- }
+ m_dst_mac.set(mac_addr);
m_bitfield |= HAS_DST_MAC;
}
@@ -83,26 +82,21 @@ public:
m_bitfield |= HAS_VLAN;
}
- /* updates a configuration with a group index member */
-
- void update(uint32_t index) {
- if (has_src_mac_addr()) {
- mac_add(m_src_mac, index);
- }
-
- if (has_dst_mac_addr()) {
- mac_add(m_dst_mac, index);
- }
+ bool has_dst_mac_addr() const {
+ return (m_bitfield & HAS_DST_MAC);
+ }
+ bool has_vlan() const {
+ return (m_bitfield & HAS_VLAN);
}
const uint8_t *get_src_mac_addr() const {
assert(has_src_mac_addr());
- return m_src_mac;
+ return m_src_mac.GetConstBuffer();
}
const uint8_t *get_dst_mac_addr() const {
assert(has_dst_mac_addr());
- return m_dst_mac;
+ return m_dst_mac.GetConstBuffer();
}
uint16_t get_vlan() const {
@@ -110,64 +104,165 @@ public:
return m_vlan;
}
+ /* updates a configuration with a group index member */
+ void update(uint32_t index, const ClientCfgDirExt &cfg);
+};
+
+class ClientCfgDirExt : public ClientCfgDirBase {
+ friend class ClientCfgCompactEntry;
+
private:
- /**
- * transform MAC address to uint64_t
- * performs add and return to MAC format
- *
- */
- void mac_add(uint8_t *mac, uint32_t i) {
- uint64_t tmp = 0;
+ enum {
+ HAS_SRC_MAC = 0x1,
+ HAS_DST_MAC = 0x2,
+ HAS_VLAN = 0x4,
+ HAS_NEXT_HOP = 0x8,
+ HAS_IPV6_NEXT_HOP = 0x10,
+ HAS_SRC_IP = 0x20,
+ HAS_SRC_IPV6 = 0x40,
+ };
- for (int i = 0; i < 6; i++) {
- tmp <<= 8;
- tmp |= mac[i];
+ uint32_t m_next_hop;
+ uint32_t m_src_ip;
+ uint16_t m_src_ipv6[8];
+ uint16_t m_ipv6_next_hop[8];
+ std::vector <MacAddress> m_resolved_macs;
+
+public:
+ void dump(FILE *fd) const;
+ void set_resolved_macs(CManyIPInfo &pretest_result, uint16_t count);
+ bool need_resolve() const;
+ void set_no_resolve_needed();
+
+ bool has_ipv6_next_hop() const {
+ return (m_bitfield & HAS_IPV6_NEXT_HOP);
+ }
+
+ bool has_next_hop() const {
+ return (m_bitfield & HAS_NEXT_HOP);
+ }
+
+ bool has_src_ip() const {
+ return (m_bitfield & HAS_SRC_IP);
+ }
+
+ bool has_src_ipv6() const {
+ return (m_bitfield & HAS_SRC_IPV6);
+ }
+
+ void set_src_ip(uint32_t src_ip) {
+ m_src_ip = src_ip;
+ m_bitfield |= HAS_SRC_IP;
+ }
+
+ void set_src_ipv6(const uint16_t src_ipv6[8]) {
+ for (int i = 0; i < 8; i++) {
+ m_src_ipv6[i] = src_ipv6[i];
}
+ m_bitfield |= HAS_SRC_IPV6;
+ }
- tmp += i;
+ void set_next_hop(uint32_t next_hop) {
+ m_next_hop = next_hop;
+ m_bitfield |= HAS_NEXT_HOP;
+ }
- for (int i = 0; i < 6; i++) {
- mac[i] = ( tmp >> ((5 - i) * 8) ) & 0xFF;
+ void set_ipv6_next_hop(const uint16_t next_hop[8]) {
+ for (int i = 0; i < 8; i++) {
+ m_ipv6_next_hop[i] = next_hop[i];
}
+ m_bitfield |= HAS_IPV6_NEXT_HOP;
+ }
+ virtual MacAddress get_resolved_mac(uint16_t index) const {
+ return m_resolved_macs[index];
}
+
};
+class ClientCfgExt;
+
/**
* single client config
- *
+ *
*/
-class ClientCfg {
+class ClientCfgBase {
public:
+ virtual void dump (FILE *fd) const {
+ fprintf(fd, " initiator :\n");
+ m_initiator.dump(fd);
+ fprintf(fd, " responder :\n");
+ m_responder.dump(fd);
+ }
+ virtual void update(uint32_t index, const ClientCfgExt *cfg);
- void update(uint32_t index) {
- m_initiator.update(index);
- m_responder.update(index);
+ public:
+ ClientCfgDirBase m_initiator;
+ ClientCfgDirBase m_responder;
+};
+
+class ClientCfgExt : public ClientCfgBase {
+public:
+ virtual void dump (FILE *fd) const {
+ fprintf(fd, " initiator:\n");
+ m_initiator.dump(fd);
+ fprintf(fd, " responder:\n");
+ m_responder.dump(fd);
}
- ClientCfgDir m_initiator;
- ClientCfgDir m_responder;
+ ClientCfgDirExt m_initiator;
+ ClientCfgDirExt m_responder;
+};
+
+class ClientCfgCompactEntry {
+ friend class ClientCfgDB;
+ public:
+ uint16_t get_count() {return m_count;}
+ uint16_t get_vlan() {return m_vlan;}
+ uint16_t get_port() {return m_port;}
+ bool is_ipv4() {return m_is_ipv4;}
+ uint32_t get_dst_ip() {return m_next_hop_base.ip;}
+ uint16_t *get_dst_ipv6() {return m_next_hop_base.ipv6;}
+ uint32_t get_src_ip() {return m_src_ip.ip;}
+ uint16_t *get_src_ipv6() {return m_src_ip.ipv6;}
+
+ public:
+ void fill_from_dir(ClientCfgDirExt cfg, uint8_t port_id);
+
+ private:
+ uint16_t m_count;
+ uint16_t m_vlan;
+ uint8_t m_port;
+ bool m_is_ipv4;
+ union {
+ uint32_t ip;
+ uint16_t ipv6[8];
+ } m_next_hop_base;
+ union {
+ uint32_t ip;
+ uint16_t ipv6[8];
+ } m_src_ip;
+
};
/******************************** internal section ********************************/
/**
- * describes a single client config
+ * describes a single client config
* entry loaded from the config file
- *
+ *
*/
class ClientCfgEntry {
-
+ friend class basic_client_cfg_test1_Test;
public:
ClientCfgEntry() {
reset();
}
-
- void dump() const;
-
+ void dump(FILE *fd) const;
+ void set_resolved_macs(CManyIPInfo &pretest_result);
bool contains(uint32_t ip) const {
return ( (ip >= m_ip_start) && (ip <= m_ip_end) );
}
@@ -176,19 +271,19 @@ public:
m_iterator = 0;
}
-
+
/**
- * assings a client config from the group
- * it will advance MAC addresses andf etc.
- *
+ * assings a client config from the group
+ * it will advance MAC addresses andf etc.
+ *
* @author imarom (27-Jun-16)
- *
- * @param info
+ *
+ * @param info
*/
- void assign(ClientCfg &info) {
+ void assign(ClientCfgBase &info) {
info = m_cfg;
- info.update(m_iterator);
-
+ info.update(m_iterator, &m_cfg);
+
/* advance for the next assign */
m_iterator = (m_iterator + 1) % m_count;
}
@@ -197,69 +292,92 @@ public:
uint32_t m_ip_start;
uint32_t m_ip_end;
- ClientCfg m_cfg;
+ ClientCfgExt m_cfg;
uint32_t m_count;
private:
+ void set_params(uint32_t start, uint32_t end, uint32_t count) { // for tests
+ m_ip_start = start;
+ m_ip_end = end;
+ m_count = count;
+ }
+ void set_cfg(const ClientCfgExt &cfg) {
+ m_cfg = cfg;
+ }
uint32_t m_iterator;
};
/**
* holds all the configured clients groups
- *
+ *
*/
class ClientCfgDB {
-public:
+ friend class basic_client_cfg_test1_Test;
+ public:
ClientCfgDB() {
m_is_empty = true;
m_cache_group = NULL;
m_under_vlan = false;
+ m_tg = NULL;
}
+ ~ClientCfgDB() {
+ m_groups.clear();
+ }
+
+ void dump(FILE *fd) ;
+
/**
- * if no config file was loaded
- * this should return true
- *
+ * if no config file was loaded
+ * this should return true
+ *
*/
bool is_empty() {
return m_is_empty;
}
+ void set_resolved_macs(CManyIPInfo &pretest_result);
+ void get_entry_list(std::vector<ClientCfgCompactEntry *> &ret);
+
+
/**
- * loads a YAML file
- * configuration will be built
- * according to the YAML config
- *
+ * loads a YAML file
+ * configuration will be built
+ * according to the YAML config
+ *
*/
void load_yaml_file(const std::string &filename);
/**
- * lookup for a specific IP address for
- * a group that contains this IP
- *
+ * lookup for a specific IP address for
+ * a group that contains this IP
+ *
*/
ClientCfgEntry * lookup(uint32_t ip);
ClientCfgEntry * lookup(const std::string &ip);
+ void set_tuple_gen_info(CTupleGenYamlInfo *tg) {m_tg = tg;}
private:
void parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node);
- void parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDir &dir);
-
+ void parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDirExt &dir);
+ void set_vlan(bool val) {m_under_vlan = val;} // for tests
+ void add_group(uint32_t ip, ClientCfgEntry cfg) { // for tests
+ m_groups.insert(std::make_pair(ip, cfg));
+ }
/**
* verify the YAML file loaded in valid
- *
+ *
*/
void verify(const YAMLParserWrapper &parser) const;
/* maps the IP start value to client groups */
std::map<uint32_t, ClientCfgEntry> m_groups;
- bool m_under_vlan;
-
- ClientCfgEntry *m_cache_group;
- bool m_is_empty;
+ bool m_under_vlan;
+ CTupleGenYamlInfo * m_tg;
+ ClientCfgEntry * m_cache_group;
+ bool m_is_empty;
};
#endif /* __TREX_CLIENT_CONFIG_H__ */
-
diff --git a/src/tuple_gen.cpp b/src/tuple_gen.cpp
index 6861b73f..a4509580 100755
--- a/src/tuple_gen.cpp
+++ b/src/tuple_gen.cpp
@@ -6,7 +6,7 @@
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,11 +21,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-
-#include "tuple_gen.h"
#include <string.h>
#include "utl_yaml.h"
#include "bp_sim.h"
+#include "tuple_gen.h"
void CServerPool::Create(IP_DIST_t dist_value,
uint32_t min_ip,
@@ -134,7 +133,7 @@ void CClientPool::allocate_configured_clients(uint32_t min_ip,
throw std::runtime_error(ss.str());
}
- ClientCfg info;
+ ClientCfgBase info;
group->assign(info);
if (is_long_range) {
@@ -216,13 +215,84 @@ void CTupleGeneratorSmart::Delete(){
m_server_pool.clear();
}
+void CTupleGenYamlInfo::dump(FILE *fd) {
+ fprintf(fd, "Client pools:\n");
+ for (int i=0; i < m_client_pool.size(); i++) {
+ m_client_pool[i].Dump(fd);
+ }
+ fprintf(fd, "Server pools:\n");
+ for (int i=0; i < m_server_pool.size(); i++) {
+ m_server_pool[i].Dump(fd);
+ }
+}
+
+// Find out matching port for given ip range.
+// If found, port is returned in port, otherwise port is set to UINT8_MAX
+// Return false in case of error. True otherwise. Port not found is not considered error.
+bool CTupleGenYamlInfo::find_port(uint32_t ip_start, uint32_t ip_end, uint8_t &port) {
+ uint8_t num_ports = CGlobalInfo::m_options.get_expected_ports();
+
+ for (int i=0; i < m_client_pool.size(); i++) {
+ CTupleGenPoolYaml &pool = m_client_pool[i];
+ uint32_t pool_start = pool.get_ip_start();
+ uint32_t pool_end = pool.get_ip_end();
+ uint32_t pool_offset = pool.getDualMask();
+ for (uint8_t port_id = 0; port_id < num_ports; port_id += 2) {
+ uint32_t pool_port_start = pool_start + pool_offset * port_id / 2;
+ uint32_t pool_port_end = pool_end + pool_offset * port_id / 2;
+ if ((ip_start >= pool_port_start) && (ip_start <= pool_port_end)) {
+ if ((ip_end >= pool_port_start) && (ip_end <= pool_port_end)) {
+ port = port_id;
+ return true;
+ } else {
+ // ip_start in range, ip_end not
+ fprintf(stderr, "Error for range %s - %s. Start is inside range %s - %s, but end is outside\n"
+ , ip_to_str(ip_start).c_str(), ip_to_str(ip_end).c_str()
+ , ip_to_str(pool_port_start).c_str(), ip_to_str(pool_port_end).c_str());
+ port = UINT8_MAX;
+ return false;
+ }
+ }
+ }
+ }
+
+ for (int i=0; i < m_server_pool.size(); i++) {
+ CTupleGenPoolYaml &pool = m_server_pool[i];
+ uint32_t pool_start = pool.get_ip_start();
+ uint32_t pool_end = pool.get_ip_end();
+ uint32_t pool_offset = pool.getDualMask();
+ for (uint8_t port_id = 1; port_id < num_ports; port_id += 2) {
+ uint32_t pool_port_start = pool_start + pool_offset * (port_id - 1) / 2;
+ uint32_t pool_port_end = pool_end + pool_offset * (port_id - 1)/ 2;
+ if ((ip_start >= pool_port_start) && (ip_start <= pool_port_end)) {
+ if ((ip_end >= pool_port_start) && (ip_end <= pool_port_end)) {
+ port = port_id;
+ return true;
+ } else {
+ fprintf(stderr, "Error for range %s - %s. Start is inside range %s - %s, but end is outside\n"
+ , ip_to_str(ip_start).c_str(), ip_to_str(ip_end).c_str()
+ , ip_to_str(pool_port_start).c_str(), ip_to_str(pool_port_end).c_str());
+ // ip_start in range, ip_end not
+ port = UINT8_MAX;
+ return false;
+ }
+ }
+ }
+ }
+
+ port = UINT8_MAX;
+ return true;
+}
+
void CTupleGenPoolYaml::Dump(FILE *fd){
- fprintf(fd," dist : %d \n",m_dist);
- fprintf(fd," IPs : %08x -%08x \n",m_ip_start,m_ip_end);
- fprintf(fd," clients per gb : %d \n",m_number_of_clients_per_gb);
- fprintf(fd," min clients : %d \n",m_min_clients);
- fprintf(fd," tcp aging : %d sec \n",m_tcp_aging_sec);
- fprintf(fd," udp aging : %d sec \n",m_udp_aging_sec);
+ fprintf(fd," Pool %s:\n", (m_name.size() == 0) ? "default":m_name.c_str());
+ fprintf(fd," dist : %d \n",m_dist);
+ fprintf(fd," IPs : %s - %s \n",ip_to_str(m_ip_start).c_str(), ip_to_str(m_ip_end).c_str());
+ fprintf(fd," dual_port_mask : %s \n",ip_to_str(m_dual_interface_mask).c_str());
+ fprintf(fd," clients per gb : %d \n",m_number_of_clients_per_gb);
+ fprintf(fd," min clients : %d \n",m_min_clients);
+ fprintf(fd," tcp aging : %d sec \n",m_tcp_aging_sec);
+ fprintf(fd," udp aging : %d sec \n",m_udp_aging_sec);
}
bool CTupleGenPoolYaml::is_valid(uint32_t num_threads,bool is_plugins){
@@ -244,10 +314,6 @@ bool CTupleGenPoolYaml::is_valid(uint32_t num_threads,bool is_plugins){
return (true);
}
-
-
-
-
#define UTL_YAML_READ(type, field, target) if (node.FindValue(#field)) { \
utl_yaml_read_ ## type (node, #field , target); \
} else { printf("generator definition mising " #field "\n"); }
diff --git a/src/tuple_gen.h b/src/tuple_gen.h
index 2491f489..e9dc8d4e 100755
--- a/src/tuple_gen.h
+++ b/src/tuple_gen.h
@@ -85,15 +85,15 @@ public:
void setClientPort(uint16_t port) {
m_client_port = port;
}
- void setClientCfg(ClientCfg *cfg) {
+ void setClientCfg(ClientCfgBase *cfg) {
m_client_cfg = cfg;
}
- ClientCfg *getClientCfg() {
+ ClientCfgBase *getClientCfg() {
return m_client_cfg;
}
- void setClientTuple(uint32_t ip, ClientCfg *cfg, uint16_t port) {
+ void setClientTuple(uint32_t ip, ClientCfgBase *cfg, uint16_t port) {
setClient(ip);
setClientPort(port);
setClientCfg(cfg);
@@ -125,7 +125,7 @@ private:
uint32_t m_server_ip;
uint32_t m_server_idx;
- ClientCfg *m_client_cfg;
+ ClientCfgBase *m_client_cfg;
uint16_t m_client_port;
uint16_t m_server_port;
@@ -337,7 +337,7 @@ template <typename T>
class CConfiguredClientInfo : public T {
public:
- CConfiguredClientInfo(uint32_t ip, const ClientCfg &cfg) : m_cfg(cfg) {
+ CConfiguredClientInfo(uint32_t ip, const ClientCfgBase &cfg) : m_cfg(cfg) {
T::set_ip(ip);
}
@@ -348,7 +348,7 @@ public:
}
private:
- ClientCfg m_cfg;
+ ClientCfgBase m_cfg;
};
@@ -852,6 +852,9 @@ struct CTupleGenPoolYaml {
uint32_t get_ip_start() {
return m_ip_start;
}
+ uint32_t get_ip_end() {
+ return m_ip_end;
+ }
bool is_valid(uint32_t num_threads,bool is_plugins);
void Dump(FILE *fd);
};
@@ -888,6 +891,9 @@ public:
exit(-1);
return 0;
}
+
+ bool find_port(uint32_t ip_start, uint32_t ip_end, uint8_t &port);
+ void dump(FILE *fd);
};
diff --git a/src/utl_ip.cpp b/src/utl_ip.cpp
new file mode 100644
index 00000000..5bd83f95
--- /dev/null
+++ b/src/utl_ip.cpp
@@ -0,0 +1,121 @@
+/*
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+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
+
+ http://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.
+*/
+#include <string>
+#include <iostream>
+#include <pkt_gen.h>
+#include "utl_ip.h"
+
+void COneIPInfo::dump(FILE *fd, const char *offset) const {
+ uint8_t mac[ETHER_ADDR_LEN];
+ m_mac.copyToArray(mac);
+ char ip_str[100];
+ get_ip_str(ip_str);
+ std::string mac_str;
+ utl_macaddr_to_str(mac, mac_str);
+ const char *mac_char = resolve_needed() ? "Not resolved" : mac_str.c_str();
+ fprintf(fd, "%sip: %s vlan: %d port: %d mac: %s\n", offset, ip_str, m_vlan, m_port, mac_char);
+}
+
+bool COneIPInfo::resolve_needed() const {
+ return m_mac.isDefaultAddress();
+}
+
+/*
+ * Fill buffer p with arp request.
+ * port_id - port id we intend to send on
+ * sip - source IP/MAC information
+ */
+void COneIPv4Info::fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip) {
+ uint8_t src_mac[ETHER_ADDR_LEN];
+ sip->get_mac(src_mac);
+
+ CTestPktGen::create_arp_req(p, ((COneIPv4Info *)sip)->get_ip(), m_ip, src_mac, m_vlan, port_id);
+}
+
+void COneIPv4Info::fill_grat_arp_buf(uint8_t *p) {
+ uint8_t src_mac[ETHER_ADDR_LEN];
+ get_mac(src_mac);
+
+ CTestPktGen::create_arp_req(p, m_ip, m_ip, src_mac, m_vlan, 0);
+}
+
+void COneIPv6Info::fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip) {
+ //??? implement ipv6
+}
+
+void COneIPv6Info::fill_grat_arp_buf(uint8_t *p) {
+ //??? implement ipv6
+}
+
+const COneIPInfo *CManyIPInfo::get_next() {
+ COneIPInfo *ret;
+
+ if (!m_iter_initiated) {
+ m_ipv4_iter = m_ipv4_resolve.begin();
+ m_iter_initiated = true;
+ }
+
+ if (m_ipv4_iter == m_ipv4_resolve.end()) {
+ m_ipv4_iter = m_ipv4_resolve.begin();
+ return NULL;
+ }
+
+ ret = &(m_ipv4_iter->second);
+ m_ipv4_iter++;
+ return ret;
+}
+
+void CManyIPInfo::dump(FILE *fd) {
+ ip_vlan_to_many_ip_iter_t it;
+ for (it = m_ipv4_resolve.begin(); it != m_ipv4_resolve.end(); it++) {
+ fprintf(fd, "IPv4 resolved list:\n");
+ uint8_t mac[ETHER_ADDR_LEN];
+ it->second.get_mac(mac);
+ fprintf(fd, "ip:%s vlan: %d resolved to mac %s\n", ip_to_str(it->first.get_ip()).c_str(), it->first.get_vlan()
+ , utl_macaddr_to_str(mac).c_str());
+ }
+}
+
+void CManyIPInfo::insert(COneIPv4Info &ip_info) {
+ CIpVlan ip_vlan(ip_info.get_ip(), ip_info.get_vlan());
+
+ m_ipv4_resolve.insert(std::make_pair(ip_vlan, ip_info));
+}
+
+bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) {
+ ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan));
+ if (it != m_ipv4_resolve.end()) {
+ uint8_t mac[ETHER_ADDR_LEN];
+ (*it).second.get_mac(mac);
+ ret_mac.set(mac);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+const COneIPInfo *CManyIPInfo::get_first() {
+ if (m_ipv4_resolve.size() == 0) {
+ return NULL;
+ } else {
+ m_ipv4_iter = m_ipv4_resolve.begin();
+ return &(m_ipv4_iter->second);
+ }
+}
diff --git a/src/utl_ip.h b/src/utl_ip.h
new file mode 100644
index 00000000..3a133a15
--- /dev/null
+++ b/src/utl_ip.h
@@ -0,0 +1,246 @@
+#ifndef UTL_IP_H
+#define UTL_IP_H
+/*
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+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
+
+ http://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.
+*/
+#include <map>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "common/basic_utils.h"
+#include "common/Network/Packet/CPktCmn.h"
+#include "common/Network/Packet/MacAddress.h"
+
+/* IP address, last 32-bits of IPv6 remaps IPv4 */
+typedef struct {
+ uint16_t v6[6]; /* First 96-bits of IPv6 */
+ uint32_t v4; /* Last 32-bits IPv6 overloads v4 */
+} ipaddr_t;
+
+// Routine to create IPv4 address string
+inline int ip_to_str(uint32_t ip,char * str) {
+ uint32_t ipv4 = PKT_HTONL(ip);
+ inet_ntop(AF_INET, (const char *)&ipv4, str, INET_ADDRSTRLEN);
+ return(strlen(str));
+}
+
+inline std::string ip_to_str(uint32_t ip) {
+ char tmp[INET_ADDRSTRLEN];
+ ip_to_str(ip, tmp);
+ return tmp;
+}
+
+// Routine to create IPv6 address string
+inline int ipv6_to_str(ipaddr_t *ip, char * str) {
+ int idx=0;
+ uint16_t ipv6[8];
+ for (uint8_t i=0; i<6; i++) {
+ ipv6[i] = PKT_HTONS(ip->v6[i]);
+ }
+ uint32_t ipv4 = PKT_HTONL(ip->v4);
+ ipv6[6] = ipv4 & 0xffff;
+ ipv6[7] = ipv4 >> 16;
+
+ str[idx++] = '[';
+ inet_ntop(AF_INET6, (const char *)&ipv6, &str[1], INET6_ADDRSTRLEN);
+ idx = strlen(str);
+ str[idx++] = ']';
+ str[idx] = 0;
+ return(idx);
+}
+
+inline std::string ip_to_str(uint8_t *ip) {
+ char tmp[INET6_ADDRSTRLEN];
+ ipv6_to_str((ipaddr_t *)ip, tmp);
+ return tmp;
+}
+
+class CIpVlan {
+ // to be able to use this in map
+ friend bool operator<(const CIpVlan& l, const CIpVlan& r) {
+ if (l.get_ip() == r.get_ip()) {
+ return l.get_vlan() < r.get_vlan();
+ } else {
+ return l.get_ip() < r.get_ip();
+ }
+ }
+
+ public:
+ CIpVlan(uint32_t ip, uint16_t vlan) {
+ m_ip = ip;
+ m_vlan = vlan;
+ }
+ uint16_t get_vlan() const {return m_vlan;}
+ void set_vlan(uint16_t vlan) {m_vlan = vlan;}
+ uint16_t get_ip() const {return m_ip;}
+ void set_ip(uint32_t ip) {m_ip = ip;}
+
+ private:
+ uint32_t m_ip;
+ uint16_t m_vlan;
+};
+
+
+class COneIPInfo {
+ public:
+ enum {
+ IP4_VER=4,
+ IP6_VER=6,
+ } COneIPInfo_ip_types;
+
+ public:
+ virtual void get_mac(uint8_t *mac) const {
+ m_mac.copyToArray(mac);
+ }
+ virtual void set_mac(uint8_t *mac) {
+ m_mac.set(mac);
+ }
+ uint16_t get_vlan() const {return m_vlan;}
+ uint16_t get_port() const {return m_port;}
+ virtual void dump(FILE *fd) const {
+ dump(fd, "");
+ }
+ virtual void dump(FILE *fd, const char *offset) const;
+ virtual uint8_t ip_ver() const {return 0;}
+ virtual uint32_t get_arp_req_len() const=0;
+ virtual uint32_t get_grat_arp_len() const=0;
+ virtual void fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip)=0;
+ virtual void fill_grat_arp_buf(uint8_t *p)=0;
+ virtual bool resolve_needed() const;
+
+ protected:
+ COneIPInfo(uint16_t vlan, MacAddress mac, uint8_t port) : m_mac(mac) {
+ m_vlan = vlan;
+ m_port = port;
+ }
+ COneIPInfo(uint16_t vlan, MacAddress mac) : COneIPInfo(vlan, mac, UINT8_MAX) {
+ }
+ virtual const void get_ip_str(char str[100]) const {
+ snprintf(str, 4, "Bad");
+ }
+
+ protected:
+ uint8_t m_port;
+ uint16_t m_vlan;
+ MacAddress m_mac;
+};
+
+class COneIPv4Info : public COneIPInfo {
+ friend bool operator== (const COneIPv4Info& lhs, const COneIPv4Info& rhs);
+
+ public:
+ COneIPv4Info(uint32_t ip, uint16_t vlan, MacAddress mac) : COneIPInfo(vlan, mac) {
+ m_ip = ip;
+ }
+ COneIPv4Info(uint32_t ip, uint16_t vlan) : COneIPv4Info (ip, vlan, MacAddress()) {
+ }
+ COneIPv4Info(uint32_t ip, uint16_t vlan, MacAddress mac, uint8_t port) : COneIPInfo(vlan, mac, port) {
+ m_ip = ip;
+ }
+ uint32_t get_ip() {return m_ip;}
+ virtual uint8_t ip_ver() const {return IP4_VER;}
+ virtual uint32_t get_arp_req_len() const {return 60;}
+ virtual uint32_t get_grat_arp_len() const {return 60;}
+ virtual void fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip);
+ virtual void fill_grat_arp_buf(uint8_t *p);
+
+ private:
+ virtual const void get_ip_str(char str[100]) const {
+ ip_to_str(m_ip, str);
+ };
+ uint32_t m_ip;
+};
+
+inline bool operator== (const COneIPv4Info& lhs, const COneIPv4Info& rhs) {
+ if (lhs.m_vlan != rhs.m_vlan)
+ return false;
+
+ if (lhs.m_ip != rhs.m_ip)
+ return false;
+
+ return true;
+}
+
+inline bool operator!= (const COneIPv4Info& lhs, const COneIPv4Info& rhs){ return !(lhs == rhs); }
+
+class COneIPv6Info : public COneIPInfo {
+ friend bool operator== (const COneIPv6Info& lhs, const COneIPv6Info& rhs);
+
+ public:
+ COneIPv6Info(uint16_t ip[8], uint16_t vlan, MacAddress mac) : COneIPInfo(vlan, mac) {
+ memcpy(m_ip, ip, sizeof(m_ip));
+ }
+
+ COneIPv6Info(uint16_t ip[8], uint16_t vlan) : COneIPv6Info(ip, vlan, MacAddress()){
+ }
+
+ COneIPv6Info(uint16_t ip[8], uint16_t vlan, MacAddress mac, uint8_t port) : COneIPInfo(vlan, mac, port) {
+ memcpy(m_ip, ip, sizeof(m_ip));
+ }
+
+ const uint8_t *get_ipv6() {return (uint8_t *)m_ip;}
+ virtual uint8_t ip_ver() const {return IP6_VER;}
+ virtual uint32_t get_arp_req_len() const {return 100; /* ??? put correct number for ipv6*/}
+ virtual uint32_t get_grat_arp_len() const {return 100; /* ??? put correct number for ipv6*/}
+ virtual void fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip);
+ virtual void fill_grat_arp_buf(uint8_t *p);
+
+ private:
+ virtual const void get_ip_str(char str[100]) {
+ ipv6_to_str((ipaddr_t *)m_ip, str);
+ }
+ uint16_t m_ip[8];
+};
+
+inline bool operator== (const COneIPv6Info& lhs, const COneIPv6Info& rhs) {
+ if (lhs.m_vlan != rhs.m_vlan)
+ return false;
+
+ if (memcmp(&lhs.m_ip, &rhs.m_ip, sizeof(rhs.m_ip)))
+ return false;
+
+ return true;
+}
+
+inline bool operator!= (const COneIPv6Info& lhs, const COneIPv6Info& rhs){ return !(lhs == rhs); }
+
+typedef std::map<CIpVlan, COneIPv4Info> ip_vlan_to_many_ip_t;
+typedef std::map<CIpVlan, COneIPv4Info>::iterator ip_vlan_to_many_ip_iter_t;
+typedef std::map<std::pair<uint16_t[8], uint16_t>, COneIPv6Info> ipv6_vlan_to_many_ipv6_t;
+
+class CManyIPInfo {
+ public:
+ CManyIPInfo () {
+ m_iter_initiated = false;
+ }
+ void insert(COneIPv4Info &ip_info);
+ bool lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac);
+ void dump(FILE *fd);
+ uint32_t size() { return m_ipv4_resolve.size() + m_ipv6_resolve.size();}
+ const COneIPInfo *get_first();
+ const COneIPInfo *get_next();
+ private:
+ ip_vlan_to_many_ip_t m_ipv4_resolve;
+ ip_vlan_to_many_ip_iter_t m_ipv4_iter;
+ ipv6_vlan_to_many_ipv6_t m_ipv6_resolve;
+ bool m_iter_initiated;
+
+};
+
+#endif
diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp
index 094a3de8..a4fd6404 100755
--- a/src/utl_yaml.cpp
+++ b/src/utl_yaml.cpp
@@ -1,12 +1,10 @@
-#include "utl_yaml.h"
-#include <common/Network/Packet/CPktCmn.h>
/*
Hanoh Haim
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -24,13 +22,15 @@ limitations under the License.
#include <istream>
#include <fstream>
#include "common/basic_utils.h"
+#include <common/Network/Packet/CPktCmn.h>
+#include "utl_yaml.h"
#define INADDRSZ 4
extern int my_inet_pton4(const char *src, unsigned char *dst);
extern int my_inet_pton6(const char *src, unsigned char *dst);
-bool utl_yaml_read_ip_addr(const YAML::Node& node,
+bool utl_yaml_read_ip_addr(const YAML::Node& node,
const std::string &name,
uint32_t & val){
std::string tmp;
@@ -42,16 +42,14 @@ bool utl_yaml_read_ip_addr(const YAML::Node& node,
val=PKT_NTOHL(ip);
res=true;
}else{
- printf(" ERROR not a valid ip %s \n",(char *)tmp.c_str());
+ printf(" Error: non valid ip %s \n",(char *)tmp.c_str());
exit(-1);
}
}
return (res);
}
-
-
-bool utl_yaml_read_uint32(const YAML::Node& node,
+bool utl_yaml_read_uint32(const YAML::Node& node,
const std::string &name,
uint32_t & val){
bool res=false;
@@ -62,7 +60,7 @@ bool utl_yaml_read_uint32(const YAML::Node& node,
return (res);
}
-bool utl_yaml_read_uint16(const YAML::Node& node,
+bool utl_yaml_read_uint16(const YAML::Node& node,
const std::string &name,
uint16_t & val){
uint32_t val_tmp;
@@ -183,10 +181,10 @@ YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name) {
return (val);
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting true/false for field '" + name + "'", node[name]);
+ parse_err("Expecting true/false for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -203,10 +201,10 @@ YAMLParserWrapper::parse_list(const YAML::Node &node, const std::string &name) {
return val;
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting sequence/list for field '" + name + "'", node[name]);
+ parse_err("Expecting sequence or list for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -223,10 +221,10 @@ YAMLParserWrapper::parse_map(const YAML::Node &node, const std::string &name) {
return val;
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting map for field '" + name + "'", node[name]);
+ parse_err("Expecting map for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -241,16 +239,43 @@ YAMLParserWrapper::parse_ip(const YAML::Node &node, const std::string &name) {
node[name] >> ip_str;
int rc = my_inet_pton4((char *)ip_str.c_str(), (unsigned char *)&ip_num);
if (!rc) {
- parse_err("invalid IP address: " + ip_str, node[name]);
+ parse_err("Invalid IP address: " + ip_str, node[name]);
}
return PKT_NTOHL(ip_num);
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting valid IP address for field '" + name + "'", node[name]);
+ parse_err("Expecting valid IP address for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("Can not locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+void
+YAMLParserWrapper::parse_ipv6(const YAML::Node &node, const std::string &name, unsigned char *ip_num) {
+ try {
+ std::string ip_str;
+
+ node[name] >> ip_str;
+ int rc = my_inet_pton6((char *)ip_str.c_str(), ip_num);
+ if (!rc) {
+ parse_err("Invalid IPv6 address: " + ip_str, node[name]);
+ }
+
+ // we want host order
+ for (int i = 0; i < 8; i++) {
+ ((uint16_t *) ip_num)[i] = PKT_NTOHS(((uint16_t *) ip_num)[i]);
+ }
+ return;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("Expecting valid IPv6 address for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -276,21 +301,21 @@ YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &nam
node[name] >> mac_str;
bool rc = mac2uint64(mac_str, mac_num);
if (!rc) {
- parse_err("invalid MAC address: " + mac_str, node[name]);
+ parse_err("Invalid MAC address: " + mac_str, node[name]);
}
return mac_num;
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting true/false for field '" + name + "'", node[name]);
+ parse_err("Expecting true/false for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
}
-uint64_t
+uint64_t
YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high, uint64_t def) {
if (!node.FindValue(name)) {
return def;
@@ -299,7 +324,7 @@ YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, u
return parse_uint(node, name, low, high);
}
-uint64_t
+uint64_t
YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high) {
try {
@@ -316,10 +341,10 @@ YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, u
return (val);
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting true/false for field '" + name + "'", node[name]);
+ parse_err("Expecting true/false for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
diff --git a/src/utl_yaml.h b/src/utl_yaml.h
index ed7d66d6..004e82db 100755
--- a/src/utl_yaml.h
+++ b/src/utl_yaml.h
@@ -63,6 +63,7 @@ public:
const YAML::Node & parse_map(const YAML::Node &node, const std::string &name);
uint32_t parse_ip(const YAML::Node &node, const std::string &name);
+ void parse_ipv6(const YAML::Node &node, const std::string &name, unsigned char *ip);
uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name);
uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name, uint64_t def);