add IPv6 default route interface auto-detection for permanent/temporary IPv6 without netif

- get_default_route_netif_index(): UDP connect trick + getifaddrs to find default route iface
- etcp_socket_add(): auto-detect netif_index when not specified in config
- queue_new() API: explicit index_offset/index_size params instead of implicit from hash_size
- radix: cleanup types (uint8_t*), replace bzero/bcmp with memset/memcmp, remove kernel ifdefs
- route6_lib: new IPv6 routing library + get_node_v6_routes()
This commit is contained in:
Evgeny committed 2026-05-10 00:05:23 +03:00
1 parent e1f051856f
commit c24a6367cc
65 files changed
+34811 -556

No files matched your search

+14 -1
View File
@@ -34,6 +34,8 @@ check_PROGRAMS = \
test_tcp_proxy \
test_etcp_router \
test_remote_proxy \
test_radix \
test_route6_lib \
bench_timeout_heap \
bench_uasync_timeouts
@@ -193,6 +195,17 @@ test_etcp_router_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS)
test_remote_proxy_SOURCES = test_remote_proxy.c
test_remote_proxy_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_radix_SOURCES = test_radix.c
test_radix_CFLAGS = -I$(top_srcdir)/lib
test_radix_LDADD = $(COMMON_LIBS)
test_route6_lib_SOURCES = test_route6_lib.c
test_route6_lib_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_route6_lib_LDADD = $(top_builddir)/src/utun-route6_lib.o \
$(top_builddir)/src/utun-route_node.o \
$(top_builddir)/src/utun-etcp_debug.o \
$(COMMON_LIBS)
test_etcp_minimal_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_etcp_100_packets_SOURCES = test_etcp_100_packets.c
@@ -331,7 +344,7 @@ clean-local:
TEST_LOG_DIR = $(top_builddir)/tests/logs
# Custom check target that runs tests and saves logs to files
check-local:
check-local: $(check_PROGRAMS)
@$(MKDIR_P) $(TEST_LOG_DIR); \
G='\033[0;32m'; R='\033[0;31m'; Y='\033[0;33m'; N='\033[0m'; \
passed=0; \
+2 -2
View File
@@ -27,7 +27,7 @@ static double test_without_pools(int iterations) {
clock_t start = clock();
struct UASYNC* ua = uasync_create();
struct ll_queue* queue = queue_new(ua, 0,"q1"); // Без пулов
struct ll_queue* queue = queue_new(ua, 0, 0, 0,"q1"); // Без пулов
for (int cycle = 0; cycle < iterations; cycle++) {
// Создать много waiters
@@ -70,7 +70,7 @@ static double test_with_pools(int iterations) {
clock_t start = clock();
struct UASYNC* ua = uasync_create();
struct ll_queue* queue = queue_new(ua, 0,"q2"); // С пулами
struct ll_queue* queue = queue_new(ua, 0, 0, 0,"q2"); // С пулами
// Создать пул памяти для данных
struct memory_pool* pool = memory_pool_init(sizeof(struct ll_entry) + 64);
+22 -22
View File
@@ -77,8 +77,8 @@ static void waiter_cb(struct ll_queue *q, void *arg) {
static void test_basic(void) {
TEST("basic creation / free");
struct UASYNC *ua = uasync_create();
struct ll_queue *q1 = queue_new(ua, 0,"q1");
struct ll_queue *q2 = queue_new(ua, 16,"q2");
struct ll_queue *q1 = queue_new(ua, 0, 0, 0, "q1");
struct ll_queue *q2 = queue_new(ua, 16, 0, 0, "q2");
ASSERT(q1 && q2, "queue_new failed");
ASSERT_EQ(queue_entry_count(q1), 0, "");
queue_free(q1); queue_free(q2);
@@ -89,13 +89,13 @@ static void test_basic(void) {
static void test_fifo(void) {
TEST("FIFO ordering");
struct UASYNC *ua = uasync_create();
struct ll_queue *q = queue_new(ua, 0,"q3");
struct ll_queue *q = queue_new(ua, 0, 0, 0, "q3");
for (int i = 0; i < 10; i++) {
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(test_data_t));
d->id = i; snprintf(d->name, sizeof(d->name), "item%d", i);
d->value = i*10; d->checksum = checksum(d);
queue_data_put_with_index(q, (struct ll_entry*)d, 0, 4);
queue_data_put(q, (struct ll_entry*)d);
}
ASSERT_EQ(queue_entry_count(q), 10, "");
@@ -112,19 +112,19 @@ static void test_fifo(void) {
static void test_lifo_priority(void) {
TEST("put_first (LIFO priority)");
struct UASYNC *ua = uasync_create();
struct ll_queue *q = queue_new(ua, 0,"q4");
struct ll_queue *q = queue_new(ua, 0, 0, 0, "q4");
for (int i = 0; i < 3; i++) {
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d));
d->id = i;
d->value = i;
d->checksum = checksum(d);
queue_data_put_with_index(q, (struct ll_entry*)d, 0, 4);
queue_data_put(q, (struct ll_entry*)d);
}
test_data_t *pri = (test_data_t*)queue_entry_new(sizeof(*pri));
pri->id = 999; pri->value = 999; pri->checksum = checksum(pri);
queue_data_put_first_with_index(q, (struct ll_entry*)pri, 0, 4);
queue_data_put_first(q, (struct ll_entry*)pri);
test_data_t *first = (test_data_t*)queue_data_get(q);
ASSERT(first && first->id == 999, "priority first");
@@ -142,7 +142,7 @@ static void test_lifo_priority(void) {
static void test_callback(void) {
TEST("callback serial processing");
struct UASYNC *ua = uasync_create();
struct ll_queue *q = queue_new(ua, 0,"q5");
struct ll_queue *q = queue_new(ua, 0, 0, 0, "q5");
int cnt = 0;
queue_set_callback(q, queue_cb, &cnt);
@@ -150,7 +150,7 @@ static void test_callback(void) {
for (int i = 0; i < 5; i++) {
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d));
d->id = i; d->value = i*10; d->checksum = checksum(d);
queue_data_put_with_index(q, (struct ll_entry*)d, 0, 4);
queue_data_put(q, (struct ll_entry*)d);
}
for (int i = 0; i < 30 && cnt < 5; i++) uasync_poll(ua, 5);
@@ -164,7 +164,7 @@ static void test_callback(void) {
static void test_waiter(void) {
TEST("wait_threshold + cancel");
struct UASYNC *ua = uasync_create();
struct ll_queue *q = queue_new(ua, 0,"q6");
struct ll_queue *q = queue_new(ua, 0, 0, 0, "q6");
int called = 0;
struct queue_waiter *w = queue_wait_threshold(q, 2, 0, waiter_cb, &called);
@@ -172,7 +172,7 @@ static void test_waiter(void) {
for (int i = 0; i < 5; i++) {
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
queue_data_put_with_index(q, (struct ll_entry*)d, 0, 4);
queue_data_put(q, (struct ll_entry*)d);
}
called = 0;
@@ -192,21 +192,21 @@ static void test_waiter(void) {
static void test_limits_hash(void) {
TEST("size limit + hash find/remove");
struct UASYNC *ua = uasync_create();
struct ll_queue *q = queue_new(ua, 16,"q7");
struct ll_queue *q = queue_new(ua, 16, 0, 4, "q7");
queue_set_size_limit(q, 3);
for (int i = 0; i < 3; i++) {
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i*10+1;
queue_data_put_with_index(q, (struct ll_entry*)d, 0, 4);
queue_data_put_with_index(q, (struct ll_entry*)d);
}
test_data_t *ex = (test_data_t*)queue_entry_new(sizeof(*ex));
ASSERT_EQ(queue_data_put_with_index(q, (struct ll_entry*)ex, 0, 4), -1, "limit reject");
ASSERT_EQ(queue_data_put_with_index(q, (struct ll_entry*)ex), -1, "limit reject");
uint32_t hash=21;
test_data_t *found = (test_data_t*)queue_find_data_by_index(q, &hash, 4);
test_data_t *found = (test_data_t*)queue_find_data_by_index(q, &hash);
ASSERT(found && found->id == 21, "hash find");
queue_remove_data(q, (struct ll_entry*)found);
ASSERT(queue_find_data_by_index(q, &hash, 4) == NULL, "removed");
ASSERT(queue_find_data_by_index(q, &hash) == NULL, "removed");
while (queue_entry_count(q)) queue_entry_free((struct ll_entry*)queue_data_get(q));
queue_free(q); uasync_destroy(ua, 0);
@@ -217,18 +217,18 @@ static void test_pool(void) {
TEST("memory_pool integration + reuse");
struct UASYNC *ua = uasync_create();
struct memory_pool *pool = memory_pool_init(sizeof(test_data_t));
struct ll_queue *q = queue_new(ua, 0,"q8");
struct ll_queue *q = queue_new(ua, 0, 0, 0, "q8");
size_t alloc1 = 0, reuse1 = 0;
memory_pool_get_stats(pool, &alloc1, &reuse1);
test_data_t *d1 = (test_data_t*)queue_entry_new_from_pool(pool);
d1->id = 1; d1->checksum = checksum(d1);
queue_data_put_with_index(q, (struct ll_entry*)d1, 0, 4);
queue_data_put(q, (struct ll_entry*)d1);
test_data_t *d2 = (test_data_t*)queue_entry_new_from_pool(pool);
d2->id = 2; d2->checksum = checksum(d2);
queue_data_put_with_index(q, (struct ll_entry*)d2, 0, 4);
queue_data_put(q, (struct ll_entry*)d2);
queue_entry_free((struct ll_entry*)queue_data_get(q)); // free d1 back to pool
queue_entry_free((struct ll_entry*)queue_data_get(q)); // free d2 back to pool
@@ -237,7 +237,7 @@ static void test_pool(void) {
test_data_t *d3 = (test_data_t*)queue_entry_new_from_pool(pool);
ASSERT(d3 != NULL, "alloc after free failed");
d3->id = 3; d3->checksum = checksum(d3);
queue_data_put_with_index(q, (struct ll_entry*)d3, 0, 4);
queue_data_put(q, (struct ll_entry*)d3);
queue_entry_free((struct ll_entry*)queue_data_get(q)); // free d3 back
size_t alloc2 = 0, reuse2 = 0;
@@ -252,7 +252,7 @@ static void test_stress(void) {
TEST("stress 10k ops");
double start = now_ms();
struct UASYNC *ua = uasync_create();
struct ll_queue *q = queue_new(ua, 64,"q9");
struct ll_queue *q = queue_new(ua, 64, 0, 4, "q9");
for (int i = 0; i < 10000; i++) {
if (queue_entry_count(q) > 80) {
@@ -261,7 +261,7 @@ static void test_stress(void) {
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d));
d->id = rand() % 10000;
d->checksum = checksum(d);
queue_data_put_with_index(q, (struct ll_entry*)d, 0, 4);
queue_data_put_with_index(q, (struct ll_entry*)d);
stats.ops++;
}
while (queue_entry_count(q)) queue_entry_free((struct ll_entry*)queue_data_get(q));
+1 -1
View File
@@ -43,7 +43,7 @@ int main() {
}
// Create queue with memory pools enabled
struct ll_queue* queue = queue_new(ua, 0,"q1");
struct ll_queue* queue = queue_new(ua, 0, 0, 0,"q1");
if (!queue) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create queue with pools");
uasync_destroy(ua, 0);
+2 -2
View File
@@ -191,8 +191,8 @@ static int init_mock_etcp(void) {
}
// Create queues
mock_etcp.input_queue = queue_new(mock_instance.ua, 0,"q1");
mock_etcp.output_queue = queue_new(mock_instance.ua, 0,"q2");
mock_etcp.input_queue = queue_new(mock_instance.ua, 0, 0, 0, "q1");
mock_etcp.output_queue = queue_new(mock_instance.ua, 0, 0, 0, "q2");
if (!mock_etcp.input_queue || !mock_etcp.output_queue) {
printf("Failed to create queues\n");
+1 -1
View File
@@ -55,7 +55,7 @@ static struct NODEINFO_Q* create_test_node(uint64_t node_id, uint8_t ver, uint32
nq->node.local_v6_subnets = 0;
nq->node.tranzit_nodes = 0;
nq->node.hop_count = 0;
nq->paths = queue_new(NULL, 16, "test_paths");
nq->paths = queue_new(NULL, 16, 0, 0, "test_paths");
/* Fill subnet after fixed header (after name_len=0, sockets=0) */
uint8_t *dyn = (uint8_t *)&nq->node + sizeof(struct NODEINFO);
struct NODEINFO_IPV4_SUBNET *sn = (struct NODEINFO_IPV4_SUBNET *)dyn;