You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

150 lines
7.8 KiB

// etcp_router.c — Сервисный слой маршрутизации поверх ETCP
// Маршрутизирует сервисные пакеты до целевой ноды, на промежуточных нодах ретранслирует
#include "etcp_router.h"
#include "etcp.h"
#include "utun_instance.h"
#include "route_bgp.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include "../lib/ll_queue.h"
#include <string.h>
// Обработчик ETCP_ID_SVC_ROUTE — вызывается etcp_int_recv на каждом узле
static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (!conn || !entry) {
if (entry) { queue_entry_free(entry); queue_dgram_free(entry); }
return;
}
struct UTUN_INSTANCE* inst = conn->instance;
if (!inst || entry->len < SVC_ROUTE_HDR_SIZE) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_router: invalid packet inst=%p len=%zu min=%d",
(void*)inst, entry ? entry->len : 0, SVC_ROUTE_HDR_SIZE);
queue_entry_free(entry); queue_dgram_free(entry);
return;
}
uint8_t svc_id = entry->dgram[1];
uint64_t dst_node_id = 0; memcpy(&dst_node_id, entry->dgram + 2, 8);
if (dst_node_id == inst->node_id) {
if (svc_id >= SVC_ROUTE_MAX_BINDINGS || !inst->router_bindings.callbacks[svc_id]) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_router: no handler for svc_id=%u dst=%016llx self=%016llx",
svc_id, (unsigned long long)dst_node_id, (unsigned long long)inst->node_id);
queue_entry_free(entry); queue_dgram_free(entry);
return;
}
size_t payload_len = entry->len - SVC_ROUTE_HDR_SIZE;
struct ll_entry* svc_entry = queue_entry_new(0);
if (!svc_entry) { queue_entry_free(entry); queue_dgram_free(entry); return; }
svc_entry->len = 1 + payload_len;
svc_entry->dgram = u_malloc(svc_entry->len);
if (!svc_entry->dgram) { queue_entry_free(svc_entry); queue_entry_free(entry); queue_dgram_free(entry); return; }
svc_entry->dgram[0] = svc_id;
if (payload_len > 0) memcpy(svc_entry->dgram + 1, entry->dgram + SVC_ROUTE_HDR_SIZE, payload_len);
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_router: delivering svc_id=%u len=%zu to handler %p src=%016llx",
svc_id, payload_len, (void*)inst->router_bindings.callbacks[svc_id],
(unsigned long long)(*(uint64_t*)(entry->dgram + 10)));
queue_entry_free(entry); queue_dgram_free(entry);
inst->router_bindings.callbacks[svc_id](conn, svc_entry);
} else {
struct ETCP_CONN* next = route_bgp_find_conn_for_node(inst->bgp, dst_node_id);
if (!next) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_router: no route to %016llx svc_id=%u, dropping",
(unsigned long long)dst_node_id, svc_id);
queue_entry_free(entry); queue_dgram_free(entry);
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_router: forwarding svc_id=%u → %016llx via %s",
svc_id, (unsigned long long)dst_node_id, next->log_name);
etcp_send(next, entry);
}
}
// ====================================================================
// Public API
// ====================================================================
int etcp_router_init(struct UTUN_INSTANCE* inst) {
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_init: NULL instance"); return -1; }
memset(&inst->router_bindings, 0, sizeof(inst->router_bindings));
int ret = etcp_bind(inst, ETCP_ID_SVC_ROUTE, etcp_router_recv_cb);
if (ret != 0) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_init: etcp_bind failed, ret=%d", ret); return -1; }
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_router initialized for node %016llx", (unsigned long long)inst->node_id);
return 0;
}
void etcp_router_destroy(struct UTUN_INSTANCE* inst) {
if (!inst) return;
etcp_unbind(inst, ETCP_ID_SVC_ROUTE);
memset(&inst->router_bindings, 0, sizeof(inst->router_bindings));
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_router destroyed for node %016llx", (unsigned long long)inst->node_id);
}
int etcp_router_bind(struct UTUN_INSTANCE* inst, uint8_t svc_id, etcp_recv_fn callback) {
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_bind: NULL instance"); return -1; }
if (svc_id >= SVC_ROUTE_MAX_BINDINGS) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_bind: invalid svc_id %u", svc_id); return -1; }
if (!callback) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_bind: NULL callback for svc_id=%u", svc_id); return -1; }
if (inst->router_bindings.callbacks[svc_id]) DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_router_bind: overwriting svc_id=%u", svc_id);
inst->router_bindings.callbacks[svc_id] = callback;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_router_bind: svc_id=%u → cb=%p", svc_id, (void*)callback);
return 0;
}
int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id) {
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_unbind: NULL instance"); return -1; }
if (svc_id >= SVC_ROUTE_MAX_BINDINGS) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_router_unbind: invalid svc_id %u", svc_id); return -1; }
if (!inst->router_bindings.callbacks[svc_id]) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_router_unbind: svc_id=%u not bound", svc_id); return -1; }
inst->router_bindings.callbacks[svc_id] = NULL;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_router_unbind: svc_id=%u", svc_id);
return 0;
}
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_entry* entry) {
if (!inst || !entry) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_route_send: NULL inst=%p entry=%p", (void*)inst, (void*)entry);
if (entry) { queue_entry_free(entry); queue_dgram_free(entry); }
return -1;
}
if (!entry->dgram || entry->len < 1) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_route_send: empty entry");
queue_entry_free(entry); queue_dgram_free(entry);
return -1;
}
uint8_t svc_id = entry->dgram[0];
size_t payload_len = entry->len - 1;
// Loopback — dispatch прямо локально
if (dst_node_id == inst->node_id) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_route_send: loopback svc_id=%u len=%zu", svc_id, payload_len);
if (svc_id < SVC_ROUTE_MAX_BINDINGS && inst->router_bindings.callbacks[svc_id])
inst->router_bindings.callbacks[svc_id](NULL, entry);
else { queue_entry_free(entry); queue_dgram_free(entry); }
return 0;
}
// Упаковываем в routing header
size_t total_len = SVC_ROUTE_HDR_SIZE + payload_len;
uint8_t* new_dgram = u_malloc(total_len);
if (!new_dgram) { queue_entry_free(entry); queue_dgram_free(entry); return -1; }
new_dgram[0] = ETCP_ID_SVC_ROUTE;
new_dgram[1] = svc_id;
memcpy(new_dgram + 2, &dst_node_id, 8);
memcpy(new_dgram + 10, &inst->node_id, 8);
if (payload_len > 0) memcpy(new_dgram + SVC_ROUTE_HDR_SIZE, entry->dgram + 1, payload_len);
struct ll_entry* new_entry = queue_entry_new(0);
if (!new_entry) { u_free(new_dgram); queue_entry_free(entry); queue_dgram_free(entry); return -1; }
new_entry->dgram = new_dgram;
new_entry->len = total_len;
queue_entry_free(entry); queue_dgram_free(entry);
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, dst_node_id);
if (!conn) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_route_send: no route to %016llx svc_id=%u, dropping",
(unsigned long long)dst_node_id, svc_id);
queue_entry_free(new_entry); queue_dgram_free(new_entry);
return -1;
}
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_route_send: svc_id=%u → %016llx via %s len=%zu",
svc_id, (unsigned long long)dst_node_id, conn->log_name, total_len);
return etcp_send(conn, new_entry);
}