net/arp: support queue iob when arp_out failed

arp_out will replace the dev->d_iob to arp request if the iob destination
address is not exist in arp table, this mechanism cause this iob lost
result in first received ping no response or first synack retransmit.
to fix this bug, we queue the iob if arp_out failed, allocate a new
iob to send arp request, after the arp request completed, then we retry
send the queue iob packet.

Signed-off-by: wenquan1 <wenquan1@xiaomi.com>
This commit is contained in:
wenquan1
2025-09-22 16:38:23 +08:00
committed by Xiang Xiao
parent adb161aa10
commit 5b52ab13c8
6 changed files with 279 additions and 60 deletions
+112 -48
View File
@@ -675,6 +675,84 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
# define devif_poll_tcp_connections(dev, callback) (0)
#endif
/****************************************************************************
* Name: devif_poll_queue
*
* Description:
* Poll iob to send.
*
* Input Parameters:
* iobq - the iob queue to poll.
* dev - NIC Device instance.
* callback - the actual sending API provided by each NIC driver.
*
* Returned Value:
* Zero indicated the polling will continue, else stop the polling.
*
* Assumptions:
* This function is called from the MAC device driver with the network
* locked.
*
****************************************************************************/
#if defined(CONFIG_NET_ARP_SEND_QUEUE) || defined(CONFIG_NET_IPFRAG)
static int devif_poll_queue(FAR struct iob_queue_s *iobq,
FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
FAR struct iob_s *iob;
bool reused = false;
int bstop = false;
while (!bstop)
{
/* Dequeue outgoing iob from iobq */
iob = iob_remove_queue(iobq);
if (iob == NULL)
{
break;
}
/* buffer could be reused for other protocols */
reused = true;
/* Replace original iob */
netdev_iob_replace(dev, iob);
/* build L2 headers */
devif_out(dev);
/* Call back into the driver */
if (dev->d_len > 0)
{
bstop = callback(dev);
}
}
/* Notify the device driver that iob is available. */
if (iob_peek_queue(iobq) != NULL)
{
netdev_txnotify_dev(dev);
}
/* Reuse iob buffer */
if (!bstop && reused)
{
iob_update_pktlen(dev->d_iob, 0, false);
netdev_iob_prepare(dev, true, 0);
}
return bstop;
}
#endif
/****************************************************************************
* Name: devif_poll_ipfrag
*
@@ -698,56 +776,34 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
static int devif_poll_ipfrag(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
FAR struct iob_s *frag;
bool reused = false;
int bstop = false;
return devif_poll_queue(&dev->d_fragout, dev, callback);
}
#endif
while (!bstop)
{
/* Dequeue outgoing fragment from dev->d_fragout */
/****************************************************************************
* Name: devif_poll_arp
*
* Description:
* Poll all queue iobs with arp finished to send.
*
* Input Parameters:
* dev - NIC Device instance.
* callback - the actual sending API provided by each NIC driver.
*
* Returned Value:
* Zero indicated the polling will continue, else stop the polling.
*
* Assumptions:
* This function is called from the MAC device driver with the network
* locked.
*
****************************************************************************/
frag = iob_remove_queue(&dev->d_fragout);
if (frag == NULL)
{
break;
}
/* Frag buffer could be reused for other protocols */
reused = true;
/* Replace original iob */
netdev_iob_replace(dev, frag);
/* build L2 headers */
devif_out(dev);
/* Call back into the driver */
if (dev->d_len > 0)
{
bstop = callback(dev);
}
}
/* Notify the device driver that ip fragments is available. */
if (iob_peek_queue(&dev->d_fragout) != NULL)
{
netdev_txnotify_dev(dev);
}
/* Reuse iob buffer */
if (!bstop && reused)
{
iob_update_pktlen(dev->d_iob, 0, false);
netdev_iob_prepare(dev, true, 0);
}
return bstop;
#ifdef CONFIG_NET_ARP_SEND_QUEUE
static int devif_poll_arp(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
return devif_poll_queue(&dev->d_arpout, dev, callback);
}
#endif
@@ -789,6 +845,14 @@ static int devif_poll_connections(FAR struct net_driver_s *dev,
* action.
*/
#ifdef CONFIG_NET_ARP_SEND_QUEUE
bstop = devif_poll_arp(dev, callback);
if (bstop)
{
return bstop;
}
#endif
#ifdef CONFIG_NET_IPFRAG
/* Traverse all of ip fragments for available packets to transfer */