From da84bd9a39a760c4a3ababc6a1a0fcca41488194 Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Thu, 15 Jan 2026 08:16:58 +0100 Subject: [PATCH 1/2] Remove packet copy when transmitting CSP packets Credits to @MErdbruegger for suggesting this improvement. --- src/csp_io.c | 148 +++++++++++++++++++++++++++------------------------ 1 file changed, 77 insertions(+), 71 deletions(-) diff --git a/src/csp_io.c b/src/csp_io.c index 70c160d43..2c7bd0571 100644 --- a/src/csp_io.c +++ b/src/csp_io.c @@ -90,63 +90,84 @@ void csp_id_clear(csp_id_t * target) { target->flags = 0; } +static int is_same_subnet(csp_iface_t * iface, csp_iface_t * routed_from) { + + /* This check is is similar to that below, but faster */ + if (iface == routed_from) { + return 1; + } + + /* Do not send to interface with similar subnet (split horizon) */ + if (csp_iflist_is_within_subnet(iface->addr, routed_from)) { + return 1; + } + + return 0; +} + +static void convert_broadcast(csp_id_t * idout, csp_id_t * idout_copy, csp_iface_t * snd_iface) { + + /* Rewrite routed brodcast (L3) to local (L2) when arriving at the interface */ + if (csp_id_is_broadcast(idout->dst, snd_iface)) { + idout_copy->dst = csp_id_get_max_nodeid(); + } +} + +static void send_packet(csp_id_t * idout_copy, csp_packet_t * snd_pkt, csp_iface_t * snd_iface, uint16_t via, int from_me) { + + /* Apply outgoing interface address to packet */ + if ((from_me) && (idout_copy->src == 0)) { + idout_copy->src = snd_iface->addr; + } + + if (snd_pkt != NULL) { + csp_send_direct_iface(idout_copy, snd_pkt, snd_iface, via, from_me); + } +} + void csp_send_direct(csp_id_t* idout, csp_packet_t * packet, csp_iface_t * routed_from) { int from_me = (routed_from == NULL ? 1 : 0); - - /* Try to find the destination on any local subnets */ int via = CSP_NO_VIA_ADDRESS; - csp_iface_t * iface = NULL; - csp_packet_t * copy = NULL; - int local_found = 0; /* Quickly send on loopback */ - if(idout->dst == csp_if_lo.addr){ + if (idout->dst == csp_if_lo.addr) { csp_send_direct_iface(idout, packet, &csp_if_lo, via, from_me); return; } - /* Make copy as broadcast modifies destination making iflist_get_by_subnet the skip next redundant ifaces */ - csp_id_t _idout = *idout; + csp_id_t idout_copy = *idout; /* Broadcast function procedure modifies destination */ + csp_iface_t * iface = NULL; /* Interface iterator */ + csp_iface_t * next_iface = NULL; /* Reference to keep track of packet copying */ + /* Try to find the destination on any local subnets */ + int local_found = 0; while ((iface = csp_iflist_get_by_subnet(idout->dst, iface)) != NULL) { local_found = 1; - /* Do not send back to same interface (split horizon) - * This check is is similar to that below, but faster */ - if (iface == routed_from) { - continue; - } - - /* Do not send to interface with similar subnet (split horizon) */ - if (csp_iflist_is_within_subnet(iface->addr, routed_from)) { + /* Do not send back to same inteface (split horizon) */ + if (is_same_subnet(iface, routed_from)) { continue; } - /* Apply outgoing interface address to packet */ - if (from_me && (idout->src == 0)) { - _idout.src = iface->addr; - } - - /* Rewrite routed broadcast (L3) to local (L2) when arriving at the interface */ - if (csp_id_is_broadcast(idout->dst, iface)) { - _idout.dst = csp_id_get_max_nodeid(); - } + if (next_iface != NULL) { + csp_packet_t * copy = csp_buffer_clone(packet); - /* Todo: Find an elegant way to avoid making a copy when only a single destination interface - * is found. But without looping the list twice. And without using stack memory. - * Is this even possible? */ - copy = csp_buffer_clone(packet); - if (copy != NULL) { - csp_send_direct_iface(&_idout, copy, iface, via, from_me); + convert_broadcast(idout, &idout_copy, next_iface); + send_packet(&idout_copy, copy, next_iface, via, from_me); } - + next_iface = iface; } - /* If the above worked, we don't want to look at the routing table */ - if (local_found == 1) { - csp_buffer_free(packet); + if (local_found) { + if (next_iface != NULL) { + convert_broadcast(idout, &idout_copy, next_iface); + send_packet(&idout_copy, packet, next_iface, via, from_me); + } else { + csp_buffer_free(packet); + } + /* If a match was found, we don't want to look at the routing table */ return; } @@ -158,32 +179,27 @@ void csp_send_direct(csp_id_t* idout, csp_packet_t * packet, csp_iface_t * route do { route_found = 1; - /* Do not send back to same interface (split horizon) - * This check is is similar to that below, but faster */ - if (route->iface == routed_from) { - continue; - } - - /* Do not send to interface with similar subnet (split horizon) */ - if (csp_iflist_is_within_subnet(route->iface->addr, routed_from)) { + /* Do not send back to same inteface (split horizon) */ + if (is_same_subnet(route->iface, routed_from)) { continue; } - /* Apply outgoing interface address to packet */ - if (from_me && (idout->src == 0)) { - idout->src = route->iface->addr; - } - - copy = csp_buffer_clone(packet); - if (copy != NULL) { - csp_send_direct_iface(idout, copy, route->iface, route->via, from_me); + if (next_iface != NULL) { + csp_packet_t * copy = csp_buffer_clone(packet); + send_packet(&idout_copy, copy, next_iface, via, from_me); } + next_iface = route->iface; + via = route->via; } while ((route = csp_rtable_search_backward(route)) != NULL); } /* If the above worked, we don't want to look at default interfaces */ if (route_found == 1) { - csp_buffer_free(packet); + if (next_iface != NULL) { + send_packet(&idout_copy, packet, next_iface, via, from_me); + } else { + csp_buffer_free(packet); + } return; } @@ -192,30 +208,20 @@ void csp_send_direct(csp_id_t* idout, csp_packet_t * packet, csp_iface_t * route /* Try to send via default interfaces */ while ((iface = csp_iflist_get_by_isdfl(iface)) != NULL) { - /* Do not send back to same interface (split horizon) - * This check is is similar to that below, but faster */ - if (iface == routed_from) { - continue; - } - - /* Do not send to interface with similar subnet (split horizon) */ - if (csp_iflist_is_within_subnet(iface->addr, routed_from)) { + if (is_same_subnet(iface, routed_from)) { continue; } - /* Apply outgoing interface address to packet */ - if (from_me && (idout->src == 0)) { - idout->src = iface->addr; - } - - /* Todo: Find an elegant way to avoid making a copy when only a single destination interface - * is found. But without looping the list twice. And without using stack memory. - * Is this even possible? */ - copy = csp_buffer_clone(packet); - if (copy != NULL) { - csp_send_direct_iface(idout, copy, iface, via, from_me); + if (next_iface != NULL) { + csp_packet_t * copy = csp_buffer_clone(packet); + send_packet(&idout_copy, copy, next_iface, via, from_me); } + next_iface = iface; + } + if (next_iface != NULL) { + send_packet(&idout_copy, packet, next_iface, via, from_me); + return; } csp_buffer_free(packet); From c96fb4ec1efeef2270051d4f1c0c902887e4e994 Mon Sep 17 00:00:00 2001 From: Johan de Claville Christiansen Date: Mon, 16 Feb 2026 18:12:01 +0100 Subject: [PATCH 2/2] inlined helper function and fix a few spellings --- src/csp_io.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/csp_io.c b/src/csp_io.c index 2c7bd0571..38c2b6911 100644 --- a/src/csp_io.c +++ b/src/csp_io.c @@ -90,7 +90,7 @@ void csp_id_clear(csp_id_t * target) { target->flags = 0; } -static int is_same_subnet(csp_iface_t * iface, csp_iface_t * routed_from) { +static inline int is_same_subnet(csp_iface_t * iface, csp_iface_t * routed_from) { /* This check is is similar to that below, but faster */ if (iface == routed_from) { @@ -105,15 +105,15 @@ static int is_same_subnet(csp_iface_t * iface, csp_iface_t * routed_from) { return 0; } -static void convert_broadcast(csp_id_t * idout, csp_id_t * idout_copy, csp_iface_t * snd_iface) { +static inline void convert_broadcast(csp_id_t * idout, csp_id_t * idout_copy, csp_iface_t * snd_iface) { - /* Rewrite routed brodcast (L3) to local (L2) when arriving at the interface */ + /* Rewrite routed broadcast (L3) to local (L2) when arriving at the interface */ if (csp_id_is_broadcast(idout->dst, snd_iface)) { idout_copy->dst = csp_id_get_max_nodeid(); } } -static void send_packet(csp_id_t * idout_copy, csp_packet_t * snd_pkt, csp_iface_t * snd_iface, uint16_t via, int from_me) { +static inline void send_packet(csp_id_t * idout_copy, csp_packet_t * snd_pkt, csp_iface_t * snd_iface, uint16_t via, int from_me) { /* Apply outgoing interface address to packet */ if ((from_me) && (idout_copy->src == 0)) { @@ -146,7 +146,7 @@ void csp_send_direct(csp_id_t* idout, csp_packet_t * packet, csp_iface_t * route local_found = 1; - /* Do not send back to same inteface (split horizon) */ + /* Do not send back to same interface (split horizon) */ if (is_same_subnet(iface, routed_from)) { continue; } @@ -179,7 +179,7 @@ void csp_send_direct(csp_id_t* idout, csp_packet_t * packet, csp_iface_t * route do { route_found = 1; - /* Do not send back to same inteface (split horizon) */ + /* Do not send back to same interface (split horizon) */ if (is_same_subnet(route->iface, routed_from)) { continue; }