Skip to content

Commit 9abe2d1

Browse files
evpopovEmil Popovtony-josi-aws
authored
Changes the ND cache full behavior when the Neighbor Discovery cache fills up. (#1040)
* Changes the ND cache full behavior: If the Neighbor Discovery cache ever gets full, trying to store a new entry will overwrite the oldest existing entry. * Adds casting to avoid warnings --------- Co-authored-by: Emil Popov <[email protected]> Co-authored-by: Tony Josi <[email protected]>
1 parent c8d9b70 commit 9abe2d1

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

source/FreeRTOS_ND.c

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@
285285
{
286286
BaseType_t x;
287287
BaseType_t xFreeEntry = -1, xEntryFound = -1;
288+
BaseType_t xOldestValue = ipconfigMAX_ARP_AGE + 1;
289+
BaseType_t xOldestEntry = 0;
288290

289291
/* For each entry in the ND cache table. */
290292
for( x = 0; x < ipconfigND_CACHE_ENTRIES; x++ )
@@ -304,29 +306,45 @@
304306
else
305307
{
306308
/* Entry is valid but the IP-address doesn't match. */
309+
310+
/* Keep track of the oldest entry in case we need to overwrite it. The problem we are trying to avoid is
311+
* that there may be a queued packet in pxARPWaitingNetworkBuffer and we may have just received the
312+
* neighbor advertisement needed for that packet. If we don't store this network advertisement in cache,
313+
* the parting of the frame from pxARPWaitingNetworkBuffer will cause the sending of neighbor solicitation
314+
* and stores the frame in pxARPWaitingNetworkBuffer. This becomes a vicious circle with thousands of
315+
* neighbor solicitation/advertisement packets going back and forth because the ND cache is full.
316+
* Overwriting the oldest cache entry is not a fool-proof solution, but it's something. */
317+
if( xNDCache[ x ].ucAge < xOldestValue )
318+
{
319+
xOldestValue = xNDCache[ x ].ucAge;
320+
xOldestEntry = x;
321+
}
307322
}
308323
}
309324

310325
if( xEntryFound < 0 )
311326
{
312327
/* The IP-address was not found, use the first free location. */
313-
xEntryFound = xFreeEntry;
328+
if( xFreeEntry >= 0 )
329+
{
330+
xEntryFound = xFreeEntry;
331+
}
332+
else
333+
{
334+
/* No free location. Overwrite the oldest. */
335+
xEntryFound = xOldestEntry;
336+
FreeRTOS_printf( ( "vNDRefreshCacheEntry: Cache FULL! Overwriting oldest entry %i with %02X-%02X-%02X-%02X-%02X-%02X\n", ( int ) xEntryFound, pxMACAddress->ucBytes[ 0 ], pxMACAddress->ucBytes[ 1 ], pxMACAddress->ucBytes[ 2 ], pxMACAddress->ucBytes[ 3 ], pxMACAddress->ucBytes[ 4 ], pxMACAddress->ucBytes[ 5 ] ) );
337+
}
314338
}
315339

316-
if( xEntryFound >= 0 )
317-
{
318-
/* Copy the IP-address. */
319-
( void ) memcpy( xNDCache[ xEntryFound ].xIPAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
320-
/* Copy the MAC-address. */
321-
( void ) memcpy( xNDCache[ xEntryFound ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( MACAddress_t ) );
322-
xNDCache[ xEntryFound ].pxEndPoint = pxEndPoint;
323-
xNDCache[ xEntryFound ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
324-
xNDCache[ xEntryFound ].ucValid = ( uint8_t ) pdTRUE;
325-
}
326-
else
327-
{
328-
FreeRTOS_printf( ( "vNDRefreshCacheEntry: %pip not found\n", ( void * ) pxIPAddress->ucBytes ) );
329-
}
340+
/* At this point, xEntryFound is always a valid index. */
341+
/* Copy the IP-address. */
342+
( void ) memcpy( xNDCache[ xEntryFound ].xIPAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
343+
/* Copy the MAC-address. */
344+
( void ) memcpy( xNDCache[ xEntryFound ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( MACAddress_t ) );
345+
xNDCache[ xEntryFound ].pxEndPoint = pxEndPoint;
346+
xNDCache[ xEntryFound ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
347+
xNDCache[ xEntryFound ].ucValid = ( uint8_t ) pdTRUE;
330348
}
331349
/*-----------------------------------------------------------*/
332350

@@ -482,7 +500,7 @@
482500
char pcBuffer[ 40 ];
483501

484502
/* Loop through each entry in the ND cache. */
485-
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
503+
for( x = 0; x < ipconfigND_CACHE_ENTRIES; x++ )
486504
{
487505
if( xNDCache[ x ].ucValid != ( uint8_t ) 0U )
488506
{

0 commit comments

Comments
 (0)