github.com/vishvananda/netlink@v1.3.0/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  	for _, nilLink := range []bool{false, true} {
   149  		var address = &net.IPNet{IP: net.IPv4(127, 0, 0, 2), Mask: net.CIDRMask(24, 32)}
   150  		var addr = &Addr{IPNet: address}
   151  
   152  		link, err := LinkByName("lo")
   153  		if err != nil {
   154  			t.Fatal(err)
   155  		}
   156  
   157  		if nilLink {
   158  			addr.LinkIndex = link.Attrs().Index
   159  			link = nil
   160  		}
   161  
   162  		err = AddrAdd(link, addr)
   163  		if err != nil {
   164  			t.Fatal(err)
   165  		}
   166  
   167  		addrs, err := AddrList(link, FAMILY_ALL)
   168  		if err != nil {
   169  			t.Fatal(err)
   170  		}
   171  
   172  		if len(addrs) != 1 {
   173  			t.Fatal("Address not added properly")
   174  		}
   175  
   176  		err = AddrAdd(link, addr)
   177  		if err == nil {
   178  			t.Fatal("Re-adding address should fail (but succeeded unexpectedly).")
   179  		}
   180  
   181  		err = AddrReplace(link, addr)
   182  		if err != nil {
   183  			t.Fatal("Replacing address failed.")
   184  		}
   185  
   186  		addrs, err = AddrList(link, FAMILY_ALL)
   187  		if err != nil {
   188  			t.Fatal(err)
   189  		}
   190  
   191  		if len(addrs) != 1 {
   192  			t.Fatal("Address not added properly")
   193  		}
   194  
   195  		if err = AddrDel(link, addr); err != nil {
   196  			t.Fatal(err)
   197  		}
   198  
   199  		addrs, err = AddrList(link, FAMILY_ALL)
   200  		if err != nil {
   201  			t.Fatal(err)
   202  		}
   203  
   204  		if len(addrs) != 0 {
   205  			t.Fatal("Address not removed properly")
   206  		}
   207  	}
   208  }
   209  
   210  func expectAddrUpdate(ch <-chan AddrUpdate, add bool, dst net.IP) bool {
   211  	for {
   212  		timeout := time.After(time.Minute)
   213  		select {
   214  		case update := <-ch:
   215  			if update.NewAddr == add && update.LinkAddress.IP.Equal(dst) {
   216  				return true
   217  			}
   218  		case <-timeout:
   219  			return false
   220  		}
   221  	}
   222  }
   223  
   224  func TestAddrSubscribeWithOptions(t *testing.T) {
   225  	tearDown := setUpNetlinkTest(t)
   226  	defer tearDown()
   227  
   228  	ch := make(chan AddrUpdate)
   229  	done := make(chan struct{})
   230  	defer close(done)
   231  	var lastError error
   232  	defer func() {
   233  		if lastError != nil {
   234  			t.Fatalf("Fatal error received during subscription: %v", lastError)
   235  		}
   236  	}()
   237  	if err := AddrSubscribeWithOptions(ch, done, AddrSubscribeOptions{
   238  		ErrorCallback: func(err error) {
   239  			lastError = err
   240  		},
   241  	}); err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	// get loopback interface
   246  	link, err := LinkByName("lo")
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  
   251  	// bring the interface up
   252  	if err = LinkSetUp(link); err != nil {
   253  		t.Fatal(err)
   254  	}
   255  
   256  	ip := net.IPv4(127, 0, 0, 1)
   257  	if !expectAddrUpdate(ch, true, ip) {
   258  		t.Fatal("Add update not received as expected")
   259  	}
   260  }
   261  
   262  func TestAddrSubscribeListExisting(t *testing.T) {
   263  	tearDown := setUpNetlinkTest(t)
   264  	defer tearDown()
   265  
   266  	ch := make(chan AddrUpdate)
   267  	done := make(chan struct{})
   268  	defer close(done)
   269  
   270  	// get loopback interface
   271  	link, err := LinkByName("lo")
   272  	if err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	// bring the interface up
   277  	if err = LinkSetUp(link); err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	var lastError error
   282  	defer func() {
   283  		if lastError != nil {
   284  			t.Fatalf("Fatal error received during subscription: %v", lastError)
   285  		}
   286  	}()
   287  	if err := AddrSubscribeWithOptions(ch, done, AddrSubscribeOptions{
   288  		ErrorCallback: func(err error) {
   289  			lastError = err
   290  		},
   291  		ListExisting: true,
   292  	}); err != nil {
   293  		t.Fatal(err)
   294  	}
   295  
   296  	ip := net.IPv4(127, 0, 0, 1)
   297  	if !expectAddrUpdate(ch, true, ip) {
   298  		t.Fatal("Add update not received as expected")
   299  	}
   300  }