Discover more specific routes as per RFC 4191
More-specific route discovery allows hosts to pick a more appropriate router for off-link destinations. Fixes #6172. PiperOrigin-RevId: 382779880
This commit is contained in:
parent
16b751b6c6
commit
a51a4b872e
|
@ -54,6 +54,11 @@ const (
|
|||
// Advertisements, as a host.
|
||||
defaultDiscoverDefaultRouters = true
|
||||
|
||||
// defaultDiscoverMoreSpecificRoutes is the default configuration for
|
||||
// whether or not to discover more-specific routes from incoming Router
|
||||
// Advertisements, as a host.
|
||||
defaultDiscoverMoreSpecificRoutes = true
|
||||
|
||||
// defaultDiscoverOnLinkPrefixes is the default configuration for
|
||||
// whether or not to discover on-link prefixes from incoming Router
|
||||
// Advertisements' Prefix Information option, as a host.
|
||||
|
@ -352,12 +357,18 @@ type NDPConfigurations struct {
|
|||
|
||||
// DiscoverDefaultRouters determines whether or not default routers are
|
||||
// discovered from Router Advertisements, as per RFC 4861 section 6. This
|
||||
// configuration is ignored if HandleRAs is false.
|
||||
// configuration is ignored if RAs will not be processed (see HandleRAs).
|
||||
DiscoverDefaultRouters bool
|
||||
|
||||
// DiscoverMoreSpecificRoutes determines whether or not more specific routes
|
||||
// are discovered from Router Advertisements, as per RFC 4191. This
|
||||
// configuration is ignored if RAs will not be processed (see HandleRAs).
|
||||
DiscoverMoreSpecificRoutes bool
|
||||
|
||||
// DiscoverOnLinkPrefixes determines whether or not on-link prefixes are
|
||||
// discovered from Router Advertisements' Prefix Information option, as per
|
||||
// RFC 4861 section 6. This configuration is ignored if HandleRAs is false.
|
||||
// RFC 4861 section 6. This configuration is ignored if RAs will not be
|
||||
// processed (see HandleRAs).
|
||||
DiscoverOnLinkPrefixes bool
|
||||
|
||||
// AutoGenGlobalAddresses determines whether or not an IPv6 endpoint performs
|
||||
|
@ -408,6 +419,7 @@ func DefaultNDPConfigurations() NDPConfigurations {
|
|||
MaxRtrSolicitationDelay: defaultMaxRtrSolicitationDelay,
|
||||
HandleRAs: defaultHandleRAs,
|
||||
DiscoverDefaultRouters: defaultDiscoverDefaultRouters,
|
||||
DiscoverMoreSpecificRoutes: defaultDiscoverMoreSpecificRoutes,
|
||||
DiscoverOnLinkPrefixes: defaultDiscoverOnLinkPrefixes,
|
||||
AutoGenGlobalAddresses: defaultAutoGenGlobalAddresses,
|
||||
AutoGenTempGlobalAddresses: defaultAutoGenTempGlobalAddresses,
|
||||
|
@ -786,6 +798,32 @@ func (ndp *ndpState) handleRA(ip tcpip.Address, ra header.NDPRouterAdvert) {
|
|||
if opt.AutonomousAddressConfigurationFlag() {
|
||||
ndp.handleAutonomousPrefixInformation(opt)
|
||||
}
|
||||
|
||||
case header.NDPRouteInformation:
|
||||
if !ndp.configs.DiscoverMoreSpecificRoutes {
|
||||
continue
|
||||
}
|
||||
|
||||
dest, err := opt.Prefix()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("%T.Prefix(): %s", opt, err))
|
||||
}
|
||||
|
||||
prf := opt.RoutePreference()
|
||||
if prf == header.ReservedRoutePreference {
|
||||
// As per RFC 4191 section 2.3,
|
||||
//
|
||||
// Prf (Route Preference)
|
||||
// 2-bit signed integer. The Route Preference indicates
|
||||
// whether to prefer the router associated with this prefix
|
||||
// over others, when multiple identical prefixes (for
|
||||
// different routers) have been received. If the Reserved
|
||||
// (10) value is received, the Route Information Option MUST
|
||||
// be ignored.
|
||||
continue
|
||||
}
|
||||
|
||||
ndp.handleOffLinkRouteDiscovery(offLinkRoute{dest: dest, router: ip}, opt.RouteLifetime(), prf)
|
||||
}
|
||||
|
||||
// TODO(b/141556115): Do (MTU) Parameter Discovery.
|
||||
|
|
|
@ -1152,6 +1152,39 @@ func raBufWithPI(ip tcpip.Address, rl uint16, prefix tcpip.AddressWithPrefix, on
|
|||
})
|
||||
}
|
||||
|
||||
// raBufWithRIO returns a valid NDP Router Advertisement with a single Route
|
||||
// Information option.
|
||||
//
|
||||
// All fields in the RA will be zero except the RIO option.
|
||||
func raBufWithRIO(t *testing.T, ip tcpip.Address, prefix tcpip.AddressWithPrefix, lifetimeSeconds uint32, prf header.NDPRoutePreference) *stack.PacketBuffer {
|
||||
// buf will hold the route information option after the Type and Length
|
||||
// fields.
|
||||
//
|
||||
// 2.3. Route Information Option
|
||||
//
|
||||
// 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 | Length | Prefix Length |Resvd|Prf|Resvd|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Route Lifetime |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Prefix (Variable Length) |
|
||||
// . .
|
||||
// . .
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
var buf [22]byte
|
||||
buf[0] = uint8(prefix.PrefixLen)
|
||||
buf[1] = byte(prf) << 3
|
||||
binary.BigEndian.PutUint32(buf[2:], lifetimeSeconds)
|
||||
if n := copy(buf[6:], prefix.Address); n != len(prefix.Address) {
|
||||
t.Fatalf("got copy(...) = %d, want = %d", n, len(prefix.Address))
|
||||
}
|
||||
return raBufWithOpts(ip, 0 /* router lifetime */, header.NDPOptionsSerializer{
|
||||
header.NDPRouteInformation(buf[:]),
|
||||
})
|
||||
}
|
||||
|
||||
func TestDynamicConfigurationsDisabled(t *testing.T) {
|
||||
const (
|
||||
nicID = 1
|
||||
|
@ -1308,8 +1341,8 @@ func boolToUint64(v bool) uint64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func checkOffLinkRouteEvent(e ndpOffLinkRouteEvent, nicID tcpip.NICID, router tcpip.Address, prf header.NDPRoutePreference, updated bool) string {
|
||||
return cmp.Diff(ndpOffLinkRouteEvent{nicID: nicID, subnet: header.IPv6EmptySubnet, router: router, prf: prf, updated: updated}, e, cmp.AllowUnexported(e))
|
||||
func checkOffLinkRouteEvent(e ndpOffLinkRouteEvent, nicID tcpip.NICID, subnet tcpip.Subnet, router tcpip.Address, prf header.NDPRoutePreference, updated bool) string {
|
||||
return cmp.Diff(ndpOffLinkRouteEvent{nicID: nicID, subnet: subnet, router: router, prf: prf, updated: updated}, e, cmp.AllowUnexported(e))
|
||||
}
|
||||
|
||||
func testWithRAs(t *testing.T, f func(*testing.T, ipv6.HandleRAsConfiguration, bool)) {
|
||||
|
@ -1342,122 +1375,167 @@ func testWithRAs(t *testing.T, f func(*testing.T, ipv6.HandleRAsConfiguration, b
|
|||
}
|
||||
}
|
||||
|
||||
func TestRouterDiscovery(t *testing.T) {
|
||||
func TestOffLinkRouteDiscovery(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
testWithRAs(t, func(t *testing.T, handleRAs ipv6.HandleRAsConfiguration, forwarding bool) {
|
||||
ndpDisp := ndpDispatcher{
|
||||
offLinkRouteC: make(chan ndpOffLinkRouteEvent, 1),
|
||||
}
|
||||
e := channel.New(0, 1280, linkAddr1)
|
||||
clock := faketime.NewManualClock()
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv6.NewProtocolWithOptions(ipv6.Options{
|
||||
NDPConfigs: ipv6.NDPConfigurations{
|
||||
HandleRAs: handleRAs,
|
||||
DiscoverDefaultRouters: true,
|
||||
},
|
||||
NDPDisp: &ndpDisp,
|
||||
})},
|
||||
Clock: clock,
|
||||
moreSpecificPrefix := tcpip.AddressWithPrefix{Address: testutil.MustParse6("a00::"), PrefixLen: 16}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
discoverDefaultRouters bool
|
||||
discoverMoreSpecificRoutes bool
|
||||
|
||||
dest tcpip.Subnet
|
||||
ra func(*testing.T, tcpip.Address, uint16, header.NDPRoutePreference) *stack.PacketBuffer
|
||||
}{
|
||||
{
|
||||
name: "Default router discovery",
|
||||
discoverDefaultRouters: true,
|
||||
discoverMoreSpecificRoutes: false,
|
||||
dest: header.IPv6EmptySubnet,
|
||||
ra: func(_ *testing.T, router tcpip.Address, lifetimeSeconds uint16, prf header.NDPRoutePreference) *stack.PacketBuffer {
|
||||
return raBufWithPrf(router, lifetimeSeconds, prf)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "More-specific route discovery",
|
||||
discoverDefaultRouters: false,
|
||||
discoverMoreSpecificRoutes: true,
|
||||
dest: moreSpecificPrefix.Subnet(),
|
||||
ra: func(t *testing.T, router tcpip.Address, lifetimeSeconds uint16, prf header.NDPRoutePreference) *stack.PacketBuffer {
|
||||
return raBufWithRIO(t, router, moreSpecificPrefix, uint32(lifetimeSeconds), prf)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
testWithRAs(t, func(t *testing.T, handleRAs ipv6.HandleRAsConfiguration, forwarding bool) {
|
||||
ndpDisp := ndpDispatcher{
|
||||
offLinkRouteC: make(chan ndpOffLinkRouteEvent, 1),
|
||||
}
|
||||
e := channel.New(0, 1280, linkAddr1)
|
||||
clock := faketime.NewManualClock()
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv6.NewProtocolWithOptions(ipv6.Options{
|
||||
NDPConfigs: ipv6.NDPConfigurations{
|
||||
HandleRAs: handleRAs,
|
||||
DiscoverDefaultRouters: test.discoverDefaultRouters,
|
||||
DiscoverMoreSpecificRoutes: test.discoverMoreSpecificRoutes,
|
||||
},
|
||||
NDPDisp: &ndpDisp,
|
||||
})},
|
||||
Clock: clock,
|
||||
})
|
||||
|
||||
expectOffLinkRouteEvent := func(addr tcpip.Address, prf header.NDPRoutePreference, updated bool) {
|
||||
t.Helper()
|
||||
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, test.dest, addr, prf, updated); diff != "" {
|
||||
t.Errorf("off-link route event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
default:
|
||||
t.Fatal("expected router discovery event")
|
||||
}
|
||||
}
|
||||
|
||||
expectAsyncOffLinkRouteInvalidationEvent := func(addr tcpip.Address, timeout time.Duration) {
|
||||
t.Helper()
|
||||
|
||||
clock.Advance(timeout)
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
var prf header.NDPRoutePreference
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, test.dest, addr, prf, false); diff != "" {
|
||||
t.Errorf("off-link route event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
default:
|
||||
t.Fatal("timed out waiting for router discovery event")
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.SetForwardingDefaultAndAllNICs(ipv6.ProtocolNumber, forwarding); err != nil {
|
||||
t.Fatalf("SetForwardingDefaultAndAllNICs(%d, %t): %s", ipv6.ProtocolNumber, forwarding, err)
|
||||
}
|
||||
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
|
||||
}
|
||||
|
||||
// Rx an RA from lladdr2 with zero lifetime. It should not be
|
||||
// remembered.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, 0, header.MediumRoutePreference))
|
||||
select {
|
||||
case <-ndpDisp.offLinkRouteC:
|
||||
t.Fatal("unexpectedly updated an off-link route with 0 lifetime")
|
||||
default:
|
||||
}
|
||||
|
||||
// Discover an off-link route through llAddr2.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, 1000, header.ReservedRoutePreference))
|
||||
if test.discoverMoreSpecificRoutes {
|
||||
// The reserved value is considered invalid with more-specific route
|
||||
// discovery so we inject the same packet but with the default
|
||||
// (medium) preference value.
|
||||
select {
|
||||
case <-ndpDisp.offLinkRouteC:
|
||||
t.Fatal("unexpectedly updated an off-link route with a reserved preference value")
|
||||
default:
|
||||
}
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, 1000, header.MediumRoutePreference))
|
||||
}
|
||||
expectOffLinkRouteEvent(llAddr2, header.MediumRoutePreference, true)
|
||||
|
||||
// Rx an RA from another router (lladdr3) with non-zero lifetime and
|
||||
// non-default preference value.
|
||||
const l3LifetimeSeconds = 6
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr3, l3LifetimeSeconds, header.HighRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr3, header.HighRoutePreference, true)
|
||||
|
||||
// Rx an RA from lladdr2 with lesser lifetime and default (medium)
|
||||
// preference value.
|
||||
const l2LifetimeSeconds = 2
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, l2LifetimeSeconds, header.MediumRoutePreference))
|
||||
select {
|
||||
case <-ndpDisp.offLinkRouteC:
|
||||
t.Fatal("should not receive a off-link route event when updating lifetimes for known routers")
|
||||
default:
|
||||
}
|
||||
|
||||
// Rx an RA from lladdr2 with a different preference.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, l2LifetimeSeconds, header.LowRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr2, header.LowRoutePreference, true)
|
||||
|
||||
// Wait for lladdr2's router invalidation job to execute. The lifetime
|
||||
// of the router should have been updated to the most recent (smaller)
|
||||
// lifetime.
|
||||
//
|
||||
// Wait for the normal lifetime plus an extra bit for the
|
||||
// router to get invalidated. If we don't get an invalidation
|
||||
// event after this time, then something is wrong.
|
||||
expectAsyncOffLinkRouteInvalidationEvent(llAddr2, l2LifetimeSeconds*time.Second)
|
||||
|
||||
// Rx an RA from lladdr2 with huge lifetime.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, 1000, header.MediumRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr2, header.MediumRoutePreference, true)
|
||||
|
||||
// Rx an RA from lladdr2 with zero lifetime. It should be invalidated.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, test.ra(t, llAddr2, 0, header.MediumRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr2, header.MediumRoutePreference, false)
|
||||
|
||||
// Wait for lladdr3's router invalidation job to execute. The lifetime
|
||||
// of the router should have been updated to the most recent (smaller)
|
||||
// lifetime.
|
||||
//
|
||||
// Wait for the normal lifetime plus an extra bit for the
|
||||
// router to get invalidated. If we don't get an invalidation
|
||||
// event after this time, then something is wrong.
|
||||
expectAsyncOffLinkRouteInvalidationEvent(llAddr3, l3LifetimeSeconds*time.Second)
|
||||
})
|
||||
})
|
||||
|
||||
expectOffLinkRouteEvent := func(addr tcpip.Address, prf header.NDPRoutePreference, updated bool) {
|
||||
t.Helper()
|
||||
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, addr, prf, updated); diff != "" {
|
||||
t.Errorf("off-link route event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
default:
|
||||
t.Fatal("expected router discovery event")
|
||||
}
|
||||
}
|
||||
|
||||
expectAsyncOffLinkRouteInvalidationEvent := func(addr tcpip.Address, timeout time.Duration) {
|
||||
t.Helper()
|
||||
|
||||
clock.Advance(timeout)
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
var prf header.NDPRoutePreference
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, addr, prf, false); diff != "" {
|
||||
t.Errorf("off-link route event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
default:
|
||||
t.Fatal("timed out waiting for router discovery event")
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.SetForwardingDefaultAndAllNICs(ipv6.ProtocolNumber, forwarding); err != nil {
|
||||
t.Fatalf("SetForwardingDefaultAndAllNICs(%d, %t): %s", ipv6.ProtocolNumber, forwarding, err)
|
||||
}
|
||||
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
|
||||
}
|
||||
|
||||
// Rx an RA from lladdr2 with zero lifetime. It should not be
|
||||
// remembered.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufSimple(llAddr2, 0))
|
||||
select {
|
||||
case <-ndpDisp.offLinkRouteC:
|
||||
t.Fatal("unexpectedly updated an off-link route with 0 lifetime")
|
||||
default:
|
||||
}
|
||||
|
||||
// Rx an RA from lladdr2 with a huge lifetime and reserved preference value
|
||||
// (which should be interpreted as the default (medium) preference value).
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPrf(llAddr2, 1000, header.ReservedRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr2, header.MediumRoutePreference, true)
|
||||
|
||||
// Rx an RA from another router (lladdr3) with non-zero lifetime and
|
||||
// non-default preference value.
|
||||
const l3LifetimeSeconds = 6
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPrf(llAddr3, l3LifetimeSeconds, header.HighRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr3, header.HighRoutePreference, true)
|
||||
|
||||
// Rx an RA from lladdr2 with lesser lifetime and default (medium)
|
||||
// preference value.
|
||||
const l2LifetimeSeconds = 2
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufSimple(llAddr2, l2LifetimeSeconds))
|
||||
select {
|
||||
case <-ndpDisp.offLinkRouteC:
|
||||
t.Fatal("should not receive a off-link route event when updating lifetimes for known routers")
|
||||
default:
|
||||
}
|
||||
|
||||
// Rx an RA from lladdr2 with a different preference.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPrf(llAddr2, l2LifetimeSeconds, header.LowRoutePreference))
|
||||
expectOffLinkRouteEvent(llAddr2, header.LowRoutePreference, true)
|
||||
|
||||
// Wait for lladdr2's router invalidation job to execute. The lifetime
|
||||
// of the router should have been updated to the most recent (smaller)
|
||||
// lifetime.
|
||||
//
|
||||
// Wait for the normal lifetime plus an extra bit for the
|
||||
// router to get invalidated. If we don't get an invalidation
|
||||
// event after this time, then something is wrong.
|
||||
expectAsyncOffLinkRouteInvalidationEvent(llAddr2, l2LifetimeSeconds*time.Second)
|
||||
|
||||
// Rx an RA from lladdr2 with huge lifetime.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufSimple(llAddr2, 1000))
|
||||
expectOffLinkRouteEvent(llAddr2, header.MediumRoutePreference, true)
|
||||
|
||||
// Rx an RA from lladdr2 with zero lifetime. It should be invalidated.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufSimple(llAddr2, 0))
|
||||
expectOffLinkRouteEvent(llAddr2, header.MediumRoutePreference, false)
|
||||
|
||||
// Wait for lladdr3's router invalidation job to execute. The lifetime
|
||||
// of the router should have been updated to the most recent (smaller)
|
||||
// lifetime.
|
||||
//
|
||||
// Wait for the normal lifetime plus an extra bit for the
|
||||
// router to get invalidated. If we don't get an invalidation
|
||||
// event after this time, then something is wrong.
|
||||
expectAsyncOffLinkRouteInvalidationEvent(llAddr3, l3LifetimeSeconds*time.Second)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestRouterDiscoveryMaxRouters tests that only
|
||||
|
@ -1494,7 +1572,7 @@ func TestRouterDiscoveryMaxRouters(t *testing.T) {
|
|||
if i <= ipv6.MaxDiscoveredOffLinkRoutes {
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, llAddr, header.MediumRoutePreference, true); diff != "" {
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, header.IPv6EmptySubnet, llAddr, header.MediumRoutePreference, true); diff != "" {
|
||||
t.Errorf("off-link route event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
default:
|
||||
|
@ -4583,7 +4661,7 @@ func TestNoCleanupNDPStateWhenForwardingEnabled(t *testing.T) {
|
|||
)
|
||||
select {
|
||||
case e := <-ndpDisp.offLinkRouteC:
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, llAddr3, header.MediumRoutePreference, true /* discovered */); diff != "" {
|
||||
if diff := checkOffLinkRouteEvent(e, nicID, header.IPv6EmptySubnet, llAddr3, header.MediumRoutePreference, true /* discovered */); diff != "" {
|
||||
t.Errorf("off-link route event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue