github.com/cilium/cilium@v1.16.2/pkg/signal/signal_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package signal
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/binary"
     9  	"io"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/cilium/ebpf/perf"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/cilium/cilium/pkg/byteorder"
    17  	"github.com/cilium/cilium/pkg/logging"
    18  	fakesignalmap "github.com/cilium/cilium/pkg/maps/signalmap/fake"
    19  )
    20  
    21  type testReader struct {
    22  	paused bool
    23  	closed bool
    24  	cpu    int
    25  	data   []byte
    26  	lost   uint64
    27  }
    28  
    29  func (r *testReader) Read() (perf.Record, error) {
    30  	if r.closed {
    31  		return perf.Record{}, io.EOF
    32  	}
    33  	return perf.Record{CPU: r.cpu, RawSample: r.data, LostSamples: r.lost}, nil
    34  }
    35  
    36  func (r *testReader) Pause() error {
    37  	r.paused = true
    38  	return nil
    39  }
    40  
    41  func (r *testReader) Resume() error {
    42  	r.paused = false
    43  	return nil
    44  }
    45  
    46  func (r *testReader) Close() error {
    47  	if r.closed {
    48  		return io.EOF
    49  	}
    50  	r.closed = true
    51  	return nil
    52  }
    53  
    54  func TestSignalSet(t *testing.T) {
    55  	buf := new(bytes.Buffer)
    56  	binary.Write(buf, byteorder.Native, SignalNatFillUp)
    57  
    58  	events := &testReader{cpu: 1, data: buf.Bytes()}
    59  	sm := &signalManager{events: events}
    60  	require.Equal(t, true, sm.isMuted())
    61  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
    62  	require.Equal(t, true, sm.isSignalMuted(SignalCTFillUp))
    63  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
    64  
    65  	// invalid signal, nothing changes
    66  	err := sm.UnmuteSignals(SignalType(16))
    67  	require.Error(t, err)
    68  	require.ErrorContains(t, err, "signal number not supported: 16")
    69  	require.Equal(t, true, sm.isMuted())
    70  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
    71  	require.Equal(t, true, sm.isSignalMuted(SignalCTFillUp))
    72  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
    73  
    74  	// 2 active signals
    75  	err = sm.UnmuteSignals(SignalNatFillUp, SignalCTFillUp)
    76  	require.Nil(t, err)
    77  	require.Equal(t, false, sm.isMuted())
    78  	require.Equal(t, false, sm.isSignalMuted(SignalNatFillUp))
    79  	require.Equal(t, false, sm.isSignalMuted(SignalCTFillUp))
    80  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
    81  
    82  	require.Equal(t, false, events.paused)
    83  	require.Equal(t, false, events.closed)
    84  
    85  	// Mute one, one still active
    86  	err = sm.MuteSignals(SignalNatFillUp)
    87  	require.Nil(t, err)
    88  	require.Equal(t, false, sm.isMuted())
    89  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
    90  	require.Equal(t, false, sm.isSignalMuted(SignalCTFillUp))
    91  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
    92  
    93  	require.Equal(t, false, events.paused)
    94  	require.Equal(t, false, events.closed)
    95  
    96  	// Nothing happens if the signal is already muted
    97  	err = sm.MuteSignals(SignalNatFillUp)
    98  	require.Nil(t, err)
    99  	require.Equal(t, false, sm.isMuted())
   100  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
   101  	require.Equal(t, false, sm.isSignalMuted(SignalCTFillUp))
   102  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
   103  
   104  	require.Equal(t, false, events.paused)
   105  	require.Equal(t, false, events.closed)
   106  
   107  	// Unmute one more
   108  	err = sm.UnmuteSignals(SignalAuthRequired)
   109  	require.Nil(t, err)
   110  	require.Equal(t, false, sm.isMuted())
   111  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
   112  	require.Equal(t, false, sm.isSignalMuted(SignalCTFillUp))
   113  	require.Equal(t, false, sm.isSignalMuted(SignalAuthRequired))
   114  
   115  	require.Equal(t, false, events.paused)
   116  	require.Equal(t, false, events.closed)
   117  
   118  	// Last signala are muted
   119  	err = sm.MuteSignals(SignalCTFillUp, SignalAuthRequired)
   120  	require.Nil(t, err)
   121  	require.Equal(t, true, sm.isMuted())
   122  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
   123  	require.Equal(t, true, sm.isSignalMuted(SignalCTFillUp))
   124  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
   125  
   126  	require.Equal(t, true, events.paused)
   127  	require.Equal(t, false, events.closed)
   128  
   129  	// A signal is unmuted again
   130  	err = sm.UnmuteSignals(SignalCTFillUp)
   131  	require.Nil(t, err)
   132  	require.Equal(t, false, sm.isMuted())
   133  	require.Equal(t, true, sm.isSignalMuted(SignalNatFillUp))
   134  	require.Equal(t, false, sm.isSignalMuted(SignalCTFillUp))
   135  	require.Equal(t, true, sm.isSignalMuted(SignalAuthRequired))
   136  
   137  	require.Equal(t, false, events.paused)
   138  	require.Equal(t, false, events.closed)
   139  }
   140  
   141  type SignalData uint32
   142  
   143  const (
   144  	// SignalProtoV4 denotes IPv4 protocol
   145  	SignalProtoV4 SignalData = iota
   146  	// SignalProtoV6 denotes IPv6 protocol
   147  	SignalProtoV6
   148  	SignalProtoMax
   149  )
   150  
   151  var signalProto = [SignalProtoMax]string{
   152  	SignalProtoV4: "ipv4",
   153  	SignalProtoV6: "ipv6",
   154  }
   155  
   156  // String implements fmt.Stringer for SignalData
   157  func (d SignalData) String() string {
   158  	return signalProto[d]
   159  }
   160  
   161  func TestLifeCycle(t *testing.T) {
   162  	logging.SetLogLevelToDebug()
   163  
   164  	buf1 := new(bytes.Buffer)
   165  	binary.Write(buf1, byteorder.Native, SignalNatFillUp)
   166  	binary.Write(buf1, byteorder.Native, SignalProtoV4)
   167  
   168  	buf2 := new(bytes.Buffer)
   169  	binary.Write(buf2, byteorder.Native, SignalCTFillUp)
   170  	binary.Write(buf2, byteorder.Native, SignalProtoV4)
   171  
   172  	messages := [][]byte{buf1.Bytes(), buf2.Bytes()}
   173  
   174  	sm := newSignalManager(fakesignalmap.NewFakeSignalMap(messages, time.Second))
   175  	require.Equal(t, true, sm.isMuted())
   176  
   177  	wakeup := make(chan SignalData, 1024)
   178  	err := sm.RegisterHandler(ChannelHandler(wakeup), SignalNatFillUp, SignalCTFillUp)
   179  	require.Nil(t, err)
   180  	require.Equal(t, false, sm.isMuted())
   181  
   182  	err = sm.start()
   183  	require.Nil(t, err)
   184  
   185  	select {
   186  	case x := <-wakeup:
   187  		sm.MuteSignals(SignalNatFillUp, SignalCTFillUp)
   188  		require.Equal(t, true, sm.isMuted())
   189  
   190  		ipv4 := false
   191  		ipv6 := false
   192  		if x == SignalProtoV4 {
   193  			ipv4 = true
   194  		} else if x == SignalProtoV6 {
   195  			ipv6 = true
   196  		}
   197  
   198  		// Drain current queue since we just woke up anyway.
   199  		for len(wakeup) > 0 {
   200  			x := <-wakeup
   201  			if x == SignalProtoV4 {
   202  				ipv4 = true
   203  			} else if x == SignalProtoV6 {
   204  				ipv6 = true
   205  			}
   206  		}
   207  
   208  		require.Equal(t, true, ipv4)
   209  		require.Equal(t, false, ipv6)
   210  
   211  	case <-time.After(5 * time.Second):
   212  		sm.MuteSignals(SignalNatFillUp, SignalCTFillUp)
   213  		require.Equal(t, true, sm.isMuted())
   214  
   215  		t.Fatal("No signals received on time.")
   216  	}
   217  
   218  	err = sm.stop()
   219  	require.Nil(t, err)
   220  }