blob: 7a75a4d368eaa140acab1d108fd489dc5b141bfc [file] [log] [blame]
Harald Welte57e5b942012-09-07 10:23:44 +02001/* test routines for BSSGP flow control implementation in libosmogb
2 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <stdint.h>
8#include <string.h>
9#include <getopt.h>
Holger Hans Peter Freyther5b6416a2013-09-16 14:13:25 +020010#include <unistd.h>
Harald Welte57e5b942012-09-07 10:23:44 +020011
Holger Hans Peter Freytherc302eca2012-09-11 11:49:35 +020012#include <osmocom/core/application.h>
Harald Welte57e5b942012-09-07 10:23:44 +020013#include <osmocom/core/utils.h>
14#include <osmocom/core/logging.h>
15#include <osmocom/core/talloc.h>
16#include <osmocom/gprs/gprs_bssgp.h>
17
18static unsigned long in_ctr = 1;
19static struct timeval tv_start;
20
21int get_centisec_diff(void)
22{
23 struct timeval tv;
24 struct timeval now;
Neels Hofmeyr8e2f7e82016-09-22 03:58:13 +020025 osmo_gettimeofday(&now, NULL);
Harald Welte57e5b942012-09-07 10:23:44 +020026
27 timersub(&now, &tv_start, &tv);
28
29 return tv.tv_sec * 100 + tv.tv_usec/10000;
30}
31
Harald Welte57e5b942012-09-07 10:23:44 +020032static int fc_out_cb(struct bssgp_flow_control *fc, struct msgb *msg,
33 uint32_t llc_pdu_len, void *priv)
34{
35 unsigned int csecs = get_centisec_diff();
Harald Welte57e5b942012-09-07 10:23:44 +020036
Holger Hans Peter Freyther10dd73c2014-10-10 17:24:34 +020037 printf("%u: FC OUT Nr %lu\n", csecs, (unsigned long) msg->cb[0]);
38 msgb_free(msg);
Holger Hans Peter Freyther5b6416a2013-09-16 14:13:25 +020039 return 0;
Harald Welte57e5b942012-09-07 10:23:44 +020040}
41
Neels Hofmeyr9541a682017-11-16 22:55:02 +010042static void fc_in(struct bssgp_flow_control *fc, unsigned int pdu_len)
Harald Welte57e5b942012-09-07 10:23:44 +020043{
Holger Hans Peter Freyther10dd73c2014-10-10 17:24:34 +020044 struct msgb *msg;
Harald Welte57e5b942012-09-07 10:23:44 +020045 unsigned int csecs = get_centisec_diff();
Neels Hofmeyr9541a682017-11-16 22:55:02 +010046 int rc;
Harald Welte57e5b942012-09-07 10:23:44 +020047
Holger Hans Peter Freyther10dd73c2014-10-10 17:24:34 +020048 msg = msgb_alloc(1, "fc test");
49 msg->cb[0] = in_ctr++;
50
51 printf("%u: FC IN Nr %lu\n", csecs, msg->cb[0]);
Neels Hofmeyr9541a682017-11-16 22:55:02 +010052 rc = bssgp_fc_in(fc, msg, pdu_len, NULL);
53 switch (rc) {
54 case 0:
55 printf(" -> %d: ok\n", rc);
56 break;
57 case -ENOSPC:
58 printf(" -> %d: queue full, msg dropped.\n", rc);
59 break;
60 case -EIO:
61 printf(" -> %d: PDU too large, msg dropped.\n", rc);
62 break;
63 default:
64 printf(" -> %d: error, msg dropped.\n", rc);
65 break;
66 }
Harald Welte57e5b942012-09-07 10:23:44 +020067}
68
69
70static void test_fc(uint32_t bucket_size_max, uint32_t bucket_leak_rate,
71 uint32_t max_queue_depth, uint32_t pdu_len,
72 uint32_t pdu_count)
73{
74 struct bssgp_flow_control *fc = talloc_zero(NULL, struct bssgp_flow_control);
75 int i;
76
Neels Hofmeyr71320112017-02-06 14:39:53 +010077 osmo_gettimeofday_override_time = (struct timeval){
78 .tv_sec = 1486385000,
79 .tv_usec = 423423,
80 };
81 osmo_gettimeofday_override = true;
82
Harald Welte57e5b942012-09-07 10:23:44 +020083 bssgp_fc_init(fc, bucket_size_max, bucket_leak_rate, max_queue_depth,
84 fc_out_cb);
85
Neels Hofmeyr8e2f7e82016-09-22 03:58:13 +020086 osmo_gettimeofday(&tv_start, NULL);
Harald Welte57e5b942012-09-07 10:23:44 +020087
Neels Hofmeyr9541a682017-11-16 22:55:02 +010088 /* Fill the queue with PDUs, possibly beyond the queue being full. If it is full, additional PDUs
89 * are discarded. */
Harald Welte57e5b942012-09-07 10:23:44 +020090 for (i = 0; i < pdu_count; i++) {
91 fc_in(fc, pdu_len);
92 osmo_timers_check();
93 osmo_timers_prepare();
94 osmo_timers_update();
95 }
96
97 while (1) {
Neels Hofmeyr71320112017-02-06 14:39:53 +010098 osmo_gettimeofday_override_add(0, 100000);
99
Harald Welte57e5b942012-09-07 10:23:44 +0200100 osmo_timers_check();
101 osmo_timers_prepare();
102 osmo_timers_update();
103
104 if (llist_empty(&fc->queue))
105 break;
106 }
107}
108
109static void help(void)
110{
111 printf(" -h --help This help message\n");
112 printf(" -s --bucket-size-max N Maximum size of bucket in octets\n");
113 printf(" -r --bucket-leak-rate N Bucket leak rate in octets/sec\n");
114 printf(" -d --max-queue-depth N Maximum length of pending PDU queue (msgs)\n");
115 printf(" -l --pdu-length N Length of each PDU in octets\n");
116}
117
118int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
119{
120 return -1;
121}
122
123static struct log_info info = {};
124
125int main(int argc, char **argv)
126{
127 uint32_t bucket_size_max = 100; /* octets */
128 uint32_t bucket_leak_rate = 100; /* octets / second */
129 uint32_t max_queue_depth = 5; /* messages */
130 uint32_t pdu_length = 10; /* octets */
131 uint32_t pdu_count = 20; /* messages */
132 int c;
Neels Hofmeyr0128c782017-11-16 22:32:36 +0100133 void *tall_msgb_ctx;
Harald Welte57e5b942012-09-07 10:23:44 +0200134
135 static const struct option long_options[] = {
136 { "bucket-size-max", 1, 0, 's' },
137 { "bucket-leak-rate", 1, 0, 'r' },
138 { "max-queue-depth", 1, 0, 'd' },
139 { "pdu-length", 1, 0, 'l' },
140 { "pdu-count", 1, 0, 'c' },
141 { "help", 0, 0, 'h' },
142 { 0, 0, 0, 0 }
143 };
144
145 osmo_init_logging(&info);
Holger Hans Peter Freytherc302eca2012-09-11 11:49:35 +0200146 log_set_use_color(osmo_stderr_target, 0);
147 log_set_print_filename(osmo_stderr_target, 0);
Harald Welte57e5b942012-09-07 10:23:44 +0200148
Neels Hofmeyr0128c782017-11-16 22:32:36 +0100149 tall_msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
150
Harald Welte57e5b942012-09-07 10:23:44 +0200151 while ((c = getopt_long(argc, argv, "s:r:d:l:c:",
152 long_options, NULL)) != -1) {
153 switch (c) {
154 case 's':
155 bucket_size_max = atoi(optarg);
156 break;
157 case 'r':
158 bucket_leak_rate = atoi(optarg);
159 break;
160 case 'd':
161 max_queue_depth = atoi(optarg);
162 break;
163 case 'l':
164 pdu_length = atoi(optarg);
165 break;
166 case 'c':
167 pdu_count = atoi(optarg);
168 break;
169 case 'h':
170 help();
171 exit(EXIT_SUCCESS);
172 break;
173 default:
174 exit(EXIT_FAILURE);
175 }
176 }
177
178 /* bucket leak rate less than 100 not supported! */
179 if (bucket_leak_rate < 100) {
180 fprintf(stderr, "Bucket leak rate < 100 not supported!\n");
181 exit(EXIT_FAILURE);
182 }
183
184 printf("===== BSSGP flow-control test START\n");
185 printf("size-max=%u oct, leak-rate=%u oct/s, "
186 "queue-len=%u msgs, pdu_len=%u oct, pdu_cnt=%u\n\n", bucket_size_max,
187 bucket_leak_rate, max_queue_depth, pdu_length, pdu_count);
188 test_fc(bucket_size_max, bucket_leak_rate, max_queue_depth,
189 pdu_length, pdu_count);
Neels Hofmeyr0128c782017-11-16 22:32:36 +0100190 printf("msgb ctx: %zu b in %zu blocks (0 b in 1 block == just the context)\n",
191 talloc_total_size(tall_msgb_ctx),
192 talloc_total_blocks(tall_msgb_ctx));
193 /* KNOWN BUG: expecting 0b in 1 block, but a full queue is still a mem leak */
194 talloc_free(tall_msgb_ctx);
Harald Welte57e5b942012-09-07 10:23:44 +0200195 printf("===== BSSGP flow-control test END\n\n");
196
197 exit(EXIT_SUCCESS);
198}