Introduce doc/examples/ directory
It contains simple usual setups to get started with osmo-gsm-tester,
such as creating a 4G network using srsLTE or a 2G network using the
osmocom stack (+ ofono modems).
Change-Id: I55d5b1152da201799af21a77ef6c562f97bd94fc
diff --git a/doc/examples/2g_osmocom/README.txt b/doc/examples/2g_osmocom/README.txt
new file mode 100644
index 0000000..4c869ca
--- /dev/null
+++ b/doc/examples/2g_osmocom/README.txt
@@ -0,0 +1,30 @@
+This a sample gsm test suite configured and ready to use.
+The only thing missing is a trial dir containing binaries.
+
+You can point osmo-gsm-tester.py at this config using the OSMO_GSM_TESTER_CONF
+environment variable:
+
+ export OSMO_GSM_TESTER_CONF="$PWD"
+
+When there is no OSMO_GSM_TESTER_CONF set, osmo-gsm-tester will instead look
+for conf files in several locations like ~/.config/osmo-gsm-tester,
+/usr/local/etc/osmo-gsm-tester, /etc/osmo-gsm-tester.
+
+If you have your trial with binary tar archives in ~/my_trial
+you can run the suite for example like this:
+
+ osmo-gsm-tester.py ~/my_trial
+
+Specifically, from this dir:
+
+ OSMO_GSM_TESTER_CONF="$PWD" ../src/osmo-gsm-tester.py ~/my_trial
+
+Alternatively you can setup this example as permanent config using something
+like:
+
+ mkdir -p ~/.config
+ ln -s "$PWD" ~/.config/osmo-gsm-tester
+
+A ./state dir will be created to store the current osmo-gsm-tester state. If
+you prefer not to write to $PWD, set up an own configuration pointing at a
+different path (see paths.conf: 'state_dir').
diff --git a/doc/examples/2g_osmocom/default-suites.conf b/doc/examples/2g_osmocom/default-suites.conf
new file mode 100644
index 0000000..94cf9c5
--- /dev/null
+++ b/doc/examples/2g_osmocom/default-suites.conf
@@ -0,0 +1 @@
+- sms:trx-b200
diff --git a/doc/examples/2g_osmocom/defaults.conf b/doc/examples/2g_osmocom/defaults.conf
new file mode 100644
index 0000000..06d596a
--- /dev/null
+++ b/doc/examples/2g_osmocom/defaults.conf
@@ -0,0 +1,63 @@
+bsc:
+ net:
+ mcc: 901
+ mnc: 70
+ short_name: osmo-gsm-tester-msc
+ long_name: osmo-gsm-tester-msc
+ encryption: a5_0
+ codec_list:
+ - fr1
+
+msc:
+ net:
+ mcc: 901
+ mnc: 70
+ short_name: osmo-gsm-tester-msc
+ long_name: osmo-gsm-tester-msc
+ encryption: a5_0
+ authentication: optional
+
+bsc_bts:
+ base_station_id_code: 63
+ stream_id: 255
+ osmobsc_bts_type: sysmobts
+ channel_allocator: ascending
+ gprs_mode: gprs
+ num_trx: 1
+ max_trx: 1
+ trx_list:
+ - nominal_power: 23
+ max_power_red: 0
+ arfcn: 868
+ timeslot_list:
+ - phys_chan_config: CCCH+SDCCH4
+ - phys_chan_config: SDCCH8
+ - phys_chan_config: TCH/F
+ - phys_chan_config: TCH/F
+ - phys_chan_config: TCH/F
+ - phys_chan_config: TCH/F
+ - phys_chan_config: PDCH
+ - phys_chan_config: PDCH
+ - nominal_power: 23
+ max_power_red: 0
+ arfcn: 872
+ timeslot_list:
+ - phys_chan_config: TCH/F
+ - phys_chan_config: SDCCH8
+ - phys_chan_config: TCH/F
+ - phys_chan_config: TCH/F
+ - phys_chan_config: TCH/F
+ - phys_chan_config: TCH/F
+ - phys_chan_config: PDCH
+ - phys_chan_config: PDCH
+
+osmo_bts_trx:
+ max_trx: 2
+
+osmo_trx:
+ type: uhd
+ launch_trx: true
+ clock_reference: internal
+
+iperf3cli:
+ time: 60
diff --git a/doc/examples/2g_osmocom/paths.conf b/doc/examples/2g_osmocom/paths.conf
new file mode 100644
index 0000000..27c5818
--- /dev/null
+++ b/doc/examples/2g_osmocom/paths.conf
@@ -0,0 +1,3 @@
+state_dir: '/var/tmp/osmo-gsm-tester/state'
+suites_dir: './suites'
+scenarios_dir: './scenarios'
diff --git a/doc/examples/2g_osmocom/resources.conf b/doc/examples/2g_osmocom/resources.conf
new file mode 100644
index 0000000..087c445
--- /dev/null
+++ b/doc/examples/2g_osmocom/resources.conf
@@ -0,0 +1,40 @@
+# all hardware and interfaces available to this osmo-gsm-tester
+
+ip_address:
+- addr: 10.42.42.2
+- addr: 10.42.42.3
+- addr: 10.42.42.4
+- addr: 10.42.42.5
+- addr: 10.42.42.6
+- addr: 10.42.42.7
+
+bts:
+- label: Ettus B200
+ type: osmo-bts-trx
+ ipa_unit_id: 6
+ addr: 10.42.42.50
+ band: GSM-1800
+ ciphers: [a5_0, a5_1, a5_3]
+ osmo_trx:
+ type: uhd
+ launch_trx: true
+ remote_user: jenkins
+ trx_ip: 10.42.42.116
+ dev_args: "type=b200,serial=306BD11"
+ clock_reference: external
+ multi_arfcn: true
+
+modem:
+- label: sierra_1st
+ path: '/sys/devices/pci0000:00/0000:00:12.2/usb1/1-5/1-5.4/1-5.4.1/1-5.4.1.2'
+ ki: 'EBAB63D06C3F546A16C977CB40E57C68'
+ auth_algo: 'comp128v1'
+ ciphers: [a5_0, a5_1]
+ features: ['2g', 'sms', 'voice', 'ussd', 'sim']
+
+- label: ec20_1
+ path: '/sys/devices/pci0000:00/0000:00:12.2/usb1/1-5/1-5.4/1-5.4.1/1-5.4.1.6'
+ ki: '07F35D0A9476646169669401215580E0'
+ auth_algo: 'comp128v1'
+ ciphers: [a5_0, a5_1]
+ features: ['2g', 'sms', 'voice', 'ussd', 'gprs', 'sim']
diff --git a/doc/examples/2g_osmocom/scenarios/trx-b200.conf b/doc/examples/2g_osmocom/scenarios/trx-b200.conf
new file mode 100644
index 0000000..2bad7e8
--- /dev/null
+++ b/doc/examples/2g_osmocom/scenarios/trx-b200.conf
@@ -0,0 +1,4 @@
+resources:
+ bts:
+ - label: Ettus B200
+ type: osmo-bts-trx
diff --git a/doc/examples/2g_osmocom/suites/sms/mo_mt_sms.py b/doc/examples/2g_osmocom/suites/sms/mo_mt_sms.py
new file mode 100755
index 0000000..7654ea6
--- /dev/null
+++ b/doc/examples/2g_osmocom/suites/sms/mo_mt_sms.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.testenv import *
+
+hlr = suite.hlr()
+bts = suite.bts()
+mgw_msc = suite.mgw()
+mgw_bsc = suite.mgw()
+stp = suite.stp()
+msc = suite.msc(hlr, mgw_msc, stp)
+bsc = suite.bsc(msc, mgw_bsc, stp)
+ms_mo = suite.modem()
+ms_mt = suite.modem()
+
+hlr.start()
+stp.start()
+msc.start()
+mgw_msc.start()
+mgw_bsc.start()
+
+bsc.bts_add(bts)
+bsc.start()
+
+bts.start()
+wait(bsc.bts_is_connected, bts)
+
+hlr.subscriber_add(ms_mo)
+hlr.subscriber_add(ms_mt)
+
+ms_mo.connect(msc.mcc_mnc())
+ms_mt.connect(msc.mcc_mnc())
+
+ms_mo.log_info()
+ms_mt.log_info()
+
+print('waiting for modems to attach...')
+wait(ms_mo.is_connected, msc.mcc_mnc())
+wait(ms_mt.is_connected, msc.mcc_mnc())
+wait(msc.subscriber_attached, ms_mo, ms_mt)
+
+sms = ms_mo.sms_send(ms_mt)
+wait(ms_mt.sms_was_received, sms)
diff --git a/doc/examples/2g_osmocom/suites/sms/suite.conf b/doc/examples/2g_osmocom/suites/sms/suite.conf
new file mode 100644
index 0000000..28a81ea
--- /dev/null
+++ b/doc/examples/2g_osmocom/suites/sms/suite.conf
@@ -0,0 +1,9 @@
+resources:
+ ip_address:
+ - times: 6 # msc, bsc, hlr, stp, mgw*2
+ bts:
+ - times: 1
+ modem:
+ - times: 2
+ features:
+ - sms
diff --git a/doc/examples/4g_srsLTE/README.txt b/doc/examples/4g_srsLTE/README.txt
new file mode 100644
index 0000000..6840801
--- /dev/null
+++ b/doc/examples/4g_srsLTE/README.txt
@@ -0,0 +1,30 @@
+This a sample 4G test suite configured and ready to use srsLTE stack.
+The only thing missing is a trial dir containing binaries.
+
+You can point osmo-gsm-tester.py at this config using the OSMO_GSM_TESTER_CONF
+environment variable:
+
+ export OSMO_GSM_TESTER_CONF="$PWD"
+
+When there is no OSMO_GSM_TESTER_CONF set, osmo-gsm-tester will instead look
+for conf files in several locations like ~/.config/osmo-gsm-tester,
+/usr/local/etc/osmo-gsm-tester, /etc/osmo-gsm-tester.
+
+If you have your trial with binary tar archives in ~/my_trial
+you can run the suite for example like this:
+
+ osmo-gsm-tester.py ~/my_trial
+
+Specifically, from this dir:
+
+ OSMO_GSM_TESTER_CONF="$PWD" ../../src/osmo-gsm-tester.py ~/my_trial
+
+Alternatively you can setup this example as permanent config using something
+like:
+
+ mkdir -p ~/.config
+ ln -s "$PWD" ~/.config/osmo-gsm-tester
+
+A ./state dir will be created to store the current osmo-gsm-tester state. If
+you prefer not to write to $PWD, set up an own configuration pointing at a
+different path (see paths.conf: 'state_dir').
diff --git a/doc/examples/4g_srsLTE/default-suites.conf b/doc/examples/4g_srsLTE/default-suites.conf
new file mode 100644
index 0000000..136cb92
--- /dev/null
+++ b/doc/examples/4g_srsLTE/default-suites.conf
@@ -0,0 +1,2 @@
+- 4g:srsue-rftype@uhd+srsenb-rftype@uhd+mod-enb-nprb@6
+- 4g:srsue-rftype@zmq+srsenb-rftype@zmq+mod-enb-nprb@25
diff --git a/doc/examples/4g_srsLTE/defaults.conf b/doc/examples/4g_srsLTE/defaults.conf
new file mode 100644
index 0000000..4a3b4c4
--- /dev/null
+++ b/doc/examples/4g_srsLTE/defaults.conf
@@ -0,0 +1,40 @@
+epc:
+ type: srsepc
+ mcc: 901
+ mnc: 70
+ qci: 9
+
+srsepc:
+ enable_pcap: false
+
+enb:
+ mcc: 901
+ mnc: 70
+ transmission_mode: 1
+ num_cells: 1
+ enable_measurements: false
+ a1_report_type: rsrp
+ a1_report_value: -105
+ a1_hysteresis: 0
+ a1_time_to_trigger: 640
+ a2_report_type: rsrp
+ a2_report_value: -110
+ a2_hysteresis: 0
+ a2_time_to_trigger: 640
+ a3_report_type: rsrp
+ a3_report_value: 6
+ a3_hysteresis: 0
+ a3_time_to_trigger: 480
+
+srsenb:
+ num_prb: 100
+ enable_pcap: false
+
+srsue:
+ enable_pcap: false
+ airplane_t_on_ms: -1
+ airplane_t_off_ms: -1
+ num_carriers: 1
+
+iperf3cli:
+ time: 60
diff --git a/doc/examples/4g_srsLTE/paths.conf b/doc/examples/4g_srsLTE/paths.conf
new file mode 100644
index 0000000..27c5818
--- /dev/null
+++ b/doc/examples/4g_srsLTE/paths.conf
@@ -0,0 +1,3 @@
+state_dir: '/var/tmp/osmo-gsm-tester/state'
+suites_dir: './suites'
+scenarios_dir: './scenarios'
diff --git a/doc/examples/4g_srsLTE/resources.conf b/doc/examples/4g_srsLTE/resources.conf
new file mode 100644
index 0000000..a1bdcbc
--- /dev/null
+++ b/doc/examples/4g_srsLTE/resources.conf
@@ -0,0 +1,44 @@
+# all hardware and interfaces available to this osmo-gsm-tester
+
+# Used to run srsEPC on it:
+run_node:
+- run_type: ssh
+ run_addr: 172.18.50.100
+ ssh_user: jenkins
+ ssh_addr: 172.18.50.100
+
+enb:
+- label: srsENB-zmq
+ type: srsenb
+ rf_dev_type: zmq
+ remote_user: jenkins
+ addr: 172.18.50.101
+
+- label: srsENB-B200
+ type: srsenb
+ rf_dev_type: uhd
+ rf_dev_args: 'type=b200,serial=317B9FE'
+ remote_user: jenkins
+ addr: 172.18.50.102
+
+modem:
+- label: srsUE-zmq
+ type: srsue
+ rf_dev_type: zmq
+ remote_user: jenkins
+ addr: 172.18.50.100
+ imsi: '001010123456789'
+ ki: '00112233445566778899aabbccddeeff'
+ auth_algo: 'xor'
+ features: ['4g']
+
+- label: srsUE-B200
+ type: srsue
+ rf_dev_type: uhd
+ rf_dev_args: 'type=b200,serial=3128FF1'
+ remote_user: jenkins
+ addr: 10.12.1.195
+ imsi: '001010123456789'
+ ki: '00112233445566778899aabbccddeeff'
+ auth_algo: 'xor'
+ features: ['4g']
diff --git a/doc/examples/4g_srsLTE/scenarios/cfg-epc-qci@.conf b/doc/examples/4g_srsLTE/scenarios/cfg-epc-qci@.conf
new file mode 100644
index 0000000..8f9c937
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/cfg-epc-qci@.conf
@@ -0,0 +1,3 @@
+config:
+ epc:
+ qci: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/cfg-epc-type@.conf b/doc/examples/4g_srsLTE/scenarios/cfg-epc-type@.conf
new file mode 100644
index 0000000..89b7fba
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/cfg-epc-type@.conf
@@ -0,0 +1,3 @@
+config:
+ epc:
+ type: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/cfg-iperf3-time@.conf b/doc/examples/4g_srsLTE/scenarios/cfg-iperf3-time@.conf
new file mode 100644
index 0000000..f46c59a
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/cfg-iperf3-time@.conf
@@ -0,0 +1,3 @@
+config:
+ iperf3cli:
+ time: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/cfg-srs-enable-pcap.conf b/doc/examples/4g_srsLTE/scenarios/cfg-srs-enable-pcap.conf
new file mode 100644
index 0000000..6927b80
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/cfg-srs-enable-pcap.conf
@@ -0,0 +1,7 @@
+config:
+ epc:
+ enable_pcap: true
+ enb:
+ enable_pcap: true
+ modem:
+ enable_pcap: true
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-enb-args@.conf b/doc/examples/4g_srsLTE/scenarios/mod-enb-args@.conf
new file mode 100644
index 0000000..a758d01
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-enb-args@.conf
@@ -0,0 +1,3 @@
+modifiers:
+ enb:
+ - additional_args: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-enb-meas-event@.conf b/doc/examples/4g_srsLTE/scenarios/mod-enb-meas-event@.conf
new file mode 100644
index 0000000..44f4fcd
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-enb-meas-event@.conf
@@ -0,0 +1,7 @@
+modifiers:
+ enb:
+ - enable_measurements: true
+ ${param1}_report_type: ${param2}
+ ${param1}_report_value: ${param3}
+ ${param1}_hysteresis: ${param4}
+ ${param1}_time_to_trigger: ${param5}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-enb-ncells@.conf b/doc/examples/4g_srsLTE/scenarios/mod-enb-ncells@.conf
new file mode 100644
index 0000000..b57b94a
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-enb-ncells@.conf
@@ -0,0 +1,3 @@
+modifiers:
+ enb:
+ - num_cells: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-enb-nprb@.conf b/doc/examples/4g_srsLTE/scenarios/mod-enb-nprb@.conf
new file mode 100644
index 0000000..f17347c
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-enb-nprb@.conf
@@ -0,0 +1,3 @@
+modifiers:
+ enb:
+ - num_prb: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-enb-txmode@.conf b/doc/examples/4g_srsLTE/scenarios/mod-enb-txmode@.conf
new file mode 100644
index 0000000..e0c8d01
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-enb-txmode@.conf
@@ -0,0 +1,3 @@
+modifiers:
+ enb:
+ - transmission_mode: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-modem-args@.conf b/doc/examples/4g_srsLTE/scenarios/mod-modem-args@.conf
new file mode 100644
index 0000000..dde7796
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-modem-args@.conf
@@ -0,0 +1,3 @@
+modifiers:
+ modem:
+ - additional_args: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-srsue-airplane_mode_sim@.conf b/doc/examples/4g_srsLTE/scenarios/mod-srsue-airplane_mode_sim@.conf
new file mode 100644
index 0000000..c05fba1
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-srsue-airplane_mode_sim@.conf
@@ -0,0 +1,4 @@
+modifiers:
+ modem:
+ - airplane_t_on_ms: ${param1}
+ airplane_t_off_ms: ${param2}
diff --git a/doc/examples/4g_srsLTE/scenarios/mod-srsue-ncarriers@.conf b/doc/examples/4g_srsLTE/scenarios/mod-srsue-ncarriers@.conf
new file mode 100644
index 0000000..bb6409a
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/mod-srsue-ncarriers@.conf
@@ -0,0 +1,3 @@
+modifiers:
+ modem:
+ - num_carriers: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/srsenb-rftype@.conf b/doc/examples/4g_srsLTE/scenarios/srsenb-rftype@.conf
new file mode 100644
index 0000000..bf64b19
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/srsenb-rftype@.conf
@@ -0,0 +1,4 @@
+resources:
+ enb:
+ - type: srsenb
+ rf_dev_type: ${param1}
diff --git a/doc/examples/4g_srsLTE/scenarios/srsue-rftype@.conf b/doc/examples/4g_srsLTE/scenarios/srsue-rftype@.conf
new file mode 100644
index 0000000..85a0609
--- /dev/null
+++ b/doc/examples/4g_srsLTE/scenarios/srsue-rftype@.conf
@@ -0,0 +1,4 @@
+resources:
+ modem:
+ - type: srsue
+ rf_dev_type: ${param1}
diff --git a/doc/examples/4g_srsLTE/suites/4g/iperf3_dl.py b/doc/examples/4g_srsLTE/suites/4g/iperf3_dl.py
new file mode 100755
index 0000000..88ae82d
--- /dev/null
+++ b/doc/examples/4g_srsLTE/suites/4g/iperf3_dl.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.testenv import *
+
+def print_result_node(result, node_str):
+ sent = result['end']['sum_sent']
+ recv = result['end']['sum_received']
+ print("Result %s:" % node_str)
+ print("\tSEND: %d KB, %d kbps, %d seconds (%s retrans)" % (sent['bytes']/1000, sent['bits_per_second']/1000, sent['seconds'], str(sent.get('retransmits', 'unknown'))))
+ print("\tRECV: %d KB, %d kbps, %d seconds" % (recv['bytes']/1000, recv['bits_per_second']/1000, recv['seconds']))
+
+def print_results(cli_res, srv_res):
+ print_result_node(cli_res, 'client')
+ print_result_node(srv_res, 'server')
+
+epc = suite.epc()
+enb = suite.enb()
+ue = suite.modem()
+iperf3srv = suite.iperf3srv({'addr': epc.tun_addr()})
+iperf3srv.set_run_node(epc.run_node())
+iperf3cli = iperf3srv.create_client()
+iperf3cli.set_run_node(ue.run_node())
+
+epc.subscriber_add(ue)
+epc.start()
+enb.ue_add(ue)
+enb.start(epc)
+
+print('waiting for ENB to connect to EPC...')
+wait(epc.enb_is_connected, enb)
+print('ENB is connected to EPC')
+
+ue.connect(enb)
+
+iperf3srv.start()
+proc = iperf3cli.prepare_test_proc(True, ue.netns())
+
+print('waiting for UE to attach...')
+wait(ue.is_connected, None)
+print('UE is attached')
+
+print("Running iperf3 client to %s through %s" % (str(iperf3cli), ue.netns()))
+proc.launch_sync()
+iperf3srv.stop()
+print_results(iperf3cli.get_results(), iperf3srv.get_results())
+
+max_rate = enb.ue_max_rate(downlink=True)
+res_str = ue.verify_metric(max_rate * 0.8, operation='avg', metric='dl_brate', criterion='gt')
+print(res_str)
+test.set_report_stdout(res_str)
diff --git a/doc/examples/4g_srsLTE/suites/4g/iperf3_ul.py b/doc/examples/4g_srsLTE/suites/4g/iperf3_ul.py
new file mode 100755
index 0000000..597b50d
--- /dev/null
+++ b/doc/examples/4g_srsLTE/suites/4g/iperf3_ul.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.testenv import *
+
+def print_result_node(result, node_str):
+ sent = result['end']['sum_sent']
+ recv = result['end']['sum_received']
+ print("Result %s:" % node_str)
+ print("\tSEND: %d KB, %d kbps, %d seconds (%s retrans)" % (sent['bytes']/1000, sent['bits_per_second']/1000, sent['seconds'], str(sent.get('retransmits', 'unknown'))))
+ print("\tRECV: %d KB, %d kbps, %d seconds" % (recv['bytes']/1000, recv['bits_per_second']/1000, recv['seconds']))
+
+def print_results(cli_res, srv_res):
+ print_result_node(cli_res, 'client')
+ print_result_node(srv_res, 'server')
+
+epc = suite.epc()
+enb = suite.enb()
+ue = suite.modem()
+iperf3srv = suite.iperf3srv({'addr': epc.tun_addr()})
+iperf3srv.set_run_node(epc.run_node())
+iperf3cli = iperf3srv.create_client()
+iperf3cli.set_run_node(ue.run_node())
+
+epc.subscriber_add(ue)
+epc.start()
+enb.ue_add(ue)
+enb.start(epc)
+
+print('waiting for ENB to connect to EPC...')
+wait(epc.enb_is_connected, enb)
+print('ENB is connected to EPC')
+
+ue.connect(enb)
+
+iperf3srv.start()
+proc = iperf3cli.prepare_test_proc(False, ue.netns())
+
+print('waiting for UE to attach...')
+wait(ue.is_connected, None)
+print('UE is attached')
+
+print("Running iperf3 client to %s through %s" % (str(iperf3cli), ue.netns()))
+proc.launch_sync()
+iperf3srv.stop()
+print_results(iperf3cli.get_results(), iperf3srv.get_results())
+
+max_rate = enb.ue_max_rate(downlink=False)
+res_str = ue.verify_metric(max_rate * 0.8, operation='avg', metric='ul_brate', criterion='gt')
+print(res_str)
+test.set_report_stdout(res_str)
diff --git a/doc/examples/4g_srsLTE/suites/4g/ping.py b/doc/examples/4g_srsLTE/suites/4g/ping.py
new file mode 100755
index 0000000..17eee78
--- /dev/null
+++ b/doc/examples/4g_srsLTE/suites/4g/ping.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.testenv import *
+
+epc = suite.epc()
+enb = suite.enb()
+ue = suite.modem()
+
+epc.subscriber_add(ue)
+epc.start()
+enb.ue_add(ue)
+enb.start(epc)
+
+print('waiting for ENB to connect to EPC...')
+wait(epc.enb_is_connected, enb)
+print('ENB is connected to EPC')
+
+ue.connect(enb)
+print('waiting for UE to attach...')
+wait(ue.is_connected, None)
+print('UE is attached')
+
+proc = ue.run_netns_wait('ping', ('ping', '-c', '10', epc.tun_addr()))
+output = proc.get_stdout()
+print(output)
+test.set_report_stdout(output)
diff --git a/doc/examples/4g_srsLTE/suites/4g/suite.conf b/doc/examples/4g_srsLTE/suites/4g/suite.conf
new file mode 100644
index 0000000..e439e99
--- /dev/null
+++ b/doc/examples/4g_srsLTE/suites/4g/suite.conf
@@ -0,0 +1,12 @@
+resources:
+ run_node: # for EPC
+ - times: 1
+ enb:
+ - times: 1
+ modem:
+ - times: 1
+ features:
+ - 4g
+
+defaults:
+ timeout: 180s