From 394ca9bb707bbcccaf01db065c5b393e42f3c7a6 Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Fri, 21 Feb 2025 09:08:02 +0100 Subject: [PATCH] net: Add timeout to various send functions Timeout can be used to early drop some request for arp and icmp to avoid being slowed when in a flood situation. Signed-off-by: Cla Mattia Galliard --- include/zephyr/net/net_core.h | 17 ++++++++++++++- include/zephyr/net/net_if.h | 23 ++++++++++++++++++++- subsys/net/ip/icmp.c | 4 ++-- subsys/net/ip/icmpv4.c | 4 ++-- subsys/net/ip/icmpv6.c | 4 ++-- subsys/net/ip/ipv4_acd.c | 4 ++-- subsys/net/ip/net_context.c | 2 +- subsys/net/ip/net_core.c | 8 +++++-- subsys/net/ip/net_if.c | 16 +++++++++++--- subsys/net/ip/net_private.h | 2 +- subsys/net/ip/net_tc.c | 4 ++-- subsys/net/l2/ethernet/arp.c | 6 ++++-- subsys/net/l2/ethernet/bridge.c | 2 +- subsys/net/l2/ethernet/ethernet.c | 4 ++-- subsys/net/l2/ethernet/gptp/gptp_messages.c | 12 +++++------ subsys/net/l2/ethernet/lldp/lldp.c | 4 +++- subsys/net/lib/capture/capture.c | 2 +- 17 files changed, 86 insertions(+), 32 deletions(-) diff --git a/include/zephyr/net/net_core.h b/include/zephyr/net/net_core.h index 7cd9a1cb15f0..62eaa09de6bf 100644 --- a/include/zephyr/net/net_core.h +++ b/include/zephyr/net/net_core.h @@ -128,7 +128,7 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt); * * @details Send data to network. This should not be used normally by * applications as it requires that the network packet is properly - * constructed. + * constructed. Equivalent to net_try_send_data with infinite timeout. * * @param pkt Network packet. * @@ -137,6 +137,21 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt); */ int net_send_data(struct net_pkt *pkt); +/** + * @brief Try sending data to network. + * + * @details Send data to network. This should not be used normally by + * applications as it requires that the network packet is properly + * constructed. + * + * @param pkt Network packet. + * @param timeout Timeout for send. + * + * @return 0 if ok, <0 if error. If <0 is returned, then the caller needs + * to unref the pkt in order to avoid memory leak. + */ +int net_try_send_data(struct net_pkt *pkt, k_timeout timeout) + /** @cond INTERNAL_HIDDEN */ /* Some helper defines for traffic class support */ diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index c8cbd4496aed..4460db65f11c 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -914,13 +914,25 @@ static inline enum net_if_oper_state net_if_oper_state(struct net_if *iface) /** * @brief Send a packet through a net iface * + * This is equivalent to net_if_try_queue_tx with an infinite timeout * @param iface Pointer to a network interface structure * @param pkt Pointer to a net packet to send * - * return verdict about the packet + * @return verdict about the packet */ enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt); +/** + * @brief Try sending a packet through a net iface + * + * @param iface Pointer to a network interface structure + * @param pkt Pointer to a net packet to send + * @param timeout timeout for attempting to send + * + * @return verdict about the packet + */ +enum net_verdict net_if_try_send_data(struct net_if *iface, struct net_pkt *pkt, k_timeout timeout); + /** * @brief Get a pointer to the interface L2 * @@ -982,11 +994,20 @@ static inline const struct device *net_if_get_device(struct net_if *iface) /** * @brief Queue a packet to the net interface TX queue * + * This is equivalent to net_if_try_queue_tx with an infinite timeout * @param iface Pointer to a network interface structure * @param pkt Pointer to a net packet to queue */ void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt); +/** + * @brief Try enqueuing a packet to the net interface TX queue + * + * @param iface Pointer to a network interface structure + * @param pkt Pointer to a net packet to queue + */ +void net_if_try_queue_tx(struct net_if *iface, struct net_pkt *pkt, k_timeout timeout); + /** * @brief Return the IP offload status * diff --git a/subsys/net/ip/icmp.c b/subsys/net/ip/icmp.c index e8553726271e..12d2f0229128 100644 --- a/subsys/net/ip/icmp.c +++ b/subsys/net/ip/icmp.c @@ -207,7 +207,7 @@ static int send_icmpv4_echo_request(struct net_icmp_ctx *ctx, ctx->user_data = user_data; ctx->iface = iface; - if (net_send_data(pkt) >= 0) { + if (net_try_send_data(pkt, K_NO_WAIT) >= 0) { net_stats_update_icmp_sent(iface); return 0; } @@ -330,7 +330,7 @@ static int send_icmpv6_echo_request(struct net_icmp_ctx *ctx, ctx->user_data = user_data; ctx->iface = iface; - if (net_send_data(pkt) >= 0) { + if (net_try_send_data(pkt, K_NO_WAIT) >= 0) { net_stats_update_icmp_sent(iface); return 0; } diff --git a/subsys/net/ip/icmpv4.c b/subsys/net/ip/icmpv4.c index cc25e572dd4c..3d616bf15b61 100644 --- a/subsys/net/ip/icmpv4.c +++ b/subsys/net/ip/icmpv4.c @@ -493,7 +493,7 @@ static int icmpv4_handle_echo_request(struct net_icmp_ctx *ctx, net_sprint_ipv4_addr(src), net_sprint_ipv4_addr(&ip_hdr->src)); - if (net_send_data(reply) < 0) { + if (net_try_send_data(reply, K_NO_WAIT) < 0) { goto drop; } @@ -588,7 +588,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, uint8_t type, uint8_t code) net_sprint_ipv4_addr(&ip_hdr->dst), net_sprint_ipv4_addr(&ip_hdr->src)); - if (net_send_data(pkt) >= 0) { + if (net_try_send_data(pkt, K_NO_WAIT) >= 0) { net_stats_update_icmp_sent(net_pkt_iface(orig)); return 0; } diff --git a/subsys/net/ip/icmpv6.c b/subsys/net/ip/icmpv6.c index 048521e1c12b..1fd712940386 100644 --- a/subsys/net/ip/icmpv6.c +++ b/subsys/net/ip/icmpv6.c @@ -169,7 +169,7 @@ static int icmpv6_handle_echo_request(struct net_icmp_ctx *ctx, net_sprint_ipv6_addr(src), net_sprint_ipv6_addr(&ip_hdr->src)); - if (net_send_data(reply) < 0) { + if (net_try_send_data(reply, K_NO_WAIT) < 0) { goto drop; } @@ -319,7 +319,7 @@ int net_icmpv6_send_error(struct net_pkt *orig, uint8_t type, uint8_t code, net_sprint_ipv6_addr(src), net_sprint_ipv6_addr(&ip_hdr->src)); - if (net_send_data(pkt) >= 0) { + if (net_try_send_data(pkt, K_NO_WAIT) >= 0) { net_stats_update_icmp_sent(net_pkt_iface(pkt)); return 0; } diff --git a/subsys/net/ip/ipv4_acd.c b/subsys/net/ip/ipv4_acd.c index 3cb1d2c6f952..cb787aca950d 100644 --- a/subsys/net/ip/ipv4_acd.c +++ b/subsys/net/ip/ipv4_acd.c @@ -103,7 +103,7 @@ static void ipv4_acd_send_probe(struct net_if_addr *ifaddr) return; } - if (net_if_send_data(iface, pkt) == NET_DROP) { + if (net_if_try_send_data(iface, pkt, K_FOREVER) == NET_DROP) { net_pkt_unref(pkt); } } @@ -120,7 +120,7 @@ static void ipv4_acd_send_announcement(struct net_if_addr *ifaddr) return; } - if (net_if_send_data(iface, pkt) == NET_DROP) { + if (net_if_try_send_data(iface, pkt, K_FOREVER) == NET_DROP) { net_pkt_unref(pkt); } } diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 1edbea992ab3..f5ece03cb5d5 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -2609,7 +2609,7 @@ static int context_sendto(struct net_context *context, net_pkt_set_ll_proto_type(pkt, ntohs(ll_dst_addr->sll_protocol)); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, timeout); } } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN && net_context_get_proto(context) == CAN_RAW) { diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 4c22e10f35a2..eb6a0901dd28 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -363,8 +363,12 @@ static inline int check_ip(struct net_pkt *pkt) return ret; } -/* Called when data needs to be sent to network */ int net_send_data(struct net_pkt *pkt) +{ + return net_try_send_data(pkt, K_FOREVER); +} + +int net_try_send_data(struct net_pkt *pkt, k_timeout timeout) { int status; int ret; @@ -407,7 +411,7 @@ int net_send_data(struct net_pkt *pkt) goto err; } - if (net_if_send_data(net_pkt_iface(pkt), pkt) == NET_DROP) { + if (net_if_try_send_data(net_pkt_iface(pkt), pkt, timeout) == NET_DROP) { ret = -EIO; goto err; } diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 53ff75ec4a62..85df1e1b10cc 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -343,6 +343,11 @@ void net_process_tx_packet(struct net_pkt *pkt) } void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt) +{ + net_if_try_queue_tx(iface, pkt, K_FOREVER); +} + +void net_if_try_queue_tx(struct net_if *iface, struct net_pkt *pkt, k_timeout timeout) { if (!net_pkt_filter_send_ok(pkt)) { /* silently drop the packet */ @@ -368,7 +373,7 @@ void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt) net_if_tx(net_pkt_iface(pkt), pkt); } else { - if (net_tc_submit_to_tx_queue(tc, pkt) != NET_OK) { + if (net_tc_try_submit_to_tx_queue(tc, pkt, timeout) != NET_OK) { goto drop; } #if defined(CONFIG_NET_POWER_MANAGEMENT) @@ -451,7 +456,12 @@ static inline void init_iface(struct net_if *iface) } #if defined(CONFIG_NET_NATIVE) -enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt) +enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt, k_timeout timeout) +{ + return net_if_try_send_data(iface, pkt, K_FOREVER); +} + +enum net_verdict net_if_try_send_data(struct net_if *iface, struct net_pkt *pkt, k_timeout timeout) { const struct net_l2 *l2; struct net_context *context = net_pkt_context(pkt); @@ -550,7 +560,7 @@ enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt) } } else if (verdict == NET_OK) { /* Packet is ready to be sent by L2, let's queue */ - net_if_queue_tx(iface, pkt); + net_if_try_queue_tx(iface, pkt, timeout); } return verdict; diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index ee71d2bb75ec..36e473e0a503 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -203,7 +203,7 @@ static inline enum net_verdict net_ipv6_input(struct net_pkt *pkt, static inline void net_tc_tx_init(void) { } static inline void net_tc_rx_init(void) { } #endif -extern enum net_verdict net_tc_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt); +enum net_verdict net_tc_try_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt, k_timeout timeout); extern enum net_verdict net_tc_submit_to_rx_queue(uint8_t tc, struct net_pkt *pkt); extern enum net_verdict net_promisc_mode_input(struct net_pkt *pkt); diff --git a/subsys/net/ip/net_tc.c b/subsys/net/ip/net_tc.c index 8846ab15cc8c..ac8aea055411 100644 --- a/subsys/net/ip/net_tc.c +++ b/subsys/net/ip/net_tc.c @@ -65,13 +65,13 @@ static struct net_traffic_class tx_classes[NET_TC_TX_COUNT]; static struct net_traffic_class rx_classes[NET_TC_RX_COUNT]; #endif -enum net_verdict net_tc_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt) +enum net_verdict net_tc_try_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt, k_timeout timeout) { #if NET_TC_TX_COUNT > 0 net_pkt_set_tx_stats_tick(pkt, k_cycle_get_32()); #if NET_TC_TX_EFFECTIVE_COUNT > 1 - if (k_sem_take(&tx_classes[tc].fifo_slot, K_FOREVER) != 0) { + if (k_sem_take(&tx_classes[tc].fifo_slot, timeout) != 0) { return NET_DROP; } #endif diff --git a/subsys/net/l2/ethernet/arp.c b/subsys/net/l2/ethernet/arp.c index 964dd9e3eda9..79a230b8d107 100644 --- a/subsys/net/l2/ethernet/arp.c +++ b/subsys/net/l2/ethernet/arp.c @@ -531,7 +531,9 @@ static void arp_gratuitous_send(struct net_if *iface, NET_DBG("Sending gratuitous ARP pkt %p", pkt); - if (net_if_send_data(iface, pkt) == NET_DROP) { + /* send without timeout, so we do not risk being blocked by tx when + * being flooded */ + if (net_if_try_send_data(iface, pkt, K_NO_WAIT) == NET_DROP) { net_pkt_unref(pkt); } } @@ -874,7 +876,7 @@ enum net_verdict net_arp_input(struct net_pkt *pkt, /* Send reply */ reply = arp_prepare_reply(net_pkt_iface(pkt), pkt, dst_hw_addr); if (reply) { - net_if_queue_tx(net_pkt_iface(reply), reply); + net_if_try_queue_tx(net_pkt_iface(reply), reply, K_NO_WAIT); } else { NET_DBG("Cannot send ARP reply"); } diff --git a/subsys/net/l2/ethernet/bridge.c b/subsys/net/l2/ethernet/bridge.c index 4b883643c3a3..4e43117b6746 100644 --- a/subsys/net/l2/ethernet/bridge.c +++ b/subsys/net/l2/ethernet/bridge.c @@ -384,7 +384,7 @@ static enum net_verdict bridge_iface_process(struct net_if *iface, net_pkt_set_family(send_pkt, AF_UNSPEC); net_pkt_set_iface(send_pkt, ctx->eth_iface[i]); - net_if_queue_tx(ctx->eth_iface[i], send_pkt); + net_if_try_queue_tx(ctx->eth_iface[i], send_pkt, K_FOREVER); NET_DBG("%s iface %d pkt %p (ref %d)", is_send ? "Send" : "Recv", diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index 88f3bc824b9e..97f68d4d0c6c 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -281,7 +281,7 @@ static enum net_verdict ethernet_recv(struct net_if *iface, out_pkt, pkt, net_if_get_by_iface(bridge), net_if_get_by_iface(iface)); - (void)net_if_queue_tx(bridge, out_pkt); + (void)net_if_try_queue_tx(bridge, out_pkt, K_FOREVER); } type = ntohs(hdr->type); @@ -788,7 +788,7 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) out_pkt, pkt, net_if_get_by_iface(bridge), net_if_get_by_iface(iface)); - (void)net_if_queue_tx(bridge, out_pkt); + (void)net_if_try_queue_tx(bridge, out_pkt, K_FOREVER); } ret = net_l2_send(api->send, net_if_get_device(iface), iface, pkt); diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index 7fc5c75b73fd..1bfac947a48f 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -826,7 +826,7 @@ void gptp_send_sync(int port, struct net_pkt *pkt) NET_GPTP_INFO("SYNC", pkt); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, K_FOREVER); } void gptp_send_follow_up(int port, struct net_pkt *pkt) @@ -835,7 +835,7 @@ void gptp_send_follow_up(int port, struct net_pkt *pkt) NET_GPTP_INFO("FOLLOWUP", pkt); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, K_FOREVER); } void gptp_send_announce(int port, struct net_pkt *pkt) @@ -844,7 +844,7 @@ void gptp_send_announce(int port, struct net_pkt *pkt) NET_GPTP_INFO("ANNOUNCE", pkt); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, K_FOREVER); } void gptp_send_pdelay_req(int port) @@ -871,7 +871,7 @@ void gptp_send_pdelay_req(int port) NET_GPTP_INFO("PDELAY_REQ", pkt); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, K_FOREVER); } else { NET_ERR("Failed to prepare %s", "PDELAY_REQ"); } @@ -897,7 +897,7 @@ void gptp_send_pdelay_resp(int port, struct net_pkt *pkt, NET_GPTP_INFO("PDELAY_RESP", pkt); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, K_FOREVER); } void gptp_send_pdelay_follow_up(int port, struct net_pkt *pkt, @@ -920,5 +920,5 @@ void gptp_send_pdelay_follow_up(int port, struct net_pkt *pkt, NET_GPTP_INFO("PDELAY_FOLLOWUP", pkt); - net_if_queue_tx(net_pkt_iface(pkt), pkt); + net_if_try_queue_tx(net_pkt_iface(pkt), pkt, K_FOREVER); } diff --git a/subsys/net/l2/ethernet/lldp/lldp.c b/subsys/net/l2/ethernet/lldp/lldp.c index da179f728236..17ad6ba8b0ae 100644 --- a/subsys/net/l2/ethernet/lldp/lldp.c +++ b/subsys/net/l2/ethernet/lldp/lldp.c @@ -147,7 +147,9 @@ static int lldp_send(struct ethernet_lldp *lldp) net_pkt_lladdr_dst(pkt)->addr = (uint8_t *)lldp_multicast_eth_addr.addr; net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_eth_addr); - if (net_if_send_data(lldp->iface, pkt) == NET_DROP) { + /* send without timeout, so we do not risk being blocked by tx when + * being flooded */ + if (net_if_try_send_data(lldp->iface, pkt, K_NO_WAIT) == NET_DROP) { net_pkt_unref(pkt); ret = -EIO; } diff --git a/subsys/net/lib/capture/capture.c b/subsys/net/lib/capture/capture.c index 122096c96fcb..eaf70f2a7c51 100644 --- a/subsys/net/lib/capture/capture.c +++ b/subsys/net/lib/capture/capture.c @@ -707,7 +707,7 @@ static int capture_send(const struct device *dev, struct net_if *iface, net_pkt_cursor_init(pkt); - verdict = net_if_send_data(ctx->tunnel_iface, pkt); + verdict = net_if_try_send_data(ctx->tunnel_iface, pkt, K_FOREVER); if (verdict == NET_DROP) { ret = -EIO; }