Clear IGMPv1 present flag on NIC down

This is dynamic state that can be re-learned when the NIC comes
back up.

Test: ipv4_test.TestIgmpV1Present
PiperOrigin-RevId: 354630921
This commit is contained in:
Ghanan Gowripalan
2021-01-29 16:10:49 -08:00
committed by gVisor bot
parent 66aa6f3d4f
commit 45fe9fe9c6
3 changed files with 51 additions and 19 deletions
+5
View File
@@ -215,6 +215,11 @@ func (igmp *igmpState) setV1Present(v bool) {
}
}
func (igmp *igmpState) resetV1Present() {
igmp.igmpV1Job.Cancel()
igmp.setV1Present(false)
}
// handleMembershipQuery handles a membership query.
//
// Precondition: igmp.ep.mu must be locked.
+40 -19
View File
@@ -101,10 +101,10 @@ func createAndInjectIGMPPacket(e *channel.Endpoint, igmpType header.IGMPType, ma
})
}
// TestIgmpV1Present tests the handling of the case where an IGMPv1 router is
// present on the network. The IGMP stack will then send IGMPv1 Membership
// reports for backwards compatibility.
func TestIgmpV1Present(t *testing.T) {
// TestIGMPV1Present tests the node's ability to fallback to V1 when a V1
// router is detected. V1 present status is expected to be reset when the NIC
// cycles.
func TestIGMPV1Present(t *testing.T) {
e, s, clock := createStack(t, true)
if err := s.AddAddress(nicID, ipv4.ProtocolNumber, addr); err != nil {
t.Fatalf("AddAddress(%d, %d, %s): %s", nicID, ipv4.ProtocolNumber, addr, err)
@@ -116,14 +116,16 @@ func TestIgmpV1Present(t *testing.T) {
// This NIC will send an IGMPv2 report immediately, before this test can get
// the IGMPv1 General Membership Query in.
p, ok := e.Read()
if !ok {
t.Fatal("unable to Read IGMP packet, expected V2MembershipReport")
{
p, ok := e.Read()
if !ok {
t.Fatal("unable to Read IGMP packet, expected V2MembershipReport")
}
if got := s.Stats().IGMP.PacketsSent.V2MembershipReport.Value(); got != 1 {
t.Fatalf("got V2MembershipReport messages sent = %d, want = 1", got)
}
validateIgmpPacket(t, p, multicastAddr, header.IGMPv2MembershipReport, 0, multicastAddr)
}
if got := s.Stats().IGMP.PacketsSent.V2MembershipReport.Value(); got != 1 {
t.Fatalf("got V2MembershipReport messages sent = %d, want = 1", got)
}
validateIgmpPacket(t, p, multicastAddr, header.IGMPv2MembershipReport, 0, multicastAddr)
if t.Failed() {
t.FailNow()
}
@@ -145,19 +147,38 @@ func TestIgmpV1Present(t *testing.T) {
// Verify the solicited Membership Report is sent. Now that this NIC has seen
// an IGMPv1 query, it should send an IGMPv1 Membership Report.
p, ok = e.Read()
if ok {
if p, ok := e.Read(); ok {
t.Fatalf("sent unexpected packet, expected V1MembershipReport only after advancing the clock = %+v", p.Pkt)
}
clock.Advance(ipv4.UnsolicitedReportIntervalMax)
p, ok = e.Read()
if !ok {
t.Fatal("unable to Read IGMP packet, expected V1MembershipReport")
{
p, ok := e.Read()
if !ok {
t.Fatal("unable to Read IGMP packet, expected V1MembershipReport")
}
if got := s.Stats().IGMP.PacketsSent.V1MembershipReport.Value(); got != 1 {
t.Fatalf("got V1MembershipReport messages sent = %d, want = 1", got)
}
validateIgmpPacket(t, p, multicastAddr, header.IGMPv1MembershipReport, 0, multicastAddr)
}
if got := s.Stats().IGMP.PacketsSent.V1MembershipReport.Value(); got != 1 {
t.Fatalf("got V1MembershipReport messages sent = %d, want = 1", got)
// Cycling the interface should reset the V1 present flag.
if err := s.DisableNIC(nicID); err != nil {
t.Fatalf("s.DisableNIC(%d): %s", nicID, err)
}
if err := s.EnableNIC(nicID); err != nil {
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
}
{
p, ok := e.Read()
if !ok {
t.Fatal("unable to Read IGMP packet, expected V2MembershipReport")
}
if got := s.Stats().IGMP.PacketsSent.V2MembershipReport.Value(); got != 2 {
t.Fatalf("got V2MembershipReport messages sent = %d, want = 2", got)
}
validateIgmpPacket(t, p, multicastAddr, header.IGMPv2MembershipReport, 0, multicastAddr)
}
validateIgmpPacket(t, p, multicastAddr, header.IGMPv1MembershipReport, 0, multicastAddr)
}
func TestSendQueuedIGMPReports(t *testing.T) {
+6
View File
@@ -229,6 +229,12 @@ func (e *endpoint) disableLocked() {
panic(fmt.Sprintf("unexpected error when removing address = %s: %s", ipv4BroadcastAddr.Address, err))
}
// Reset the IGMP V1 present flag.
//
// If the node comes back up on the same network, it will re-learn that it
// needs to perform IGMPv1.
e.mu.igmp.resetV1Present()
if !e.setEnabled(false) {
panic("should have only done work to disable the endpoint if it was enabled")
}