Skip to content

Commit

Permalink
net: Add timeout to various send functions
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
clamattia committed Feb 21, 2025
1 parent a94acf3 commit 394ca9b
Show file tree
Hide file tree
Showing 17 changed files with 86 additions and 32 deletions.
17 changes: 16 additions & 1 deletion include/zephyr/net/net_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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 */
Expand Down
23 changes: 22 additions & 1 deletion include/zephyr/net/net_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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
*
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/icmpv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/icmpv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/ipv4_acd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion subsys/net/ip/net_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions subsys/net/ip/net_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
16 changes: 13 additions & 3 deletions subsys/net/ip/net_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion subsys/net/ip/net_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions subsys/net/ip/net_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions subsys/net/l2/ethernet/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Check warning on line 535 in subsys/net/l2/ethernet/arp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

BLOCK_COMMENT_STYLE

subsys/net/l2/ethernet/arp.c:535 Block comments use a trailing */ on a separate line

Check warning on line 535 in subsys/net/l2/ethernet/arp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

BLOCK_COMMENT_STYLE

subsys/net/l2/ethernet/arp.c:535 Block comments use a trailing */ on a separate line
if (net_if_try_send_data(iface, pkt, K_NO_WAIT) == NET_DROP) {
net_pkt_unref(pkt);
}
}
Expand Down Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion subsys/net/l2/ethernet/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions subsys/net/l2/ethernet/ethernet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
12 changes: 6 additions & 6 deletions subsys/net/l2/ethernet/gptp/gptp_messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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");
}
Expand All @@ -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,
Expand All @@ -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);
}
4 changes: 3 additions & 1 deletion subsys/net/l2/ethernet/lldp/lldp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Check warning on line 151 in subsys/net/l2/ethernet/lldp/lldp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

BLOCK_COMMENT_STYLE

subsys/net/l2/ethernet/lldp/lldp.c:151 Block comments use a trailing */ on a separate line

Check warning on line 151 in subsys/net/l2/ethernet/lldp/lldp.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

BLOCK_COMMENT_STYLE

subsys/net/l2/ethernet/lldp/lldp.c:151 Block comments use a trailing */ on a separate line
if (net_if_try_send_data(lldp->iface, pkt, K_NO_WAIT) == NET_DROP) {
net_pkt_unref(pkt);
ret = -EIO;
}
Expand Down
2 changes: 1 addition & 1 deletion subsys/net/lib/capture/capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 394ca9b

Please sign in to comment.