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