mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
added more targeted routing for packet forwarding in federation (#643)
This commit is contained in:
parent
683dbc5106
commit
c8fabbdfe0
|
@ -671,6 +671,15 @@ typedef struct sn_stats {
|
|||
time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */
|
||||
} sn_stats_t;
|
||||
|
||||
typedef struct node_supernode_association {
|
||||
|
||||
n2n_mac_t mac; /* mac address of an edge */
|
||||
const struct sockaddr_in sock; /* network order socket of that edge's supernode */
|
||||
time_t last_seen; /* time mark to keep track of purging requirements */
|
||||
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} node_supernode_association_t;
|
||||
|
||||
struct sn_community {
|
||||
char community[N2N_COMMUNITY_SIZE];
|
||||
uint8_t is_federation; /* if not-zero, then the current community is the federation of supernodes */
|
||||
|
@ -679,6 +688,7 @@ struct sn_community {
|
|||
he_context_t *header_encryption_ctx; /* Header encryption cipher context. */
|
||||
he_context_t *header_iv_ctx; /* Header IV ecnryption cipher context, REMOVE as soon as seperate fields for checksum and replay protection available */
|
||||
struct peer_info *edges; /* Link list of registered edges. */
|
||||
node_supernode_association_t *assoc; /* list of other edges from this community and their supernodes */
|
||||
int64_t number_enc_packets; /* Number of encrypted packets handled so far, required for sorting from time to time */
|
||||
n2n_ip_subnet_t auto_ip_net; /* Address range of auto ip address service. */
|
||||
|
||||
|
|
193
src/sn_utils.c
193
src/sn_utils.c
|
@ -20,13 +20,6 @@
|
|||
|
||||
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
|
||||
|
||||
static int try_forward (n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
uint8_t from_supernode,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static ssize_t sendto_peer (n2n_sn_t *sss,
|
||||
const struct peer_info *peer,
|
||||
|
@ -38,14 +31,6 @@ static int sendto_mgmt (n2n_sn_t *sss,
|
|||
const uint8_t *mgmt_buf,
|
||||
size_t mgmt_size);
|
||||
|
||||
static int try_broadcast (n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
uint8_t from_supernode,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static uint16_t reg_lifetime (n2n_sn_t *sss);
|
||||
|
||||
static int update_edge (n2n_sn_t *sss,
|
||||
|
@ -81,54 +66,6 @@ static int process_udp (n2n_sn_t *sss,
|
|||
|
||||
/* ************************************** */
|
||||
|
||||
static int try_forward (n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
uint8_t from_supernode,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize) {
|
||||
|
||||
struct peer_info * scan;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
||||
HASH_FIND_PEER(comm->edges, dstMac, scan);
|
||||
|
||||
if(NULL != scan) {
|
||||
int data_sent_len;
|
||||
data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize);
|
||||
|
||||
if(data_sent_len == pktsize) {
|
||||
++(sss->stats.fwd);
|
||||
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
} else {
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(!from_supernode) {
|
||||
/* Forwarding packet to all federated supernodes. */
|
||||
traceEvent(TRACE_DEBUG, "Unknown MAC. Broadcasting packet to all federated supernodes.");
|
||||
try_broadcast(sss, NULL, cmn, sss->mac_addr, from_supernode, pktbuf, pktsize);
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "try_forward unknown MAC. Dropping the packet.");
|
||||
/* Not a known MAC so drop. */
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void close_tcp_connection(n2n_sn_t *sss, n2n_tcp_connection_t *conn) {
|
||||
|
||||
|
@ -299,9 +236,9 @@ static int try_broadcast (n2n_sn_t * sss,
|
|||
traceEvent(TRACE_DEBUG, "try_broadcast");
|
||||
|
||||
/* We have to make sure that a broadcast reaches the other supernodes and edges
|
||||
* connected to them. try_broadcast needs a from_supernode parameter: if set
|
||||
* do forward to edges of community only. If unset. forward to all locally known
|
||||
* nodes and all supernodes */
|
||||
* connected to them. try_broadcast needs a from_supernode parameter: if set,
|
||||
* do forward to edges of community only. If unset, forward to all locally known
|
||||
* nodes of community AND all supernodes associated with the community */
|
||||
|
||||
if (!from_supernode) {
|
||||
HASH_ITER(hh, sss->federation->edges, scan, tmp) {
|
||||
|
@ -356,6 +293,65 @@ static int try_broadcast (n2n_sn_t * sss,
|
|||
}
|
||||
|
||||
|
||||
static int try_forward (n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
uint8_t from_supernode,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize) {
|
||||
|
||||
struct peer_info * scan;
|
||||
node_supernode_association_t *assoc;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
||||
HASH_FIND_PEER(comm->edges, dstMac, scan);
|
||||
|
||||
if(NULL != scan) {
|
||||
int data_sent_len;
|
||||
data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize);
|
||||
|
||||
if(data_sent_len == pktsize) {
|
||||
++(sss->stats.fwd);
|
||||
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
} else {
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(!from_supernode) {
|
||||
// check if target edge is associated with a certain supernode
|
||||
HASH_FIND(hh, comm->assoc, dstMac, sizeof(n2n_mac_t), assoc);
|
||||
if(assoc) {
|
||||
traceEvent(TRACE_DEBUG, "try_forward found mac address associated with a known supernode, forwarding packet to that supernode");
|
||||
sendto_sock(sss, sss->sock,
|
||||
(const struct sockaddr*)&(assoc->sock),
|
||||
pktbuf, pktsize);
|
||||
} else {
|
||||
// forwarding packet to all federated supernodes
|
||||
traceEvent(TRACE_DEBUG, "try_forward sees unknown mac address, broadcasting packet to all federated supernodes");
|
||||
try_broadcast(sss, NULL, cmn, sss->mac_addr, from_supernode, pktbuf, pktsize);
|
||||
}
|
||||
} else {
|
||||
traceEvent(TRACE_DEBUG, "try_forward sees unknown mac address in packet from a supernode, dropping the packet");
|
||||
/* Not a known MAC so drop. */
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Initialise some fields of the community structure **/
|
||||
int comm_init (struct sn_community *comm, char *cmn) {
|
||||
|
||||
|
@ -435,6 +431,7 @@ void sn_term (n2n_sn_t *sss) {
|
|||
struct sn_community *community, *tmp;
|
||||
struct sn_community_regular_expression *re, *tmp_re;
|
||||
n2n_tcp_connection_t *conn, *tmp_conn;
|
||||
node_supernode_association_t *assoc, *tmp_assoc;
|
||||
|
||||
if(sss->sock >= 0) {
|
||||
closesocket(sss->sock);
|
||||
|
@ -465,6 +462,11 @@ void sn_term (n2n_sn_t *sss) {
|
|||
if(NULL != community->header_encryption_ctx) {
|
||||
free(community->header_encryption_ctx);
|
||||
}
|
||||
// remove all associations
|
||||
HASH_ITER(hh, community->assoc, assoc, tmp_assoc) {
|
||||
HASH_DEL(community->assoc, assoc);
|
||||
free(assoc);
|
||||
}
|
||||
HASH_DEL(sss->communities, community);
|
||||
free(community);
|
||||
}
|
||||
|
@ -484,6 +486,29 @@ void sn_term (n2n_sn_t *sss) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void update_node_supernode_association (struct sn_community *comm,
|
||||
n2n_mac_t *edgeMac, const struct sockaddr_in *sender_sock,
|
||||
time_t now) {
|
||||
|
||||
node_supernode_association_t *assoc;
|
||||
|
||||
HASH_FIND(hh, comm->assoc, edgeMac, sizeof(n2n_mac_t), assoc);
|
||||
if(!assoc) {
|
||||
// create a new association
|
||||
assoc = (node_supernode_association_t*)malloc(sizeof(node_supernode_association_t));
|
||||
if(assoc) {
|
||||
memcpy(&(assoc->mac), edgeMac, sizeof(n2n_mac_t));
|
||||
memcpy((struct sockaddr_in*)&(assoc->sock), sender_sock, sizeof(struct sockaddr_in));
|
||||
assoc->last_seen = now;
|
||||
HASH_ADD(hh, comm->assoc, mac, sizeof(n2n_mac_t), assoc);
|
||||
} else {
|
||||
// already there, update socket and time only
|
||||
memcpy((struct sockaddr_in*)&(assoc->sock), sender_sock, sizeof(struct sockaddr_in));
|
||||
assoc->last_seen = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Determine the appropriate lifetime for new registrations.
|
||||
*
|
||||
|
@ -903,8 +928,10 @@ static int purge_expired_communities (n2n_sn_t *sss,
|
|||
time_t* p_last_purge,
|
||||
time_t now) {
|
||||
|
||||
struct sn_community *comm, *tmp;
|
||||
struct sn_community *comm, *tmp_comm;
|
||||
node_supernode_association_t *assoc, *tmp_assoc;
|
||||
size_t num_reg = 0;
|
||||
size_t num_assoc = 0;
|
||||
|
||||
if((now - (*p_last_purge)) < PURGE_REGISTRATION_FREQUENCY) {
|
||||
return 0;
|
||||
|
@ -912,25 +939,42 @@ static int purge_expired_communities (n2n_sn_t *sss,
|
|||
|
||||
traceEvent(TRACE_DEBUG, "Purging old communities and edges");
|
||||
|
||||
HASH_ITER(hh, sss->communities, comm, tmp) {
|
||||
HASH_ITER(hh, sss->communities, comm, tmp_comm) {
|
||||
// federation is taken care of in re_register_and_purge_supernodes()
|
||||
if(comm->is_federation == IS_FEDERATION)
|
||||
continue;
|
||||
|
||||
// purge the community's local peers
|
||||
num_reg += purge_peer_list(&comm->edges, sss->sock, sss->tcp_connections, now - REGISTRATION_TIMEOUT);
|
||||
|
||||
// purge the community's associated peers (connected to other supernodes)
|
||||
HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) {
|
||||
if(comm->assoc->last_seen < (now - 3 * REGISTRATION_TIMEOUT)) {
|
||||
HASH_DEL(comm->assoc, assoc);
|
||||
free(assoc);
|
||||
num_assoc++;
|
||||
}
|
||||
}
|
||||
|
||||
if((comm->edges == NULL) && (comm->purgeable == COMMUNITY_PURGEABLE)) {
|
||||
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
|
||||
if(NULL != comm->header_encryption_ctx) {
|
||||
/* this should not happen as 'purgeable' and thus only communities w/o encrypted header here */
|
||||
free(comm->header_encryption_ctx);
|
||||
}
|
||||
// remove all associations
|
||||
HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) {
|
||||
HASH_DEL(comm->assoc, assoc);
|
||||
free(assoc);
|
||||
}
|
||||
HASH_DEL(sss->communities, comm);
|
||||
free(comm);
|
||||
}
|
||||
}
|
||||
(*p_last_purge) = now;
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Remove %ld edges", num_reg);
|
||||
traceEvent(TRACE_DEBUG, "purge_expired_communities removed %ld locally registered edges and %ld remotely associated edges",
|
||||
num_reg, num_assoc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1405,6 +1449,7 @@ static int process_udp (n2n_sn_t * sss,
|
|||
struct sn_community *fed;
|
||||
struct sn_community_regular_expression *re, *tmp_re;
|
||||
struct peer_info *peer, *tmp_peer, *p;
|
||||
node_supernode_association_t *assoc;
|
||||
int8_t allowed_match = -1;
|
||||
uint8_t match = 0;
|
||||
int match_length = 0;
|
||||
|
@ -1565,7 +1610,6 @@ static int process_udp (n2n_sn_t * sss,
|
|||
if(!(cmn.flags & N2N_FLAGS_SOCKET)) {
|
||||
// ... forward to all other supernodes (note try_broadcast()'s behavior with
|
||||
// NULL comm and from_supernode parameter)
|
||||
|
||||
// exception: do not forward auto ip draw
|
||||
if(!is_null_mac(reg.edgeMac)) {
|
||||
reg.sock.family = AF_INET;
|
||||
|
@ -1602,8 +1646,10 @@ static int process_udp (n2n_sn_t * sss,
|
|||
macaddr_str(mac_buf, reg.edgeMac),
|
||||
sock_to_cstr(sockbuf, &(ack.sock)));
|
||||
} else {
|
||||
// this is an edge with valid authentication registering with another supernode
|
||||
// so we can delete it here if present (can happen)
|
||||
// this is an edge with valid authentication registering with another supernode, so ...
|
||||
// 1- ... associate it with that other supernode
|
||||
update_node_supernode_association(comm, &(reg.edgeMac), sender_sock, now);
|
||||
// 2- ... we can delete it from regular list if present (can happen)
|
||||
HASH_FIND_PEER(comm->edges, reg.edgeMac, peer);
|
||||
if(peer != NULL) {
|
||||
if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) {
|
||||
|
@ -1986,6 +2032,9 @@ static int process_udp (n2n_sn_t * sss,
|
|||
HASH_FIND_PEER(comm->edges, pi.srcMac, peer);
|
||||
if(peer != NULL) {
|
||||
if((comm->is_federation == IS_NO_FEDERATION) && (!is_null_mac(pi.srcMac))) {
|
||||
// snoop on the information to use for supernode forwarding (do not wait until first remote REGISTER_SUPER)
|
||||
update_node_supernode_association(comm, &(pi.mac), sender_sock, now);
|
||||
|
||||
// this is a PEER_INFO for one of the edges conencted to this supernode, forward,
|
||||
// i.e. re-assemble (memcpy of udpbuf to encbuf could be sufficient as well)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user