Skip to content

fixes: correct BGP-LS NLRI marshalling and IPv6 Router-ID TLV length - #3606

Closed
aronjohanns wants to merge 2 commits into
osrg:masterfrom
aronjohanns:srpolicy/fixes
Closed

aronjohanns wants to merge 2 commits into
osrg:masterfrom
aronjohanns:srpolicy/fixes

Conversation

@aronjohanns

Copy link
Copy Markdown
Contributor

Two small BGP-LS fixes split out of the work in #3595.

Comment thread pkg/packet/bgp/bgp.go
LsTLV: LsTLV{
Type: LS_TLV_IPV6_LOCAL_ROUTER_ID,
Length: 0,
Length: 16,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewLsTLVRemoteIPv6RouterID and NewLsTLVOpaquePrefixAttr, and NewLsTLVPrefixSID have the same bug (LsTLV's wrong length). Please fix them together.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed all three in the same commit and retitled it since it now covers all four constructors.

v6 := netip.MustParseAddr("2001:db8::1")
assert.EqualValues(t, 4, NewLsTLVLocalIPv4RouterID(&v4).Len()-tlvHdrLen)
assert.EqualValues(t, 16, NewLsTLVLocalIPv6RouterID(&v6).Len()-tlvHdrLen)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to test serializing LsTLVLocalIPv6RouterID?

b, err := NewLsTLVLocalIPv6RouterID(&v6).Serialize()
assert.NoError(t, err)
assert.Len(t, b, 20)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, replaced Len() checks with Serialize() for all four RouterID TLVs plus PrefixSID and OpaquePrefixAttr.

@fujita

fujita commented Sep 15, 2026

Copy link
Copy Markdown
Member

The commit message says "Serialize writes the real value length, and the two
callers in NewLsAttributeTLVs only serialize, so the wire encoding is right
today." That is not right. LsTLV.Serialize does not write the value length;
it checks it:

if len(value) != int(l.Length) {
	return nil, malformedAttrListErr("serialization failed: LS TLV malformed")
}

So with Length 0 and a 16-octet address, Serialize fails. On master a BGP-LS
attribute that carries a Node IPv6 Local Router-ID cannot be serialized at
all:

local:    Len()=4 err=serialization failed: LS TLV malformed
pathattr: err=serialization failed: LS TLV malformed

The fix is right, but the bug is worse than the message says.

aronjohanns and others added 2 commits September 16, 2026 08:45
NewLsTLVLocalIPv6RouterID, NewLsTLVRemoteIPv6RouterID, NewLsTLVPrefixSID
and NewLsTLVOpaquePrefixAttr set Length to 0 (4 for the remote IPv6
Router-ID) instead of the length of the value they carry.
LsTLV.Serialize rejects a value whose length does not match the Length
field, so a BGP-LS attribute carrying any of these TLVs failed to
serialize entirely, and Len() understated the descriptor length that
NewLsTLVNodeDescriptor sums over its sub-TLVs. Set the IPv6 Router-IDs
to the 16 octets RFC 6119 section 4.1 gives them, the Prefix-SID to the
8 octets of its fixed part with a 4-octet SID, and the opaque prefix
attribute to the length of its payload.

Co-Authored-By: Claude Fable 5 <[email protected]>
MarshalNLRI switches on the concrete Link-State NLRI and had no default
branch. An LsAddrPrefix carrying a type the switch does not know, or no
NLRI at all, was returned as an LsAddrPrefix whose Nlri field is nil.
The gRPC client then sees a route with a type and length but nothing
else, and cannot tell that from a decoding bug on its side. Report it as
an error instead, as the other address families in this function do.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@aronjohanns

Copy link
Copy Markdown
Contributor Author

The commit message says "Serialize writes the real value length, and the two callers in NewLsAttributeTLVs only serialize, so the wire encoding is right today." That is not right. LsTLV.Serialize does not write the value length; it checks it:

if len(value) != int(l.Length) {
	return nil, malformedAttrListErr("serialization failed: LS TLV malformed")
}

So with Length 0 and a 16-octet address, Serialize fails. On master a BGP-LS attribute that carries a Node IPv6 Local Router-ID cannot be serialized at all:

local:    Len()=4 err=serialization failed: LS TLV malformed
pathattr: err=serialization failed: LS TLV malformed

The fix is right, but the bug is worse than the message says.

Ok, I rewrote the commit message to state that

@fujita

fujita commented Sep 16, 2026

Copy link
Copy Markdown
Member

Merged, thanks.

@fujita fujita closed this Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants