github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/addr_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package netlink
     5  
     6  import (
     7  	"net"
     8  	"os"
     9  	"testing"
    10  	"time"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func TestAddrAdd(t *testing.T) {
    16  	DoTestAddr(t, AddrAdd)
    17  }
    18  
    19  func TestAddrReplace(t *testing.T) {
    20  	DoTestAddr(t, AddrReplace)
    21  }
    22  
    23  func DoTestAddr(t *testing.T, FunctionUndertest func(Link, *Addr) error) {
    24  	if os.Getenv("CI") == "true" {
    25  		t.Skipf("Fails in CI with: addr_test.go:*: Address flags not set properly, got=128, expected=132")
    26  	}
    27  	// TODO: IFA_F_PERMANENT does not seem to be set by default on older kernels?
    28  	// TODO: IFA_F_OPTIMISTIC failing in CI. should we just skip that one check?
    29  	var address = &net.IPNet{IP: net.IPv4(127, 0, 0, 2), Mask: net.CIDRMask(32, 32)}
    30  	var peer = &net.IPNet{IP: net.IPv4(127, 0, 0, 3), Mask: net.CIDRMask(24, 32)}
    31  	var addrTests = []struct {
    32  		addr     *Addr
    33  		expected *Addr
    34  	}{
    35  		{
    36  			&Addr{IPNet: address},
    37  			&Addr{IPNet: address, Label: "lo", Scope: unix.RT_SCOPE_UNIVERSE, Flags: unix.IFA_F_PERMANENT},
    38  		},
    39  		{
    40  			&Addr{IPNet: address, Label: "local"},
    41  			&Addr{IPNet: address, Label: "local", Scope: unix.RT_SCOPE_UNIVERSE, Flags: unix.IFA_F_PERMANENT},
    42  		},
    43  		{
    44  			&Addr{IPNet: address, Flags: unix.IFA_F_OPTIMISTIC},
    45  			&Addr{IPNet: address, Label: "lo", Flags: unix.IFA_F_OPTIMISTIC | unix.IFA_F_PERMANENT, Scope: unix.RT_SCOPE_UNIVERSE},
    46  		},
    47  		{
    48  			&Addr{IPNet: address, Flags: unix.IFA_F_OPTIMISTIC | unix.IFA_F_DADFAILED},
    49  			&Addr{IPNet: address, Label: "lo", Flags: unix.IFA_F_OPTIMISTIC | unix.IFA_F_DADFAILED | unix.IFA_F_PERMANENT, Scope: unix.RT_SCOPE_UNIVERSE},
    50  		},
    51  		{
    52  			&Addr{IPNet: address, Scope: unix.RT_SCOPE_NOWHERE},
    53  			&Addr{IPNet: address, Label: "lo", Flags: unix.IFA_F_PERMANENT, Scope: unix.RT_SCOPE_NOWHERE},
    54  		},
    55  		{
    56  			&Addr{IPNet: address, Peer: peer},
    57  			&Addr{IPNet: address, Peer: peer, Label: "lo", Scope: unix.RT_SCOPE_UNIVERSE, Flags: unix.IFA_F_PERMANENT},
    58  		},
    59  	}
    60  
    61  	tearDown := setUpNetlinkTest(t)
    62  	defer tearDown()
    63  
    64  	link, err := LinkByName("lo")
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  
    69  	for _, tt := range addrTests {
    70  		if err = FunctionUndertest(link, tt.addr); err != nil {
    71  			t.Fatal(err)
    72  		}
    73  
    74  		addrs, err := AddrList(link, FAMILY_ALL)
    75  		if err != nil {
    76  			t.Fatal(err)
    77  		}
    78  
    79  		if len(addrs) != 1 {
    80  			t.Fatal("Address not added properly")
    81  		}
    82  
    83  		if !addrs[0].Equal(*tt.expected) {
    84  			t.Fatalf("Address ip no set properly, got=%s, expected=%s", addrs[0], tt.expected)
    85  		}
    86  
    87  		if addrs[0].Label != tt.expected.Label {
    88  			t.Fatalf("Address label not set properly, got=%s, expected=%s", addrs[0].Label, tt.expected.Label)
    89  		}
    90  
    91  		if addrs[0].Flags != tt.expected.Flags {
    92  			t.Fatalf("Address flags not set properly, got=%d, expected=%d", addrs[0].Flags, tt.expected.Flags)
    93  		}
    94  
    95  		if addrs[0].Scope != tt.expected.Scope {
    96  			t.Fatalf("Address scope not set properly, got=%d, expected=%d", addrs[0].Scope, tt.expected.Scope)
    97  		}
    98  
    99  		if ifindex := link.Attrs().Index; ifindex != addrs[0].LinkIndex {
   100  			t.Fatalf("Address ifindex not set properly, got=%d, expected=%d", addrs[0].LinkIndex, ifindex)
   101  		}
   102  
   103  		if tt.expected.Peer != nil {
   104  			if !addrs[0].PeerEqual(*tt.expected) {
   105  				t.Fatalf("Peer Address ip no set properly, got=%s, expected=%s", addrs[0].Peer, tt.expected.Peer)
   106  			}
   107  		}
   108  
   109  		// Pass FAMILY_V4, we should get the same results as FAMILY_ALL
   110  		addrs, err = AddrList(link, FAMILY_V4)
   111  		if err != nil {
   112  			t.Fatal(err)
   113  		}
   114  		if len(addrs) != 1 {
   115  			t.Fatal("Address not added properly")
   116  		}
   117  
   118  		// Pass a wrong family number, we should get nil list
   119  		addrs, err = AddrList(link, 0x8)
   120  		if err != nil {
   121  			t.Fatal(err)
   122  		}
   123  
   124  		if len(addrs) != 0 {
   125  			t.Fatal("Address not expected")
   126  		}
   127  
   128  		if err = AddrDel(link, tt.addr); err != nil {
   129  			t.Fatal(err)
   130  		}
   131  
   132  		addrs, err = AddrList(link, FAMILY_ALL)
   133  		if err != nil {
   134  			t.Fatal(err)
   135  		}
   136  
   137  		if len(addrs) != 0 {
   138  			t.Fatal("Address not removed properly")
   139  		}
   140  	}
   141  
   142  }
   143  
   144  func TestAddrAddReplace(t *testing.T) {
   145  	tearDown := setUpNetlinkTest(t)
   146  	defer tearDown()
   147  
   148  	var address = &net.IPNet{IP: net.IPv4(127, 0, 0, 2), Mask: net.CIDRMask(24, 32)}
   149  	var addr = &Addr{IPNet: address}
   150  
   151  	link, err := LinkByName("lo")
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	err = AddrAdd(link, addr)
   157  	if err != nil {
   158  		t.Fatal(err)
   159  	}
   160  
   161  	addrs, err := AddrList(link, FAMILY_ALL)
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  
   166  	if len(addrs) != 1 {
   167  		t.Fatal("Address not added properly")
   168  	}
   169  
   170  	err = AddrAdd(link, addr)
   171  	if err == nil {
   172  		t.Fatal("Re-adding address should fail (but succeeded unexpectedly).")
   173  	}
   174  
   175  	err = AddrReplace(link, addr)
   176  	if err != nil {
   177  		t.Fatal("Replacing address failed.")
   178  	}
   179  
   180  	addrs, err = AddrList(link, FAMILY_ALL)
   181  	if err != nil {
   182  		t.Fatal(err)
   183  	}
   184  
   185  	if len(addrs) != 1 {
   186  		t.Fatal("Address not added properly")
   187  	}
   188  
   189  	if err = AddrDel(link, addr); err != nil {
   190  		t.Fatal(err)
   191  	}
   192  
   193  	addrs, err = AddrList(link, FAMILY_ALL)
   194  	if err != nil {
   195  		t.Fatal(err)
   196  	}
   197  
   198  	if len(addrs) != 0 {
   199  		t.Fatal("Address not removed properly")
   200  	}
   201  }
   202  
   203  func expectAddrUpdate(ch <-chan AddrUpdate, add bool, dst net.IP) bool {
   204  	for {
   205  		timeout := time.After(time.Minute)
   206  		select {
   207  		case update := <-ch:
   208  			if update.NewAddr == add && update.LinkAddress.IP.Equal(dst) {
   209  				return true
   210  			}
   211  		case <-timeout:
   212  			return false
   213  		}
   214  	}
   215  }
   216  
   217  func TestAddrSubscribeWithOptions(t *testing.T) {
   218  	tearDown := setUpNetlinkTest(t)
   219  	defer tearDown()
   220  
   221  	ch := make(chan AddrUpdate)
   222  	done := make(chan struct{})
   223  	defer close(done)
   224  	var lastError error
   225  	defer func() {
   226  		if lastError != nil {
   227  			t.Fatalf("Fatal error received during subscription: %v", lastError)
   228  		}
   229  	}()
   230  	if err := AddrSubscribeWithOptions(ch, done, AddrSubscribeOptions{
   231  		ErrorCallback: func(err error) {
   232  			lastError = err
   233  		},
   234  	}); err != nil {
   235  		t.Fatal(err)
   236  	}
   237  
   238  	// get loopback interface
   239  	link, err := LinkByName("lo")
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  
   244  	// bring the interface up
   245  	if err = LinkSetUp(link); err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	ip := net.IPv4(127, 0, 0, 1)
   250  	if !expectAddrUpdate(ch, true, ip) {
   251  		t.Fatal("Add update not received as expected")
   252  	}
   253  }
   254  
   255  func TestAddrSubscribeListExisting(t *testing.T) {
   256  	tearDown := setUpNetlinkTest(t)
   257  	defer tearDown()
   258  
   259  	ch := make(chan AddrUpdate)
   260  	done := make(chan struct{})
   261  	defer close(done)
   262  
   263  	// get loopback interface
   264  	link, err := LinkByName("lo")
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  
   269  	// bring the interface up
   270  	if err = LinkSetUp(link); err != nil {
   271  		t.Fatal(err)
   272  	}
   273  
   274  	var lastError error
   275  	defer func() {
   276  		if lastError != nil {
   277  			t.Fatalf("Fatal error received during subscription: %v", lastError)
   278  		}
   279  	}()
   280  	if err := AddrSubscribeWithOptions(ch, done, AddrSubscribeOptions{
   281  		ErrorCallback: func(err error) {
   282  			lastError = err
   283  		},
   284  		ListExisting: true,
   285  	}); err != nil {
   286  		t.Fatal(err)
   287  	}
   288  
   289  	ip := net.IPv4(127, 0, 0, 1)
   290  	if !expectAddrUpdate(ch, true, ip) {
   291  		t.Fatal("Add update not received as expected")
   292  	}
   293  }