src/core/net/ip6_mpl.cpp
Error Mpl::UpdateSeedSet(uint16_t aSeedId, uint8_t aSequence)
{
    Error      error    = kErrorNone;
    SeedEntry *insert   = nullptr;
    SeedEntry *group    = mSeedSet;
    SeedEntry *evict    = mSeedSet;
    uint8_t    curCount = 0;
    uint8_t    maxCount = 0;

    for (uint32_t i = 0; i < kNumSeedEntries; i++, curCount++)
    {
        if (mSeedSet[i].mLifetime == 0)
        {
            // unused entries exist

            if (insert == nullptr)
            {
                // no existing group, set insert and evict entry to be the same
                insert = &mSeedSet[i];
            }

            // mark first unused entry for eviction
            evict = &mSeedSet[i];
            break;
        }

        if (mSeedSet[i].mSeedId != group->mSeedId)
        {
            // processing new group

            if (aSeedId == group->mSeedId && insert == nullptr)
            {
                // insert at end of existing group
                insert = &mSeedSet[i];
                curCount++;
            }

            if (maxCount < curCount)
            {
                // look to evict an entry from the seed with the most entries
                evict    = group;
                maxCount = curCount;
            }

            group    = &mSeedSet[i];
            curCount = 0;
        }

        if (aSeedId == mSeedSet[i].mSeedId)
        {
            // have existing entries for aSeedId

            int8_t diff = static_cast<int8_t>(aSequence - mSeedSet[i].mSequence);

            if (diff == 0)
            {
                // already received, drop message
                ExitNow(error = kErrorDrop);
            }
            else if (insert == nullptr && diff < 0)
            {
                // insert in order of sequence
                insert = &mSeedSet[i];
                curCount++;
            }
        }
    }

    if (evict->mLifetime != 0)
    {
        // no free entries available, look to evict an existing entry
        OT_ASSERT(curCount != 0);

        if (aSeedId == group->mSeedId && insert == nullptr)
        {
            // insert at end of existing group
            insert = &mSeedSet[kNumSeedEntries];
            curCount++;
        }

        if (maxCount < curCount)
        {
            // look to evict an entry from the seed with the most entries
            evict    = group;
            maxCount = curCount;
        }

        // require evict group size to have >= 2 entries
        VerifyOrExit(maxCount > 1, error = kErrorDrop);

        if (insert == nullptr)
        {
            // no existing entries for aSeedId
            insert = evict;
        }
        else
        {
            // require Sequence to be larger than oldest stored Sequence in group
            VerifyOrExit(insert > mSeedSet && aSeedId == (insert - 1)->mSeedId, error = kErrorDrop);
        }
    }

    if (evict > insert)
    {
        OT_ASSERT(insert >= mSeedSet);
        memmove(insert + 1, insert, static_cast<size_t>(evict - insert) * sizeof(SeedEntry));
    }
    else if (evict < insert)
    {
        OT_ASSERT(evict >= mSeedSet);
        memmove(evict, evict + 1, static_cast<size_t>(insert - 1 - evict) * sizeof(SeedEntry));
        insert--;
    }

    insert->mSeedId   = aSeedId;
    insert->mSequence = aSequence;
    insert->mLifetime = kSeedEntryLifetime;

    if (!mSeedSetTimer.IsRunning())
    {
        mSeedSetTimer.Start(kSeedEntryLifetimeDt);
    }

exit:
    return error;
}
/*
 * mSeedSet stores recently received (Seed ID, Sequence) values.
 * - (Seed ID, Sequence) values are grouped by Seed ID.
 * - (Seed ID, Sequence) groups are not sorted by Seed ID relative to other groups.
 * - (Seed ID, Sequence) values within a group are sorted by Sequence.
 * - All unused entries (marked by 0 lifetime) are grouped at the end.
 *
 * Update process:
 *
 * - Eviction selection:
 *   - If there are unused entries, mark the first unused entry for "eviction"
 *   - Otherwise, pick the first entry of the group that has the most entries.
 *
 * - Insert selection:
 *   - If there exists a group matching the Seed ID, select insert entry based on Sequence ordering.
 *   - Otherwise, set insert entry equal to evict entry.
 *
 * - If evicting a valid entry (lifetime non-zero):
 *   - Require group size to have >=2 entries.
 *   - If inserting into existing group, require Sequence to be larger than oldest stored Sequence in group.
 */
mSeedSet stores recently received (Seed ID, Sequence) values.
- (Seed ID, Sequence) values are grouped by Seed ID.
- (Seed ID, Sequence) groups are not sorted by Seed ID relative to other groups.
- (Seed ID, Sequence) values within a group are sorted by Sequence.
- All unused entries (marked by 0 lifetime) are grouped at the end.

Update process.

- Eviction selection:
- If there are unused entries, mark the first unused entry for "eviction"
- Otherwise, pick the first entry of the group that has the most entries.

- Insert selection:
- If there exists a group matching the Seed ID, select insert entry based on Sequence ordering.
- Otherwise, set insert entry equal to evict entry.

- If evicting a valid entry (lifetime non-zero):
- Require group size to have >=2 entries.
- If inserting into existing group, require Sequence to be larger than oldest stored Sequence in group.
mSeedSet stores recently received ( Seed ID Sequence ) values . - ( Seed ID Sequence ) values are grouped by Seed ID . - ( Seed ID Sequence ) groups are not sorted by Seed ID relative to other groups . - ( Seed ID Sequence ) values within a group are sorted by Sequence . - All unused entries ( marked by 0 lifetime ) are grouped at the end . Update process . - Eviction selection : - If there are unused entries mark the first unused entry for " eviction " - Otherwise pick the first entry of the group that has the most entries . - Insert selection : - If there exists a group matching the Seed ID select insert entry based on Sequence ordering . - Otherwise set insert entry equal to evict entry . - If evicting a valid entry ( lifetime non - zero ) : - Require group size to have > = 2 entries . - If inserting into existing group require Sequence to be larger than oldest stored Sequence in group .
Error Mpl::UpdateSeedSet(uint16_t aSeedId, uint8_t aSequence)
{
    Error      error    = kErrorNone;
    SeedEntry *insert   = nullptr;
    SeedEntry *group    = mSeedSet;
    SeedEntry *evict    = mSeedSet;
    uint8_t    curCount = 0;
    uint8_t    maxCount = 0;
    for (uint32_t i = 0; i < kNumSeedEntries; i++, curCount++)
    {
        if (mSeedSet[i].mLifetime == 0)
        {
            if (insert == nullptr)
            {
                insert = &mSeedSet[i];
            }
            evict = &mSeedSet[i];
            break;
        }
        if (mSeedSet[i].mSeedId != group->mSeedId)
        {
            if (aSeedId == group->mSeedId && insert == nullptr)
            {
                insert = &mSeedSet[i];
                curCount++;
            }
            if (maxCount < curCount)
            {
                evict    = group;
                maxCount = curCount;
            }
            group    = &mSeedSet[i];
            curCount = 0;
        }
        if (aSeedId == mSeedSet[i].mSeedId)
        {
            int8_t diff = static_cast<int8_t>(aSequence - mSeedSet[i].mSequence);
            if (diff == 0)
            {
                ExitNow(error = kErrorDrop);
            }
            else if (insert == nullptr && diff < 0)
            {
                insert = &mSeedSet[i];
                curCount++;
            }
        }
    }
    if (evict->mLifetime != 0)
    {
        OT_ASSERT(curCount != 0);
        if (aSeedId == group->mSeedId && insert == nullptr)
        {
            insert = &mSeedSet[kNumSeedEntries];
            curCount++;
        }
        if (maxCount < curCount)
        {
            evict    = group;
            maxCount = curCount;
        }
        VerifyOrExit(maxCount > 1, error = kErrorDrop);
        if (insert == nullptr)
        {
            insert = evict;
        }
        else
        {
            VerifyOrExit(insert > mSeedSet && aSeedId == (insert - 1)->mSeedId, error = kErrorDrop);
        }
    }
    if (evict > insert)
    {
        OT_ASSERT(insert >= mSeedSet);
        memmove(insert + 1, insert, static_cast<size_t>(evict - insert) * sizeof(SeedEntry));
    }
    else if (evict < insert)
    {
        OT_ASSERT(evict >= mSeedSet);
        memmove(evict, evict + 1, static_cast<size_t>(insert - 1 - evict) * sizeof(SeedEntry));
        insert--;
    }
    insert->mSeedId   = aSeedId;
    insert->mSequence = aSequence;
    insert->mLifetime = kSeedEntryLifetime;
    if (!mSeedSetTimer.IsRunning())
    {
        mSeedSetTimer.Start(kSeedEntryLifetimeDt);
    }
exit:
    return error;
}
Error Mpl :: UpdateSeedSet ( uint16_t aSeedId , uint8_t aSequence ) { Error error = kErrorNone ; SeedEntry * insert = nullptr ; SeedEntry * group = mSeedSet ; SeedEntry * evict = mSeedSet ; uint8_t curCount = 0 ; uint8_t maxCount = 0 ; for ( uint32_t i = 0 ; i < kNumSeedEntries ; i ++ , curCount ++ ) { if ( mSeedSet [ i ] . mLifetime == 0 ) { if ( insert == nullptr ) { insert = & mSeedSet [ i ] ; } evict = & mSeedSet [ i ] ; break ; } if ( mSeedSet [ i ] . mSeedId != group -> mSeedId ) { if ( aSeedId == group -> mSeedId && insert == nullptr ) { insert = & mSeedSet [ i ] ; curCount ++ ; } if ( maxCount < curCount ) { evict = group ; maxCount = curCount ; } group = & mSeedSet [ i ] ; curCount = 0 ; } if ( aSeedId == mSeedSet [ i ] . mSeedId ) { int8_t diff = static_cast < int8_t > ( aSequence - mSeedSet [ i ] . mSequence ) ; if ( diff == 0 ) { ExitNow ( error = kErrorDrop ) ; } else if ( insert == nullptr && diff < 0 ) { insert = & mSeedSet [ i ] ; curCount ++ ; } } } if ( evict -> mLifetime != 0 ) { OT_ASSERT ( curCount != 0 ) ; if ( aSeedId == group -> mSeedId && insert == nullptr ) { insert = & mSeedSet [ kNumSeedEntries ] ; curCount ++ ; } if ( maxCount < curCount ) { evict = group ; maxCount = curCount ; } VerifyOrExit ( maxCount > 1 , error = kErrorDrop ) ; if ( insert == nullptr ) { insert = evict ; } else { VerifyOrExit ( insert > mSeedSet && aSeedId == ( insert - 1 ) -> mSeedId , error = kErrorDrop ) ; } } if ( evict > insert ) { OT_ASSERT ( insert >= mSeedSet ) ; memmove ( insert + 1 , insert , static_cast < size_t > ( evict - insert ) * sizeof ( SeedEntry ) ) ; } else if ( evict < insert ) { OT_ASSERT ( evict >= mSeedSet ) ; memmove ( evict , evict + 1 , static_cast < size_t > ( insert - 1 - evict ) * sizeof ( SeedEntry ) ) ; insert -- ; } insert -> mSeedId = aSeedId ; insert -> mSequence = aSequence ; insert -> mLifetime = kSeedEntryLifetime ; if ( ! mSeedSetTimer . IsRunning ( ) ) { mSeedSetTimer . Start ( kSeedEntryLifetimeDt ) ; } exit : return error ; }
mSeedSet stores recently received (Seed ID, Sequence) values.
mSeedSet stores recently received ( Seed ID Sequence ) values .
// unused entries exist // no existing group, set insert and evict entry to be the same // mark first unused entry for eviction // processing new group // insert at end of existing group // look to evict an entry from the seed with the most entries // have existing entries for aSeedId // already received, drop message // insert in order of sequence // no free entries available, look to evict an existing entry // insert at end of existing group // look to evict an entry from the seed with the most entries // require evict group size to have >= 2 entries // no existing entries for aSeedId // require Sequence to be larger than oldest stored Sequence in group