Support parsing Prf field in RAs

This change prepares for a later change which actually handles the
Prf field in RAs to discover default routers with preference values,
as per RFC 4191.

Updates #6172.

Test: header_test.TestNDPRouterAdvert
PiperOrigin-RevId: 379421710
This commit is contained in:
Ghanan Gowripalan
2021-06-14 23:09:01 -07:00
committed by gVisor bot
parent bccc446154
commit 3a8ba8ed9d
2 changed files with 143 additions and 23 deletions
+74 -1
View File
@@ -19,12 +19,72 @@ import (
"time"
)
// NDPRoutePreference is the preference values for default routers or
// more-specific routes.
//
// As per RFC 4191 section 2.1,
//
// Default router preferences and preferences for more-specific routes
// are encoded the same way.
//
// Preference values are encoded as a two-bit signed integer, as
// follows:
//
// 01 High
// 00 Medium (default)
// 11 Low
// 10 Reserved - MUST NOT be sent
//
// Note that implementations can treat the value as a two-bit signed
// integer.
//
// Having just three values reinforces that they are not metrics and
// more values do not appear to be necessary for reasonable scenarios.
type NDPRoutePreference uint8
const (
// HighRoutePreference indicates a high preference, as per
// RFC 4191 section 2.1.
HighRoutePreference NDPRoutePreference = 0b01
// MediumRoutePreference indicates a medium preference, as per
// RFC 4191 section 2.1.
//
// This is the default preference value.
MediumRoutePreference = 0b00
// LowRoutePreference indicates a low preference, as per
// RFC 4191 section 2.1.
LowRoutePreference = 0b11
// ReservedRoutePreference is a reserved preference value, as per
// RFC 4191 section 2.1.
//
// It MUST NOT be sent.
ReservedRoutePreference = 0b10
)
// NDPRouterAdvert is an NDP Router Advertisement message. It will only contain
// the body of an ICMPv6 packet.
//
// See RFC 4861 section 4.2 for more details.
// See RFC 4861 section 4.2 and RFC 4191 section 2.2 for more details.
type NDPRouterAdvert []byte
// As per RFC 4191 section 2.2,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Cur Hop Limit |M|O|H|Prf|Resvd| Router Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reachable Time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Retrans Timer |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Options ...
// +-+-+-+-+-+-+-+-+-+-+-+-
const (
// NDPRAMinimumSize is the minimum size of a valid NDP Router
// Advertisement message (body of an ICMPv6 packet).
@@ -47,6 +107,14 @@ const (
// within the bit-field/flags byte of an NDPRouterAdvert.
ndpRAOtherConfFlagMask = (1 << 6)
// ndpDefaultRouterPreferenceShift is the shift of the Prf (Default Router
// Preference) field within the flags byte of an NDPRouterAdvert.
ndpDefaultRouterPreferenceShift = 3
// ndpDefaultRouterPreferenceMask is the mask of the Prf (Default Router
// Preference) field within the flags byte of an NDPRouterAdvert.
ndpDefaultRouterPreferenceMask = (0b11 << ndpDefaultRouterPreferenceShift)
// ndpRARouterLifetimeOffset is the start of the 2-byte Router Lifetime
// field within an NDPRouterAdvert.
ndpRARouterLifetimeOffset = 2
@@ -80,6 +148,11 @@ func (b NDPRouterAdvert) OtherConfFlag() bool {
return b[ndpRAFlagsOffset]&ndpRAOtherConfFlagMask != 0
}
// DefaultRouterPreference returns the Default Router Preference field.
func (b NDPRouterAdvert) DefaultRouterPreference() NDPRoutePreference {
return NDPRoutePreference((b[ndpRAFlagsOffset] & ndpDefaultRouterPreferenceMask) >> ndpDefaultRouterPreferenceShift)
}
// RouterLifetime returns the lifetime associated with the default router. A
// value of 0 means the source of the Router Advertisement is not a default
// router and SHOULD NOT appear on the default router list. Note, a value of 0
+69 -22
View File
@@ -126,36 +126,83 @@ func TestNDPNeighborAdvert(t *testing.T) {
}
func TestNDPRouterAdvert(t *testing.T) {
b := []byte{
64, 128, 1, 2,
3, 4, 5, 6,
7, 8, 9, 10,
tests := []struct {
hopLimit uint8
managedFlag, otherConfFlag bool
prf NDPRoutePreference
routerLifetimeS uint16
reachableTimeMS, retransTimerMS uint32
}{
{
hopLimit: 1,
managedFlag: false,
otherConfFlag: true,
prf: HighRoutePreference,
routerLifetimeS: 2,
reachableTimeMS: 3,
retransTimerMS: 4,
},
{
hopLimit: 64,
managedFlag: true,
otherConfFlag: false,
prf: LowRoutePreference,
routerLifetimeS: 258,
reachableTimeMS: 78492,
retransTimerMS: 13213,
},
}
ra := NDPRouterAdvert(b)
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
flags := uint8(0)
if test.managedFlag {
flags |= 1 << 7
}
if test.otherConfFlag {
flags |= 1 << 6
}
flags |= uint8(test.prf) << 3
if got := ra.CurrHopLimit(); got != 64 {
t.Errorf("got ra.CurrHopLimit = %d, want = 64", got)
}
b := []byte{
test.hopLimit, flags, 1, 2,
3, 4, 5, 6,
7, 8, 9, 10,
}
binary.BigEndian.PutUint16(b[2:], test.routerLifetimeS)
binary.BigEndian.PutUint32(b[4:], test.reachableTimeMS)
binary.BigEndian.PutUint32(b[8:], test.retransTimerMS)
if got := ra.ManagedAddrConfFlag(); !got {
t.Errorf("got ManagedAddrConfFlag = false, want = true")
}
ra := NDPRouterAdvert(b)
if got := ra.OtherConfFlag(); got {
t.Errorf("got OtherConfFlag = true, want = false")
}
if got := ra.CurrHopLimit(); got != test.hopLimit {
t.Errorf("got ra.CurrHopLimit() = %d, want = %d", got, test.hopLimit)
}
if got, want := ra.RouterLifetime(), time.Second*258; got != want {
t.Errorf("got ra.RouterLifetime = %d, want = %d", got, want)
}
if got := ra.ManagedAddrConfFlag(); got != test.managedFlag {
t.Errorf("got ManagedAddrConfFlag() = %t, want = %t", got, test.managedFlag)
}
if got, want := ra.ReachableTime(), time.Millisecond*50595078; got != want {
t.Errorf("got ra.ReachableTime = %d, want = %d", got, want)
}
if got := ra.OtherConfFlag(); got != test.otherConfFlag {
t.Errorf("got OtherConfFlag() = %t, want = %t", got, test.otherConfFlag)
}
if got, want := ra.RetransTimer(), time.Millisecond*117967114; got != want {
t.Errorf("got ra.RetransTimer = %d, want = %d", got, want)
if got := ra.DefaultRouterPreference(); got != test.prf {
t.Errorf("got DefaultRouterPreference() = %d, want = %d", got, test.prf)
}
if got, want := ra.RouterLifetime(), time.Second*time.Duration(test.routerLifetimeS); got != want {
t.Errorf("got ra.RouterLifetime() = %d, want = %d", got, want)
}
if got, want := ra.ReachableTime(), time.Millisecond*time.Duration(test.reachableTimeMS); got != want {
t.Errorf("got ra.ReachableTime() = %d, want = %d", got, want)
}
if got, want := ra.RetransTimer(), time.Millisecond*time.Duration(test.retransTimerMS); got != want {
t.Errorf("got ra.RetransTimer() = %d, want = %d", got, want)
}
})
}
}