Coverage Report

Created: 2023-09-25 07:12

/src/open5gs/lib/core/ogs-pkbuf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-core.h"
21
22
#undef OGS_LOG_DOMAIN
23
0
#define OGS_LOG_DOMAIN __ogs_mem_domain
24
25
#if OGS_USE_TALLOC == 0
26
#define OGS_CLUSTER_128_SIZE    128
27
#define OGS_CLUSTER_256_SIZE    256
28
#define OGS_CLUSTER_512_SIZE    512
29
#define OGS_CLUSTER_1024_SIZE   1024
30
#define OGS_CLUSTER_2048_SIZE   2048
31
#define OGS_CLUSTER_8192_SIZE   8192
32
#define OGS_CLUSTER_32768_SIZE  32768
33
34
/*
35
 *
36
 * In lib/core/ogs-kqueue.c:69
37
 *   context->change_list = ogs_calloc(
38
 *       pollset->capacity, sizeof(struct kevent));
39
 *   1. pollset->capacity : 1024*16
40
 *   2. sizeof(struct kevent) : 64
41
 *   3. sizeof(ogs_pkbuf_t *) is headroom in ogs_calloc()
42
 *
43
 * So, we use BIG_SIZE : 1024*(16*64=1024)*64+8
44
 */
45
#define OGS_CLUSTER_BIG_SIZE    (1024*1024+sizeof(ogs_pkbuf_t *))
46
47
typedef uint8_t ogs_cluster_128_t[OGS_CLUSTER_128_SIZE];
48
typedef uint8_t ogs_cluster_256_t[OGS_CLUSTER_256_SIZE];
49
typedef uint8_t ogs_cluster_512_t[OGS_CLUSTER_512_SIZE];
50
typedef uint8_t ogs_cluster_1024_t[OGS_CLUSTER_1024_SIZE];
51
typedef uint8_t ogs_cluster_2048_t[OGS_CLUSTER_2048_SIZE];
52
typedef uint8_t ogs_cluster_8192_t[OGS_CLUSTER_8192_SIZE];
53
typedef uint8_t ogs_cluster_32768_t[OGS_CLUSTER_32768_SIZE];
54
typedef uint8_t ogs_cluster_big_t[OGS_CLUSTER_BIG_SIZE];
55
56
OGS_STATIC_ASSERT(sizeof(ogs_cluster_128_t) % sizeof(void *) == 0);
57
OGS_STATIC_ASSERT(sizeof(ogs_cluster_256_t) % sizeof(void *) == 0);
58
OGS_STATIC_ASSERT(sizeof(ogs_cluster_512_t) % sizeof(void *) == 0);
59
OGS_STATIC_ASSERT(sizeof(ogs_cluster_1024_t) % sizeof(void *) == 0);
60
OGS_STATIC_ASSERT(sizeof(ogs_cluster_2048_t) % sizeof(void *) == 0);
61
OGS_STATIC_ASSERT(sizeof(ogs_cluster_8192_t) % sizeof(void *) == 0);
62
OGS_STATIC_ASSERT(sizeof(ogs_cluster_32768_t) % sizeof(void *) == 0);
63
OGS_STATIC_ASSERT(sizeof(ogs_cluster_big_t) % sizeof(void *) == 0);
64
65
typedef struct ogs_pkbuf_pool_s {
66
    OGS_POOL(pkbuf, ogs_pkbuf_t);
67
    OGS_POOL(cluster, ogs_cluster_t);
68
69
    OGS_POOL(cluster_128, ogs_cluster_128_t);
70
    OGS_POOL(cluster_256, ogs_cluster_256_t);
71
    OGS_POOL(cluster_512, ogs_cluster_512_t);
72
    OGS_POOL(cluster_1024, ogs_cluster_1024_t);
73
    OGS_POOL(cluster_2048, ogs_cluster_2048_t);
74
    OGS_POOL(cluster_8192, ogs_cluster_8192_t);
75
    OGS_POOL(cluster_32768, ogs_cluster_32768_t);
76
    OGS_POOL(cluster_big, ogs_cluster_big_t);
77
78
    ogs_thread_mutex_t mutex;
79
} ogs_pkbuf_pool_t;
80
81
static OGS_POOL(pkbuf_pool, ogs_pkbuf_pool_t);
82
static ogs_pkbuf_pool_t *default_pool = NULL;
83
84
static ogs_cluster_t *cluster_alloc(
85
        ogs_pkbuf_pool_t *pool, unsigned int size);
86
static void cluster_free(ogs_pkbuf_pool_t *pool, ogs_cluster_t *cluster);
87
#endif
88
89
void *ogs_pkbuf_put_data(
90
        ogs_pkbuf_t *pkbuf, const void *data, unsigned int len)
91
468
{
92
468
    void *tmp = ogs_pkbuf_put(pkbuf, len);
93
94
468
    memcpy(tmp, data, len);
95
468
    return tmp;
96
468
}
97
98
void ogs_pkbuf_init(void)
99
1
{
100
#if OGS_USE_TALLOC == 0
101
    ogs_pool_init(&pkbuf_pool, ogs_core()->pkbuf.pool);
102
103
#endif
104
1
}
105
106
void ogs_pkbuf_final(void)
107
0
{
108
#if OGS_USE_TALLOC == 0
109
    ogs_pool_final(&pkbuf_pool);
110
#endif
111
0
}
112
113
void ogs_pkbuf_default_init(ogs_pkbuf_config_t *config)
114
1
{
115
#if OGS_USE_TALLOC == 0
116
    ogs_assert(config);
117
    memset(config, 0, sizeof *config);
118
119
    config->cluster_128_pool = 65536;
120
    config->cluster_256_pool = 16384;
121
    config->cluster_512_pool = 4096;
122
    config->cluster_1024_pool = 2048;
123
    config->cluster_2048_pool = 1024;
124
    config->cluster_8192_pool = 256;
125
    config->cluster_32768_pool = 64;
126
    config->cluster_big_pool = 8;
127
#endif
128
1
}
129
130
void ogs_pkbuf_default_create(ogs_pkbuf_config_t *config)
131
1
{
132
#if OGS_USE_TALLOC == 0
133
    default_pool = ogs_pkbuf_pool_create(config);
134
#endif
135
1
}
136
137
void ogs_pkbuf_default_destroy(void)
138
0
{
139
#if OGS_USE_TALLOC == 0
140
    ogs_pkbuf_pool_destroy(default_pool);
141
#endif
142
0
}
143
144
ogs_pkbuf_pool_t *ogs_pkbuf_pool_create(ogs_pkbuf_config_t *config)
145
0
{
146
0
    ogs_pkbuf_pool_t *pool = NULL;
147
#if OGS_USE_TALLOC == 0
148
    int tmp = 0;
149
150
    ogs_assert(config);
151
152
    ogs_pool_alloc(&pkbuf_pool, &pool);
153
    ogs_assert(pool);
154
    memset(pool, 0, sizeof *pool);
155
156
    ogs_thread_mutex_init(&pool->mutex);
157
158
    tmp = config->cluster_128_pool + config->cluster_256_pool +
159
        config->cluster_512_pool + config->cluster_1024_pool +
160
        config->cluster_2048_pool + config->cluster_8192_pool +
161
        config->cluster_32768_pool + config->cluster_big_pool;
162
163
    ogs_pool_init(&pool->pkbuf, tmp);
164
    ogs_pool_init(&pool->cluster, tmp);
165
166
    ogs_pool_init(&pool->cluster_128, config->cluster_128_pool);
167
    ogs_pool_init(&pool->cluster_256, config->cluster_256_pool);
168
    ogs_pool_init(&pool->cluster_512, config->cluster_512_pool);
169
    ogs_pool_init(&pool->cluster_1024, config->cluster_1024_pool);
170
    ogs_pool_init(&pool->cluster_2048, config->cluster_2048_pool);
171
    ogs_pool_init(&pool->cluster_8192, config->cluster_8192_pool);
172
    ogs_pool_init(&pool->cluster_32768, config->cluster_32768_pool);
173
    ogs_pool_init(&pool->cluster_big, config->cluster_big_pool);
174
#endif
175
176
0
    return pool;
177
0
}
178
179
#define ogs_pkbuf_pool_final(pool) do { \
180
    if (((pool)->size != (pool)->avail)) { \
181
        int i; \
182
        ogs_error("%d in '%s[%d]' were not released.", \
183
                (pool)->size - (pool)->avail, (pool)->name, (pool)->size); \
184
        for (i = 0; i < (pool)->size; i++) { \
185
            ogs_pkbuf_t *pkbuf = (pool)->index[i]; \
186
            if (pkbuf) { \
187
                ogs_log_print(OGS_LOG_ERROR, "SIZE[%d] is not freed. (%s)\n", \
188
                        pkbuf->len, pkbuf->file_line); \
189
            } \
190
        } \
191
    } \
192
    free((pool)->free); \
193
    free((pool)->array); \
194
    free((pool)->index); \
195
} while (0)
196
197
void ogs_pkbuf_pool_destroy(ogs_pkbuf_pool_t *pool)
198
0
{
199
#if OGS_USE_TALLOC == 0
200
    ogs_assert(pool);
201
202
    ogs_pkbuf_pool_final(&pool->pkbuf);
203
    ogs_pool_final(&pool->cluster);
204
205
    ogs_pool_final(&pool->cluster_128);
206
    ogs_pool_final(&pool->cluster_256);
207
    ogs_pool_final(&pool->cluster_512);
208
    ogs_pool_final(&pool->cluster_1024);
209
    ogs_pool_final(&pool->cluster_2048);
210
    ogs_pool_final(&pool->cluster_8192);
211
    ogs_pool_final(&pool->cluster_32768);
212
    ogs_pool_final(&pool->cluster_big);
213
214
    ogs_thread_mutex_destroy(&pool->mutex);
215
216
    ogs_pool_free(&pkbuf_pool, pool);
217
#endif
218
0
}
219
220
ogs_pkbuf_t *ogs_pkbuf_alloc_debug(
221
        ogs_pkbuf_pool_t *pool, unsigned int size, const char *file_line)
222
468
{
223
468
#if OGS_USE_TALLOC == 1
224
468
    ogs_pkbuf_t *pkbuf = NULL;
225
226
468
    pkbuf = ogs_talloc_zero_size(pool, sizeof(*pkbuf) + size, file_line);
227
468
    if (!pkbuf) {
228
0
        ogs_error("ogs_pkbuf_alloc() failed [size=%d]", size);
229
0
        return NULL;
230
0
    }
231
232
468
    pkbuf->head = pkbuf->_data;
233
468
    pkbuf->end = pkbuf->_data + size;
234
235
468
    pkbuf->len = 0;
236
237
468
    pkbuf->data = pkbuf->_data;
238
468
    pkbuf->tail = pkbuf->_data;
239
240
468
    pkbuf->file_line = file_line; /* For debug */
241
242
468
    return pkbuf;
243
#else
244
    ogs_pkbuf_t *pkbuf = NULL;
245
    ogs_cluster_t *cluster = NULL;
246
247
    if (pool == NULL)
248
        pool = default_pool;
249
    ogs_assert(pool);
250
251
    ogs_thread_mutex_lock(&pool->mutex);
252
253
    cluster = cluster_alloc(pool, size);
254
    if (!cluster) {
255
        ogs_error("ogs_pkbuf_alloc() failed [size=%d]", size);
256
        ogs_thread_mutex_unlock(&pool->mutex);
257
        return NULL;
258
    }
259
260
    ogs_pool_alloc(&pool->pkbuf, &pkbuf);
261
    if (!pkbuf) {
262
        ogs_error("ogs_pkbuf_alloc() failed [size=%d]", size);
263
        ogs_thread_mutex_unlock(&pool->mutex);
264
        return NULL;
265
    }
266
    memset(pkbuf, 0, sizeof(*pkbuf));
267
268
    OGS_OBJECT_REF(cluster);
269
270
    pkbuf->cluster = cluster;
271
272
    pkbuf->len = 0;
273
274
    pkbuf->data = cluster->buffer;
275
    pkbuf->head = cluster->buffer;
276
    pkbuf->tail = cluster->buffer;
277
    pkbuf->end = cluster->buffer + size;
278
279
    pkbuf->file_line = file_line; /* For debug */
280
281
    pkbuf->pool = pool;
282
283
    ogs_thread_mutex_unlock(&pool->mutex);
284
285
    return pkbuf;
286
#endif
287
468
}
288
289
void ogs_pkbuf_free(ogs_pkbuf_t *pkbuf)
290
468
{
291
468
#if OGS_USE_TALLOC == 1
292
468
    ogs_talloc_free(pkbuf, OGS_FILE_LINE);
293
#else
294
    ogs_pkbuf_pool_t *pool = NULL;
295
    ogs_cluster_t *cluster = NULL;
296
    ogs_assert(pkbuf);
297
298
    pool = pkbuf->pool;
299
    ogs_assert(pool);
300
301
    ogs_thread_mutex_lock(&pool->mutex);
302
303
    cluster = pkbuf->cluster;
304
    ogs_assert(cluster);
305
306
    if (OGS_OBJECT_IS_REF(cluster))
307
        OGS_OBJECT_UNREF(cluster);
308
    else
309
        cluster_free(pool, pkbuf->cluster);
310
311
    ogs_pool_free(&pool->pkbuf, pkbuf);
312
313
    ogs_thread_mutex_unlock(&pool->mutex);
314
#endif
315
468
}
316
317
ogs_pkbuf_t *ogs_pkbuf_copy_debug(ogs_pkbuf_t *pkbuf, const char *file_line)
318
0
{
319
0
#if OGS_USE_TALLOC == 1
320
0
    ogs_pkbuf_t *newbuf;
321
#else
322
    ogs_pkbuf_pool_t *pool = NULL;
323
    ogs_pkbuf_t *newbuf = NULL;
324
#endif
325
0
    int size = 0;
326
327
0
    ogs_assert(pkbuf);
328
0
    size = pkbuf->end - pkbuf->head;
329
0
    if (size <= 0) {
330
0
        ogs_error("Invalid argument[size=%d, head=%p, end=%p] in (%s)",
331
0
                size, pkbuf->head, pkbuf->end, file_line);
332
0
        return NULL;
333
0
    }
334
335
0
#if OGS_USE_TALLOC == 1
336
0
    newbuf = ogs_pkbuf_alloc_debug(NULL, size, file_line);
337
0
    if (!newbuf) {
338
0
        ogs_error("ogs_pkbuf_alloc() failed [size=%d]", size);
339
0
        return NULL;
340
0
    }
341
342
    /* copy data */
343
0
    memcpy(newbuf->_data, pkbuf->_data, size);
344
345
    /* copy header */
346
0
    newbuf->len = pkbuf->len;
347
348
0
    newbuf->tail += pkbuf->tail - pkbuf->_data;
349
0
    newbuf->data += pkbuf->data - pkbuf->_data;
350
351
0
    return newbuf;
352
#else
353
    pool = pkbuf->pool;
354
    ogs_assert(pool);
355
356
    ogs_thread_mutex_lock(&pool->mutex);
357
358
    ogs_pool_alloc(&pool->pkbuf, &newbuf);
359
    if (!newbuf) {
360
        ogs_error("ogs_pkbuf_copy() failed [size=%d]", size);
361
        ogs_thread_mutex_unlock(&pool->mutex);
362
        return NULL;
363
    }
364
    ogs_assert(newbuf);
365
    memcpy(newbuf, pkbuf, sizeof *pkbuf);
366
367
    OGS_OBJECT_REF(newbuf->cluster);
368
369
    ogs_thread_mutex_unlock(&pool->mutex);
370
#endif
371
372
0
    return newbuf;
373
0
}
374
375
#if OGS_USE_TALLOC == 0
376
static ogs_cluster_t *cluster_alloc(
377
        ogs_pkbuf_pool_t *pool, unsigned int size)
378
{
379
    ogs_cluster_t *cluster = NULL;
380
    void *buffer = NULL;
381
    ogs_assert(pool);
382
383
    ogs_pool_alloc(&pool->cluster, &cluster);
384
    ogs_assert(cluster);
385
    memset(cluster, 0, sizeof(*cluster));
386
387
    if (size <= OGS_CLUSTER_128_SIZE) {
388
        ogs_pool_alloc(&pool->cluster_128, (ogs_cluster_128_t**)&buffer);
389
        if (!buffer) {
390
            ogs_error("ogs_pool_alloc() failed");
391
            return NULL;
392
        }
393
        cluster->size = OGS_CLUSTER_128_SIZE;
394
    } else if (size <= OGS_CLUSTER_256_SIZE) {
395
        ogs_pool_alloc(&pool->cluster_256, (ogs_cluster_256_t**)&buffer);
396
        if (!buffer) {
397
            ogs_error("ogs_pool_alloc() failed");
398
            return NULL;
399
        }
400
        cluster->size = OGS_CLUSTER_256_SIZE;
401
    } else if (size <= OGS_CLUSTER_512_SIZE) {
402
        ogs_pool_alloc(&pool->cluster_512, (ogs_cluster_512_t**)&buffer);
403
        if (!buffer) {
404
            ogs_error("ogs_pool_alloc() failed");
405
            return NULL;
406
        }
407
        cluster->size = OGS_CLUSTER_512_SIZE;
408
    } else if (size <= OGS_CLUSTER_1024_SIZE) {
409
        ogs_pool_alloc(&pool->cluster_1024, (ogs_cluster_1024_t**)&buffer);
410
        if (!buffer) {
411
            ogs_error("ogs_pool_alloc() failed");
412
            return NULL;
413
        }
414
        cluster->size = OGS_CLUSTER_1024_SIZE;
415
    } else if (size <= OGS_CLUSTER_2048_SIZE) {
416
        ogs_pool_alloc(&pool->cluster_2048, (ogs_cluster_2048_t**)&buffer);
417
        if (!buffer) {
418
            ogs_error("ogs_pool_alloc() failed");
419
            return NULL;
420
        }
421
        cluster->size = OGS_CLUSTER_2048_SIZE;
422
    } else if (size <= OGS_CLUSTER_8192_SIZE) {
423
        ogs_pool_alloc(&pool->cluster_8192, (ogs_cluster_8192_t**)&buffer);
424
        if (!buffer) {
425
            ogs_error("ogs_pool_alloc() failed");
426
            return NULL;
427
        }
428
        cluster->size = OGS_CLUSTER_8192_SIZE;
429
    } else if (size <= OGS_CLUSTER_32768_SIZE) {
430
        ogs_pool_alloc(&pool->cluster_32768, (ogs_cluster_32768_t**)&buffer);
431
        if (!buffer) {
432
            ogs_error("ogs_pool_alloc() failed");
433
            return NULL;
434
        }
435
        cluster->size = OGS_CLUSTER_32768_SIZE;
436
    } else if (size <= OGS_CLUSTER_BIG_SIZE) {
437
        ogs_pool_alloc(&pool->cluster_big, (ogs_cluster_big_t**)&buffer);
438
        if (!buffer) {
439
            ogs_error("ogs_pool_alloc() failed");
440
            return NULL;
441
        }
442
        cluster->size = OGS_CLUSTER_BIG_SIZE;
443
    } else {
444
        ogs_fatal("invalid size = %d", size);
445
        ogs_assert_if_reached();
446
    }
447
    cluster->buffer = buffer;
448
449
    return cluster;
450
}
451
452
static void cluster_free(ogs_pkbuf_pool_t *pool, ogs_cluster_t *cluster)
453
{
454
    ogs_assert(pool);
455
    ogs_assert(cluster);
456
    ogs_assert(cluster->buffer);
457
458
    switch (cluster->size) {
459
    case OGS_CLUSTER_128_SIZE:
460
        ogs_pool_free(&pool->cluster_128, (ogs_cluster_128_t*)cluster->buffer);
461
        break;
462
    case OGS_CLUSTER_256_SIZE:
463
        ogs_pool_free(&pool->cluster_256, (ogs_cluster_256_t*)cluster->buffer);
464
        break;
465
    case OGS_CLUSTER_512_SIZE:
466
        ogs_pool_free(&pool->cluster_512, (ogs_cluster_512_t*)cluster->buffer);
467
        break;
468
    case OGS_CLUSTER_1024_SIZE:
469
        ogs_pool_free(
470
                &pool->cluster_1024, (ogs_cluster_1024_t*)cluster->buffer);
471
        break;
472
    case OGS_CLUSTER_2048_SIZE:
473
        ogs_pool_free(
474
                &pool->cluster_2048, (ogs_cluster_2048_t*)cluster->buffer);
475
        break;
476
    case OGS_CLUSTER_8192_SIZE:
477
        ogs_pool_free(
478
                &pool->cluster_8192, (ogs_cluster_8192_t*)cluster->buffer);
479
        break;
480
    case OGS_CLUSTER_32768_SIZE:
481
        ogs_pool_free(
482
                &pool->cluster_32768, (ogs_cluster_32768_t*)cluster->buffer);
483
        break;
484
    case OGS_CLUSTER_BIG_SIZE:
485
        ogs_pool_free(&pool->cluster_big, (ogs_cluster_big_t*)cluster->buffer);
486
        break;
487
    default:
488
        ogs_assert_if_reached();
489
    }
490
491
    ogs_pool_free(&pool->cluster, cluster);
492
}
493
#endif