Skip to content

mipv6: InitialBindackTimeoutFirstReg is dead code, first home registration always uses INITIAL_BINDACK_TIMEOUT #1132

Description

@adamgeorge309

Summary

Mipv6::createBUTimer() implements the RFC 6275 Section 11.8 rule that selects the initial
retransmission timer for a Binding Update (BU), but the branch that would select
InitialBindackTimeoutFirstReg is unreachable. A Mobile Node's (MN) first home registration
therefore always starts its exponential backoff at INITIAL_BINDACK_TIMEOUT (1 s) instead of
InitialBindackTimeoutFirstReg (1.5 s by RFC default).

What the standard requires

RFC 6275 Section 11.8, Retransmissions and Rate Limiting:

o If the mobile node is sending a Binding Update and does not have
an existing binding at the home agent, it SHOULD use
InitialBindackTimeoutFirstReg (see Section 13) as a value for the
initial retransmission timer. This long retransmission interval
will allow the home agent to complete the Duplicate Address
Detection procedure mandated in this case, as detailed in
Section 11.7.1.

o Otherwise, the mobile node should use the specified value of
INITIAL_BINDACK_TIMEOUT for the initial retransmission timer.

RFC 3775 Section 11.8 is identical, so this has applied for as long as the model has existed.

Where it goes wrong

src/inet/networklayer/mipv6/Mipv6.cc. The two-argument createBUTimer() overload calls
BindingUpdateList::fetch(), which is a lookup-or-create: it inserts a Binding Update List
(BUL) entry when none exists, purely so that it can set the entry's state field. It then calls
the four-argument overload, which tests whether a BUL entry exists:

void Mipv6::createBUTimer(const Ipv6Address& buDest, NetworkInterface *ie)
{
    cancelTimerIfEntry(buDest, ie->getInterfaceId(), KEY_BUL_EXP);

    BindingUpdateList::BindingUpdateListEntry *bulEntry = bul->fetch(buDest);   // <-- creates the entry
    ASSERT(bulEntry != nullptr);

    if (bulEntry->state != BindingUpdateList::DEREGISTER)
        bulEntry->state = BindingUpdateList::REGISTER;

    if (buDest == ie->getProtocolData<Mipv6InterfaceData>()->getHomeAgentAddress())
        createBUTimer(buDest, ie, (uint)par("maxHaBindingLifeTime").doubleValueInUnit("s"), true);
    ...
}

void Mipv6::createBUTimer(const Ipv6Address& buDest, NetworkInterface *ie, const uint lifeTime,
        bool homeRegistration)
{
    ...
    if (!bul->isInBindingUpdateList(buDest))                        // <-- always false by now
        buIfEntry->ackTimeout = ie->getProtocolData<Mipv6InterfaceData>()->_getInitialBindAckTimeoutFirst();
    else
        buIfEntry->ackTimeout = ie->getProtocolData<Mipv6InterfaceData>()->_getInitialBindAckTimeout();
    ...
}

fetch() populates the map three statements before the predicate reads it, so
_getInitialBindAckTimeoutFirst() is never called on any code path.

How to reproduce

Change MIPv6_INITIAL_BINDACK_TIMEOUT_FIRST in
src/inet/networklayer/ipv6/Mipv6InterfaceData.h to an obviously distinct value such as 7,
rebuild, and run:

cd examples/ipv6/mipv6
inet -u Cmdenv -c Handover --cmdenv-log-level=WARN '--**.mipv6.cmdenv-log-level=TRACE'

The logged backoff is unchanged:

21.750073506141  Sending periodic BU message at time: 21.750073506141 seconds.
21.750073506141  Present Sent Time: 21.750073506141, Present TimeOut: 2
21.750073506141  Next Sent Time: 22.750073506141

Present TimeOut: 2 is INITIAL_BINDACK_TIMEOUT (1 s) after the one doubling that
sendPeriodicBU() applies, i.e. the first-registration value was not used.

Two further problems with the predicate

Both surface only once the branch is reachable again, so they should be fixed in the same change.

  1. It tests the wrong thing. The RFC condition is "does not have an existing binding at the
    home agent". A Binding Update List (BUL) entry only records that a Binding Update (BU) was
    attempted; it does not mean a binding exists. BindingUpdateList::hasActiveBinding() — an
    acknowledged binding whose expiry still lies in the future — is the predicate the RFC describes.

  2. It is not restricted to home registrations. The longer timer exists solely to cover the Home
    Agent's (HA) Duplicate Address Detection (DAD), which only a home registration triggers. The test
    is not gated on the homeRegistration argument, so once revived it would also stretch the initial
    retransmission timer for Binding Updates (BUs) sent to Correspondent Nodes (CNs), where RFC 6275
    Section 11.8 calls for INITIAL_BINDACK_TIMEOUT.

Observable effect

Together with the wrong default value tracked in #1133, this makes every first home registration
in examples/ipv6/mipv6 cost two Binding Updates (BUs) instead of one. The Home Agent (HA) models
Duplicate Address Detection (DAD) as a 1 s delay before the Binding Acknowledgement (BA)
(Mipv6.cc, sendTime = existingBinding ? 0 : 1), which matches DupAddrDetectTransmits ×
RetransTimer = 1 s. Measured in -c Handover:

Event Time (s)
Binding Update (BU) #1 sent by Mobile Node (MN) 21.750074
Binding Update (BU) #1 received by Home Agent (HA) 21.750737
Mobile Node (MN) retransmission timer expires (+1.000 s) 22.750074
Binding Update (BU) #2 sent 22.750074
Binding Acknowledgement (BA) for Binding Update (BU) #1 arrives 22.752424
Binding Acknowledgement (BA) for Binding Update (BU) #2 arrives 22.753396

The Binding Acknowledgement (BA) loses the race by 2.35 ms. The RFC's 1.5x factor exists precisely
to give that margin, and the model currently has none.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions