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 }