@ -3,20 +3,20 @@
* @ brief М о д е л ь д а н н ы х у з л а с е т и — с т р у к т у р ы , с е р и а л и з а ц и я , wire - ф о р м а т .
* @ brief М о д е л ь д а н н ы х у з л а с е т и — с т р у к т у р ы , с е р и а л и з а ц и я , wire - ф о р м а т .
*
*
* Э т о т м о д у л ь о п р е д е л я е т :
* Э т о т м о д у л ь о п р е д е л я е т :
* - К а к у з е л п р е д с т а в л е н в п а м я т и ( TOPO_NODE , TOPO_NODEQ , а д р е с а , п о д с е т и )
* - К а к у з е л п р е д с т а в л е н в п а м я т и ( TOPO_NODE , TOPO_GROUP_ NODE , а д р е с а , п о д с е т и )
* - К а к у з е л п е р е д а ё т с я п о с е т и ( packed - с т р у к т у р ы TOPOMSG_ * )
* - К а к у з е л п е р е д а ё т с я п о с е т и ( packed - с т р у к т у р ы TOPOMSG_ * )
* - К а к у з е л с е р и а л и з у е т с я / д е с е р и а л и з у е т с я ( topo_node_serialize / deserialize )
* - К а к у з е л с е р и а л и з у е т с я / д е с е р и а л и з у е т с я ( topo_node_serialize / deserialize )
*
*
* М о д у л ь н е с о д е р ж и т с е т е в о й л о г и к и и BGP - о б м е н а — э т и м з а н и м а е т с я topo_group .
* Х р а н е н и е :
*
* - И д е н т и ч н о с т ь у з л а ( pubkeys , а д р е с а , и м я ) — в г л о б а л ь н о м р е е с т р е TOPO_GROUPS - > node_registry
* Х р а н е н и е : д а н н ы е у з л о в с о х р а н я ю т с я в SQLite ( т а б л и ц ы nodes , node_addresses )
* Е д и н с т в е н н ы й э к з е м п л я р TOPO_NODE , р а з д е л я е т с я м е ж д у г р у п п а м и ч е р е з group_ref_count .
* ч е р е з м о д у л ь topo_node_sqlite .
* - Per - group д а н н ы е ( node_id , paths , subnets , connectivity ) — в TOPO_GROUP - > nodes ( о ч е р е д ь TOPO_GROUP_NODE )
*
*
* О с н о в н ы е п о н я т и я :
* О с н о в н ы е п о н я т и я :
* TOPO_NODE — и д е н т и ч н о с т ь у з л а ( pubkeys , и м я , в е р с и я , с п и с к и а д р е с о в )
* TOPO_NODE — г л о б а л ь н а я и д е н т и ч н о с т ь у з л а . В с т р о е н в node_registry к а к queue entry .
* TOPO_NODEQ — з а п и с ь в о ч е р е д и г р у п п ы ( п л ю с п у т и , hop_list , с в я з н о с т ь )
* TOPO_GROUP_NODE — у з е л в к о н т е к с т е г р у п п ы : node_id + paths , hop_list , с в я з н о с т ь
* TOPO_NODEPATH — п у т ь д о у з л а ч е р е з к о н к р е т н о е ETCP - с о е д и н е н и е
* TOPO_NODEPATH — п у т ь д о у з л а ч е р е з к о н к р е т н о е ETCP - с о е д и н е н и е
* TOPOMSG_NODE — wire - ф о р м а т , п е р е д а в а е м ы й п о NODEINFO
* TOPOMSG_NODE — wire - ф о р м а т , п е р е д а в а е м ы й п о NODEINFO
*/
*/
# ifndef TOPO_NODE_H
# ifndef TOPO_NODE_H
# define TOPO_NODE_H
# define TOPO_NODE_H
@ -33,29 +33,20 @@ extern "C" {
struct TOPO_GROUP ;
struct TOPO_GROUP ;
struct TOPO_GROUPS ;
struct TOPO_GROUPS ;
struct ETCP_SOCKET ;
struct ETCP_SOCKET ;
struct ETCP_CONN ;
struct UTUN_INSTANCE ;
struct UTUN_INSTANCE ;
// ---- типы адресов в плоском списке TOPOMSG_ADDR4 ----
# define TOPO_ADDR_INTERFACE 0
# define TOPO_ADDR_NAT 1
# define TOPO_ADDR_INTERFACE 0 // interface_addr сокета (LAN)
# define TOPO_ADDR_REAL 2
# define TOPO_ADDR_NAT 1 // nat_addr после детекции NAT
# define TOPO_ADDR_REAL 2 // подтверждённый прямой интернет-адрес (nat проверка показала совпадение с interface_addr)
// ---- протоколы транспорта (поле protocol в TOPOMSG_ADDR4/TOPOMSG_ADDR6) ----
# define TOPO_PROTO_UDP 0x01
# define TOPO_PROTO_UDP 0x01
# define TOPO_PROTO_TCP 0x02
# define TOPO_PROTO_TCP 0x02
// ---- типы NAT (etcp_connections.h) ----
# define ADDR_TYPE_NETIF 0
// NAT_TYPE_UNKNOWN(0), NAT_TYPE_EIM(1), NAT_TYPE_STRICT(2)
# define ADDR_TYPE_DIRECT 1
// NAT_VERIFIED_UNKNOWN(4), NAT_VERIFIED_EIM(5), NAT_VERIFIED_STRICT(6), NAT_VERIFIED_DIRECT(7)
# define ADDR_TYPE_NAT_EIM 2
# define ADDR_TYPE_NAT_STRICT 3
// ---- типы адресов для БД (node_addresses.addr_type) ----
# define ADDR_TYPE_NETIF 0 // interface / auto-detected
# define ADDR_TYPE_DIRECT 1 // прямой публичный адрес (detected no NAT)
# define ADDR_TYPE_NAT_EIM 2 // EIM NAT
# define ADDR_TYPE_NAT_STRICT 3 // strict NAT
// ---- статусы зондирования связности ----
# define PROBE_STATUS_NONE 0
# define PROBE_STATUS_NONE 0
# define PROBE_STATUS_IN_PROGRESS 1
# define PROBE_STATUS_IN_PROGRESS 1
@ -74,18 +65,11 @@ struct UTUN_INSTANCE;
# define CONN_TYPE_INDIRECT 3
# define CONN_TYPE_INDIRECT 3
# define CONN_MGR_MAX_INTERMEDIARIES 3
# define CONN_MGR_MAX_INTERMEDIARIES 3
// ---- флаги nodeinfo ----
# define TOPO_FLAG_SEND_SUBNETS 0x01
# define TOPO_FLAG_SEND_SUBNETS 0x01
// ---- group_id по умолчанию ----
# define TOPO_GROUP_UTUN 0x8000000000000000ULL
# define TOPO_GROUP_UTUN 0x8000000000000000ULL
// ---- типы групп ----
# define TOPO_GROUP_TYPE_UTUN 1
# define TOPO_GROUP_TYPE_UTUN 1
# define TOPO_GROUP_TYPE_CHAT 2
# define TOPO_GROUP_TYPE_CHAT 2
// ---- состояние связности с удалённым узлом (локальное, не передаётся по BGP) ----
struct TOPO_CONNECTIVITY {
struct TOPO_CONNECTIVITY {
uint8_t probe_status ;
uint8_t probe_status ;
uint8_t pending_count ;
uint8_t pending_count ;
@ -101,88 +85,30 @@ struct TOPO_CONNECTIVITY {
uint64_t nat_probe_time ;
uint64_t nat_probe_time ;
uint64_t real_probe_time ;
uint64_t real_probe_time ;
uint64_t ping_req_time ;
uint64_t ping_req_time ;
uint64_t last_ping_time ; // время последнего успешного пинга (0.1ms timebase)
uint64_t last_ping_time ;
void * probe_list ;
void * probe_list ;
} ;
} ;
# define PING_TTL_TB (86400ULL * 10000ULL) // 1 день в 0.1ms units
# define PING_TTL_TB (86400ULL * 10000ULL)
// =======================================================================
// Протокольные структуры (wire-format, packed, без next)
// =======================================================================
struct TOPOMSG_SOCKMETA4 {
uint8_t id ;
uint8_t config_type ;
uint8_t nat_type ;
} __attribute__ ( ( packed ) ) ;
struct TOPOMSG_ADDR4 {
uint8_t addr [ 4 ] ;
uint16_t port ;
uint8_t type ;
uint8_t socket_id ;
uint8_t protocol ;
} __attribute__ ( ( packed ) ) ;
struct TOPOMSG_SOCKMETA6 {
uint8_t id ;
uint8_t config_type ;
uint8_t nat_type ;
} __attribute__ ( ( packed ) ) ;
struct TOPOMSG_ADDR6 {
uint8_t addr [ 16 ] ;
uint16_t port ;
uint8_t type ;
uint8_t socket_id ;
uint8_t protocol ;
} __attribute__ ( ( packed ) ) ;
struct TOPOMSG_SUBNET4 {
uint8_t addr [ 4 ] ;
uint8_t prefix_length ;
} __attribute__ ( ( packed ) ) ;
struct TOPOMSG_SUBNET6 {
struct TOPOMSG_SOCKMETA4 { uint8_t id , config_type , nat_type ; } __attribute__ ( ( packed ) ) ;
uint8_t addr [ 16 ] ;
struct TOPOMSG_ADDR4 { uint8_t addr [ 4 ] ; uint16_t port ; uint8_t type , socket_id , protocol ; } __attribute__ ( ( packed ) ) ;
uint8_t prefix_length ;
struct TOPOMSG_SOCKMETA6 { uint8_t id , config_type , nat_type ; } __attribute__ ( ( packed ) ) ;
} __attribute__ ( ( packed ) ) ;
struct TOPOMSG_ADDR6 { uint8_t addr [ 16 ] ; uint16_t port ; uint8_t type , socket_id , protocol ; } __attribute__ ( ( packed ) ) ;
struct TOPOMSG_SUBNET4 { uint8_t addr [ 4 ] ; uint8_t prefix_length ; } __attribute__ ( ( packed ) ) ;
struct TOPOMSG_TRANZIT {
struct TOPOMSG_SUBNET6 { uint8_t addr [ 16 ] ; uint8_t prefix_length ; } __attribute__ ( ( packed ) ) ;
uint64_t node_id ;
struct TOPOMSG_TRANZIT { uint64_t node_id ; uint16_t rtt , link_q ; } __attribute__ ( ( packed ) ) ;
uint16_t rtt ;
uint16_t link_q ;
} __attribute__ ( ( packed ) ) ;
/**
* @ brief П р о т о к о л ь н ы й ф о р м а т NODEINFO с о о б щ е н и я ( wire - format )
*/
struct TOPOMSG_NODE {
struct TOPOMSG_NODE {
uint8_t flags ;
uint8_t flags ; uint64_t group_id , node_id ; uint8_t ver ;
uint64_t group_id ;
uint8_t public_key [ SC_PUBKEY_SIZE ] , ed25519_public_key [ SC_PUBKEY_SIZE ] ;
uint64_t node_id ;
uint8_t x25519_self_sig [ 64 ] ;
uint8_t ver ;
uint8_t node_name_len , local_v4_sockets , local_v4_addrs , local_v6_sockets , local_v6_addrs ;
uint8_t public_key [ SC_PUBKEY_SIZE ] ;
uint8_t local_v4_subnets , local_v6_subnets , tranzit_nodes , hop_count ;
uint8_t ed25519_public_key [ SC_PUBKEY_SIZE ] ;
uint16_t cumulative_rtt ;
uint8_t x25519_self_sig [ 64 ] ; // Ed25519_sign(ed25519_privkey, x25519_pubkey, 32)
uint8_t node_name_len ;
uint8_t local_v4_sockets ;
uint8_t local_v4_addrs ;
uint8_t local_v6_sockets ;
uint8_t local_v6_addrs ;
uint8_t local_v4_subnets ;
uint8_t local_v6_subnets ;
uint8_t tranzit_nodes ;
uint8_t hop_count ;
uint16_t cumulative_rtt ; // сумма RTT upstream (0.1ms), без последнего линка
} __attribute__ ( ( packed ) ) ;
} __attribute__ ( ( packed ) ) ;
# define TOPOMSG_NODE_HDR_SIZE sizeof(struct TOPOMSG_NODE)
# define TOPOMSG_NODE_HDR_SIZE sizeof(struct TOPOMSG_NODE)
// =======================================================================
// Структуры для хранения в памяти (linked list с next* первым полем)
// =======================================================================
struct TOPO_SOCKMETA4 { struct TOPO_SOCKMETA4 * next ; uint8_t id , config_type , nat_type ; } ;
struct TOPO_SOCKMETA4 { struct TOPO_SOCKMETA4 * next ; uint8_t id , config_type , nat_type ; } ;
struct TOPO_ADDR4 { struct TOPO_ADDR4 * next ; uint8_t addr [ 4 ] ; uint16_t port ; uint8_t type , socket_id , protocol ; } ;
struct TOPO_ADDR4 { struct TOPO_ADDR4 * next ; uint8_t addr [ 4 ] ; uint16_t port ; uint8_t type , socket_id , protocol ; } ;
@ -191,35 +117,25 @@ struct TOPO_ADDR6 { struct TOPO_ADDR6* next; uint8_t addr[16]; uint16_t port
struct TOPO_SUBNET4 { struct TOPO_SUBNET4 * next ; uint8_t addr [ 4 ] ; uint8_t prefix_length ; } ;
struct TOPO_SUBNET4 { struct TOPO_SUBNET4 * next ; uint8_t addr [ 4 ] ; uint8_t prefix_length ; } ;
struct TOPO_SUBNET6 { struct TOPO_SUBNET6 * next ; uint8_t addr [ 16 ] ; uint8_t prefix_length ; } ;
struct TOPO_SUBNET6 { struct TOPO_SUBNET6 * next ; uint8_t addr [ 16 ] ; uint8_t prefix_length ; } ;
// Универсальная голова списка (next — первое поле во всех TOPO_*)
struct _topo_head { struct _topo_head * next ; } ;
struct _topo_head { struct _topo_head * next ; } ;
static inline int topo_list_count ( struct _topo_head * head ) { int n = 0 ; while ( head ) { n + + ; head = head - > next ; } return n ; }
static inline int topo_list_count ( struct _topo_head * head ) { int n = 0 ; while ( head ) { n + + ; head = head - > next ; } return n ; }
/**
/** Глобальная идентичность узла. Встроен в TOPO_GROUPS->node_registry как queue entry. */
* @ brief И д е н т и ф и к а ц и о н н а я и н ф о р м а ц и я о б у з л е ( п а м я т ь , р а з д е л я е т с я м е ж д у г р у п п а м и )
*/
struct TOPO_NODE {
struct TOPO_NODE {
uint32_t ref_count ;
struct ll_entry ll ;
uint8_t flags ;
uint32_t group_ref_count ;
uint64_t group_id ;
uint8_t flags ; uint64_t group_id , node_id ; uint8_t ver ;
uint64_t node_id ;
uint8_t public_key [ SC_PUBKEY_SIZE ] , ed25519_public_key [ SC_PUBKEY_SIZE ] ;
uint8_t ver ;
uint8_t x25519_self_sig [ 64 ] ;
uint8_t public_key [ SC_PUBKEY_SIZE ] ;
char * node_name ;
uint8_t ed25519_public_key [ SC_PUBKEY_SIZE ] ;
struct TOPO_SOCKMETA4 * v4_sock_meta ;
uint8_t x25519_self_sig [ 64 ] ; // Ed25519_sign(ed25519_privkey, x25519_pubkey, 32)
struct TOPO_ADDR4 * v4_addrs ;
char * node_name ; // отдельный u_strdup/u_free
struct TOPO_SOCKMETA4 * v4_sock_meta ; // linked list head
struct TOPO_ADDR4 * v4_addrs ; // linked list head
struct TOPO_SOCKMETA6 * v6_sock_meta ;
struct TOPO_SOCKMETA6 * v6_sock_meta ;
struct TOPO_ADDR6 * v6_addrs ;
struct TOPO_ADDR6 * v6_addrs ;
} ;
} ;
/**
* @ brief П о д с е т и у з л а ( о т д е л ь н ы й malloc , NULL е с л и н е т п о д с е т е й )
*/
struct TOPO_NODESUBNETS {
struct TOPO_NODESUBNETS {
struct TOPO_SUBNET4 * v4_subnets ; // linked list head
struct TOPO_SUBNET4 * v4_subnets ;
struct TOPO_SUBNET6 * v6_subnets ;
struct TOPO_SUBNET6 * v6_subnets ;
} ;
} ;
@ -227,76 +143,57 @@ struct TOPO_NODEPATH {
struct ll_entry ll ;
struct ll_entry ll ;
struct ETCP_CONN * conn ;
struct ETCP_CONN * conn ;
uint8_t hop_count ;
uint8_t hop_count ;
uint16_t cumulative_rtt ; // сумма RTT upstream (0.1ms) для этого пути
uint16_t cumulative_rtt ;
} ;
} ;
struct TOPO_NODEQ {
/** Узел в контексте группы (per-group данные). Хранится в TOPO_GROUP->nodes. */
struct TOPO_GROUP_NODE {
struct ll_entry ll ;
struct ll_entry ll ;
uint64_t hash_node_id ; // копия node_id для хеш-индекса
uint64_t node_id ;
struct TOPO_NODE * node ; // отдельный malloc, ref_count
struct TOPO_NODESUBNETS * subnets ;
struct TOPO_NODESUBNETS * subnets ; // отдельный malloc (NULL если без подсетей)
struct TOPOMSG_TRANZIT * tranzit_data ;
struct TOPOMSG_TRANZIT * tranzit_data ; // отдельный malloc
uint64_t * hop_list ;
uint64_t * hop_list ; // отдельный malloc
uint8_t tranzit_count , hop_count ;
uint8_t tranzit_count ;
uint16_t cumulative_rtt ;
uint8_t hop_count ;
uint16_t cumulative_rtt ; // база из последнего NODEINFO для пересылки
struct ll_queue * paths ;
struct ll_queue * paths ;
uint8_t dirty ;
uint8_t dirty , last_ver , conn_mgr_type ;
uint8_t last_ver ;
uint8_t conn_mgr_type ;
uint64_t conn_mgr_intermediaries [ CONN_MGR_MAX_INTERMEDIARIES ] ;
uint64_t conn_mgr_intermediaries [ CONN_MGR_MAX_INTERMEDIARIES ] ;
uint8_t conn_mgr_intermediariy_count ;
uint8_t conn_mgr_intermediariy_count ;
struct TOPO_CONNECTIVITY connectivity ;
struct TOPO_CONNECTIVITY connectivity ;
struct ETCP_SOCKET * best_socket ;
struct ETCP_SOCKET * best_socket ;
} ;
} ;
// API — глобальный реестр TOPO_NODE
struct TOPO_NODE * topo_node_registry_find ( struct TOPO_GROUPS * groups , uint64_t node_id ) ;
struct TOPO_NODE * topo_node_registry_store ( struct TOPO_GROUPS * groups , struct TOPO_NODE * ni ) ;
void topo_node_registry_ref ( struct TOPO_GROUPS * groups , uint64_t node_id ) ;
void topo_node_registry_unref ( struct TOPO_GROUPS * groups , uint64_t node_id ) ;
void topo_node_destroy ( struct TOPO_GROUPS * groups , struct TOPO_NODE * ni ) ;
// =======================================================================
// API — per-group
// API
struct TOPO_GROUP_NODE * topo_node_find_by_id ( struct TOPO_GROUP * group , uint64_t node_id ) ;
// =======================================================================
void topo_nodeq_free_group_fields ( struct TOPO_GROUPS * groups , struct TOPO_GROUP_NODE * nq ) ;
struct TOPO_NODEQ * topo_node_find_by_id ( struct TOPO_GROUP * group , uint64_t node_id ) ;
// Владение TOPO_NODE: создаётся с ref_count=0. Владелец вызывает topo_node_ref() чтобы завладеть.
// При отказе от владения — topo_node_unref(). При ref_count=0 узел удаляется.
void topo_node_ref ( struct TOPO_NODE * ni ) ;
void topo_node_unref ( struct TOPO_NODE * ni ) ;
// Глобальный реестр TOPO_NODE* (по node_id). Каждый узел хранится один раз.
// При помещении в реестр и при получении из реестра владение берётся (ref++).
// При освобождении из реестра владение возвращается (unref, при ref=0 — удаление).
struct TOPO_NODE * topo_node_registry_acquire ( struct TOPO_GROUPS * groups , struct TOPO_NODE * ni ) ;
void topo_node_registry_release ( struct TOPO_GROUPS * groups , struct TOPO_NODE * ni ) ;
// Освободить узел без учёта ref_count (для ошибок после deserialize, пока ref=0).
void topo_node_free_raw ( struct TOPO_GROUPS * groups , struct TOPO_NODE * ni ) ;
void topo_node_free_lists ( struct TOPO_GROUP * group , struct TOPO_NODEQ * nq ) ;
int topo_node_dyn_size ( const struct TOPOMSG_NODE * msg ) ;
int topo_node_dyn_size ( const struct TOPOMSG_NODE * msg ) ;
int topo_node_serialize ( struct TOPO_NODE * ni , struct TOPO_GROUP_NODE * nq , uint8_t * out , size_t out_max , uint16_t cumulative_rtt ) ;
// convenience accessors
static inline const struct TOPO_SOCKMETA4 * topo_v4_sock_meta ( const struct TOPO_NODE * ni ) { return ni - > v4_sock_meta ; }
static inline const struct TOPO_ADDR4 * topo_v4_addrs ( const struct TOPO_NODE * ni ) { return ni - > v4_addrs ; }
static inline const struct TOPO_SOCKMETA6 * topo_v6_sock_meta ( const struct TOPO_NODE * ni ) { return ni - > v6_sock_meta ; }
static inline const struct TOPO_ADDR6 * topo_v6_addrs ( const struct TOPO_NODE * ni ) { return ni - > v6_addrs ; }
static inline const struct TOPO_SUBNET4 * topo_v4_subnets ( const struct TOPO_NODESUBNETS * r ) { return r ? r - > v4_subnets : NULL ; }
static inline const struct TOPO_SUBNET6 * topo_v6_subnets ( const struct TOPO_NODESUBNETS * r ) { return r ? r - > v6_subnets : NULL ; }
int topo_node_serialize ( struct TOPO_GROUP * group , struct TOPO_NODEQ * nq , uint8_t * out , size_t out_max , uint16_t cumulative_rtt ) ;
int topo_node_deserialize ( struct TOPO_GROUP * group , const uint8_t * data , size_t len , struct TOPO_NODE * * out_ni , struct TOPO_NODESUBNETS * * out_subnets ,
int topo_node_deserialize ( struct TOPO_GROUP * group , const uint8_t * data , size_t len , struct TOPO_NODE * * out_ni , struct TOPO_NODESUBNETS * * out_subnets ,
struct TOPOMSG_TRANZIT * * out_tranzit , uint8_t * out_tranzit_count , uint64_t * * out_hop_list , uint8_t * out_hop_count ,
struct TOPOMSG_TRANZIT * * out_tranzit , uint8_t * out_tranzit_count , uint64_t * * out_hop_list , uint8_t * out_hop_count ,
uint16_t * out_cumulative_rtt ) ;
uint16_t * out_cumulative_rtt ) ;
int topo_group_update_my_nodeinfo ( struct UTUN_INSTANCE * instance , struct TOPO_GROUP * group ) ;
int topo_group_update_my_nodeinfo ( struct UTUN_INSTANCE * instance , struct TOPO_GROUP * group ) ;
void topo_node_dump_all ( struct TOPO_GROUP * group ) ;
void topo_node_dump_all ( struct TOPO_GROUP * group ) ;
int topo_node_format_all ( struct TOPO_GROUP * group , char * buf , size_t buf_size ) ;
int topo_node_format_all ( struct TOPO_GROUP * group , char * buf , size_t buf_size ) ;
int topo_node_ping_request_cbk ( struct TOPO_GROUPS * groups , uint64_t node_id ) ;
int topo_node_ping_request_cbk ( struct TOPO_GROUPS * groups , uint64_t node_id ) ;
void topo_node_ping_update_rtt ( struct TOPO_GROUPS * groups , uint64_t node_id , uint16_t rtt ) ;
void topo_node_ping_update_rtt ( struct TOPO_GROUPS * groups , uint64_t node_id , uint16_t rtt ) ;
static inline const struct TOPO_SOCKMETA4 * topo_v4_sock_meta ( const struct TOPO_NODE * ni ) { return ni - > v4_sock_meta ; }
static inline const struct TOPO_ADDR4 * topo_v4_addrs ( const struct TOPO_NODE * ni ) { return ni - > v4_addrs ; }
static inline const struct TOPO_SOCKMETA6 * topo_v6_sock_meta ( const struct TOPO_NODE * ni ) { return ni - > v6_sock_meta ; }
static inline const struct TOPO_ADDR6 * topo_v6_addrs ( const struct TOPO_NODE * ni ) { return ni - > v6_addrs ; }
static inline const struct TOPO_SUBNET4 * topo_v4_subnets ( const struct TOPO_NODESUBNETS * r ) { return r ? r - > v4_subnets : NULL ; }
static inline const struct TOPO_SUBNET6 * topo_v6_subnets ( const struct TOPO_NODESUBNETS * r ) { return r ? r - > v6_subnets : NULL ; }
# ifdef __cplusplus
# ifdef __cplusplus
}
}
# endif
# endif
# endif
# endif // TOPO_NODE_H