/* multicast — адресная рассылка по маршрутам topo-группы, с разделением по next hop. * send копирует данные; descriptor задаёт приложение источника, это не номер пакета. * Одна FIFO на ETCP-соединение обслуживает все группы/источники/дескрипторы. * При переполнении теряется новая ветка; источник получает OVERLOAD через router. * Все вызовы и callbacks — uasync-поток. В callbacks допустима отправка, но нельзя * уничтожать ядро/группу/модуль. Данные callbacks заимствованы только на время вызова. * * Wire DATA, все числа little-endian: * cmd:1 | group:8 | descriptor:2 | count:2 | source:8 | recipients:8*count | * payload | visited:8*hops | hops:1. * Получатели строго возрастают. Источник начинает visited собой, каждый транзит * добавляет себя ровно один раз. Первый visited=source, последний=ETCP peer. * Полный резерв visited учитывается до отправки, payload на транзите не меняется. * * Wire OVERLOAD — payload отдельного router-сервиса: * descriptor:2 | src:8 | dst:8 | packets:4 | count:2 | prefix_len:1 | * prefix:16 | recipients:8*count. * src/dst — концы перегруженного участка; router dst — источник DATA. * packets относится к КАЖДОМУ указанному получателю. Части длинного отчёта имеют * непересекающиеся списки: складывать их packets как число исходных пакетов нельзя. * Отчёт сохраняет префикс первого пакета; разные наборы получателей не смешиваются. */ #ifndef UTUN_MULTICAST_H #define UTUN_MULTICAST_H #include #include #ifdef __cplusplus extern "C" { #endif struct UTUN_INSTANCE; struct TOPO_GROUP; struct multicast_ctx; #define MULTICAST_QUEUE_BYTES (256u * 1024u) #define MULTICAST_REPORT_BYTES (16u * 1024u) #define MULTICAST_REPORT_INTERVAL_TB 3000 #define MULTICAST_MAX_VISITED 64 #define MULTICAST_HEADER_SIZE 21 #define MULTICAST_PATH_RESERVE (8 * MULTICAST_MAX_VISITED + 1) #define MULTICAST_REPORT_HEADER_SIZE 41 enum multicast_loss_reason { MULTICAST_OVERLOAD = 1, /* очередь выбранного исходящего соединения заполнена */ MULTICAST_NO_ROUTE, /* только локальное уведомление источнику */ MULTICAST_PATH_LOOP, /* локальное уведомление; транзит логирует потерю */ MULTICAST_INTERNAL_ERROR /* выделение памяти / отказ транспорта */ }; struct multicast_loss { uint64_t group_id; /* группа исходной рассылки */ uint64_t source_node_id; /* источник исходного DATA */ uint64_t src, dst; /* узел потери и выбранный next hop; dst=0 без маршрута */ uint16_t descriptor; /* идентификатор приложения источника */ uint16_t recipient_count; /* число ID в recipients */ const uint64_t* recipients; /* заимствованный массив в host byte order */ uint32_t packets; /* потери для каждого получателя этого списка */ enum multicast_loss_reason reason; uint8_t prefix_len; /* 0..16 значимых байт */ uint8_t prefix[16]; /* начало payload первого потерянного пакета */ }; typedef void (*multicast_recv_fn)(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t source, uint16_t descriptor, const uint8_t* payload, size_t len, void* arg); typedef void (*multicast_loss_fn)(struct UTUN_INSTANCE* inst, const struct multicast_loss* loss, void* arg); struct multicast_stats { uint64_t sent, delivered, overload_packets, no_route_packets, loop_packets, invalid_packets, internal_errors; uint64_t reports_sent, reports_received, reports_evicted; /* отправленные части / принятые / вытесненные записи */ size_t queued_bytes, report_bytes; /* данные в FIFO / память отчётов и окон, без уже переданного транспорту */ unsigned queues; /* лениво созданные FIFO, в том числе временно опустевшие */ }; /* Инициализация после etcp_router_init; destroy до router/ETCP. 0/-1; повторный init — ошибка. */ int multicast_init(struct UTUN_INSTANCE* inst); void multicast_destroy(struct UTUN_INSTANCE* inst); /* Один приёмник и обработчик потерь на ядро; NULL отключает соответствующий callback. */ void multicast_set_callbacks(struct UTUN_INSTANCE* inst, multicast_recv_fn recv, multicast_loss_fn loss, void* arg); /* count>0, ID ненулевые; повторы удаляются. len может быть 0. 0=принято к обработке, * -1=неверный аргумент/размер или отказ начального выделения. Частичные потери — через loss. * Доставка best effort: повторов/сквозных ACK нет; порядок при смене маршрутов не гарантируется. */ int multicast_send(struct TOPO_GROUP* group, uint16_t descriptor, const uint64_t* recipients, uint16_t count, const void* payload, size_t len); /* Снимок диагностики; 0/-1, не создаёт состояния. */ int multicast_get_stats(struct UTUN_INSTANCE* inst, struct multicast_stats* out); /* Внутренние hooks топологии: отложенный пересмотр маршрутов / отмена данных удаляемой группы. */ void multicast_routes_changed(struct UTUN_INSTANCE* inst); void multicast_close_group(struct UTUN_INSTANCE* inst, uint64_t group_id); #ifdef __cplusplus } #endif #endif