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