net/devif/devif_callback.c: corrected the connection event list to work as FIFO instead of LIFO.

In case of enabled packet forwarding mode, packets were forwarded in a reverse order
because of LIFO behavior of the connection event list.
The issue exposed only during high network traffic. Thus the event list started to grow
that resulted in changing the order of packets inside of groups of several packets
like the following: 3, 2, 1, 6, 5, 4, 8, 7 etc.

Remarks concerning the connection event list implementation:
* Now the queue (list) is FIFO as it should be.
* The list is singly linked.
* The list has a head pointer (inside of outer net_driver_s structure),
  and a tail pointer is added into outer net_driver_s structure.
* The list item is devif_callback_s structure.
  It still has two pointers to two different list chains (*nxtconn and *nxtdev).
* As before the first argument (*dev) of the list functions can be NULL,
  while the other argument (*list) is effective (not NULL).
* An extra (*tail) argument is added to devif_callback_alloc()
  and devif_conn_callback_free() functions.
* devif_callback_alloc() time complexity is O(1) (i.e. O(n) to fill the whole list).
* devif_callback_free() time complexity is O(n) (i.e. O(n^2) to empty the whole list).
* devif_conn_event() time complexity is O(n).
This commit is contained in:
Alexander Lunev
2021-08-29 23:57:26 +03:00
committed by Xiang Xiao
parent 63a17f5cdd
commit 36fbedcbfc
23 changed files with 123 additions and 52 deletions
+4 -2
View File
@@ -330,7 +330,8 @@ void devif_callback_init(void);
FAR struct devif_callback_s *
devif_callback_alloc(FAR struct net_driver_s *dev,
FAR struct devif_callback_s **list);
FAR struct devif_callback_s **list_head,
FAR struct devif_callback_s **list_tail);
/****************************************************************************
* Name: devif_conn_callback_free
@@ -352,7 +353,8 @@ FAR struct devif_callback_s *
void devif_conn_callback_free(FAR struct net_driver_s *dev,
FAR struct devif_callback_s *cb,
FAR struct devif_callback_s **list);
FAR struct devif_callback_s **list_head,
FAR struct devif_callback_s **list_tail);
/****************************************************************************
* Name: devif_dev_callback_free
+54 -18
View File
@@ -62,7 +62,8 @@ static FAR struct devif_callback_s *g_cbfreelist = NULL;
static void devif_callback_free(FAR struct net_driver_s *dev,
FAR struct devif_callback_s *cb,
FAR struct devif_callback_s **list)
FAR struct devif_callback_s **list_head,
FAR struct devif_callback_s **list_tail)
{
FAR struct devif_callback_s *prev;
FAR struct devif_callback_s *curr;
@@ -116,11 +117,11 @@ static void devif_callback_free(FAR struct net_driver_s *dev,
* it is supposed to be in the data notification list.
*/
if (list)
if (list_head)
{
/* Find the callback structure in the connection event list */
for (prev = NULL, curr = *list;
for (prev = NULL, curr = *list_head;
curr && curr != cb;
prev = curr, curr = curr->nxtconn)
{
@@ -133,11 +134,25 @@ static void devif_callback_free(FAR struct net_driver_s *dev,
{
if (prev)
{
/* The found item to be removed is not in the head. */
prev->nxtconn = cb->nxtconn;
}
else
{
*list = cb->nxtconn;
/* The found item to be removed is in the head. */
*list_head = cb->nxtconn;
}
if (!cb->nxtconn)
{
/* If the tail item is being removed,
* update the tail pointer.
*/
DEBUGASSERT(list_tail);
*list_tail = prev;
}
}
}
@@ -235,11 +250,12 @@ void devif_callback_init(void)
FAR struct devif_callback_s *
devif_callback_alloc(FAR struct net_driver_s *dev,
FAR struct devif_callback_s **list)
FAR struct devif_callback_s **list_head,
FAR struct devif_callback_s **list_tail)
{
FAR struct devif_callback_s *ret;
/* Check the head of the free list */
/* Check the head of the free list */
net_lock();
ret = g_cbfreelist;
@@ -267,7 +283,7 @@ FAR struct devif_callback_s *
{
/* No.. release the callback structure and fail */
devif_callback_free(NULL, NULL, list);
devif_callback_free(NULL, NULL, list_head, list_tail);
net_unlock();
return NULL;
}
@@ -276,12 +292,28 @@ FAR struct devif_callback_s *
dev->d_devcb = ret;
}
/* Add the newly allocated instance to the head of the specified list */
/* Add the newly allocated instance to the tail of the specified list */
if (list)
if (list_head && list_tail)
{
ret->nxtconn = *list;
*list = ret;
ret->nxtconn = NULL;
if (*list_tail)
{
/* If the list is not empty, add the item to the tail. */
(*list_tail)->nxtconn = ret;
}
else
{
/* If the list is empty, add the first item to the list. */
*list_head = ret;
}
/* Update the tail pointer */
*list_tail = ret;
}
}
#ifdef CONFIG_DEBUG_FEATURES
@@ -315,7 +347,8 @@ FAR struct devif_callback_s *
void devif_conn_callback_free(FAR struct net_driver_s *dev,
FAR struct devif_callback_s *cb,
FAR struct devif_callback_s **list)
FAR struct devif_callback_s **list_head,
FAR struct devif_callback_s **list_tail)
{
/* Check if the device pointer is still valid. It could be invalid if, for
* example, the device were unregistered between the time when the callback
@@ -331,7 +364,7 @@ void devif_conn_callback_free(FAR struct net_driver_s *dev,
/* Then free the callback */
devif_callback_free(dev, cb, list);
devif_callback_free(dev, cb, list_head, list_tail);
}
/****************************************************************************
@@ -357,7 +390,8 @@ void devif_conn_callback_free(FAR struct net_driver_s *dev,
void devif_dev_callback_free(FAR struct net_driver_s *dev,
FAR struct devif_callback_s *cb)
{
FAR struct devif_callback_s **list;
FAR struct devif_callback_s **list_head;
FAR struct devif_callback_s **list_tail;
/* Check if the device pointer is still valid. It could be invalid if, for
* example, the device were unregistered between the time when the callback
@@ -366,23 +400,25 @@ void devif_dev_callback_free(FAR struct net_driver_s *dev,
if (dev != NULL && netdev_verify(dev))
{
/* The device reference is valid.. the use the list pointer in the
/* The device reference is valid. Then use the list pointer in the
* device structure as well.
*/
list = &dev->d_conncb;
list_head = &dev->d_conncb;
list_tail = &dev->d_conncb_tail;
}
else
{
/* The device reference is longer valid */
dev = NULL;
list = NULL;
list_head = NULL;
list_tail = NULL;
}
/* Then free the callback */
devif_callback_free(dev, cb, list);
devif_callback_free(dev, cb, list_head, list_tail);
}
/****************************************************************************