diff --git a/go.mod b/go.mod index e257bd1..8906c6c 100644 --- a/go.mod +++ b/go.mod @@ -1,24 +1,22 @@ module github.com/yerden/go-dpdk -go 1.19 +go 1.22 require ( - github.com/prometheus/client_golang v1.14.0 - github.com/stretchr/testify v1.8.3 - golang.org/x/sys v0.4.0 + github.com/prometheus/client_golang v1.19.0 + github.com/stretchr/testify v1.9.0 + golang.org/x/sys v0.18.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.39.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 9ceb6dd..b0fae6b 100644 --- a/go.sum +++ b/go.sum @@ -5,43 +5,32 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lpm/common.go b/lpm/common.go index 4ca9054..8593050 100644 --- a/lpm/common.go +++ b/lpm/common.go @@ -2,28 +2,22 @@ package lpm import ( "encoding/binary" - "net" + "net/netip" ) -func cvtIPv4(addr net.IP) (ip uint32) { - if addr = addr.To4(); addr == nil { - panic("not an IPv4 address") - } - return binary.BigEndian.Uint32(addr[:]) +func cvtIPv4(addr netip.Addr) (ip uint32) { + a4 := addr.As4() + return binary.BigEndian.Uint32(a4[:]) } -func cvtIPv4Net(ipp net.IPNet) (ip uint32, prefix uint8) { - addr := ipp.IP.Mask(ipp.Mask) - ones, _ := ipp.Mask.Size() - return cvtIPv4(addr), uint8(ones) +func cvtIPv4Net(prefix netip.Prefix) (ip uint32, bits uint8) { + return cvtIPv4(prefix.Masked().Addr()), uint8(prefix.Bits()) } -func cvtIPv6Net(ipp net.IPNet) (ip [16]byte, prefix uint8) { - addr := ipp.IP.Mask(ipp.Mask) - ones, _ := ipp.Mask.Size() - if len(addr) <= 4 { +func cvtIPv6Net(prefix netip.Prefix) (ip [16]byte, bits uint8) { + addr := prefix.Masked().Addr() + if !addr.Is6() || addr.Is4In6() { panic("not an IPv6 address") } - copy(ip[:], addr.To16()) - return ip, uint8(ones) + return addr.As16(), uint8(prefix.Bits()) } diff --git a/lpm/lpm.go b/lpm/lpm.go index 47e7f20..616a20f 100644 --- a/lpm/lpm.go +++ b/lpm/lpm.go @@ -13,7 +13,7 @@ package lpm import "C" import ( - "net" + "net/netip" "unsafe" "github.com/yerden/go-dpdk/common" @@ -64,12 +64,13 @@ func FindExisting(name string, ptr interface{}) error { // containing the configuration. // // Returns handle to LPM object on success, and errno value: -// E_RTE_NO_CONFIG - function could not get pointer to rte_config structure -// E_RTE_SECONDARY - function was called from a secondary process instance -// EINVAL - invalid parameter passed to function -// ENOSPC - the maximum number of memzones has already been allocated -// EEXIST - a memzone with the same name already exists -// ENOMEM - no appropriate memory area found in which to create memzone +// +// E_RTE_NO_CONFIG - function could not get pointer to rte_config structure +// E_RTE_SECONDARY - function was called from a secondary process instance +// EINVAL - invalid parameter passed to function +// ENOSPC - the maximum number of memzones has already been allocated +// EEXIST - a memzone with the same name already exists +// ENOMEM - no appropriate memory area found in which to create memzone func Create(name string, socket int, cfg *Config) (*LPM, error) { s := C.CString(name) defer C.free(unsafe.Pointer(s)) @@ -95,21 +96,21 @@ func (r *LPM) Free() { // // ip/prefix is an IP address/subnet to add, nextHop is a value // associated with added IP subnet. -func (r *LPM) Add(ipnet net.IPNet, nextHop uint32) error { +func (r *LPM) Add(ipnet netip.Prefix, nextHop uint32) error { ip, prefix := cvtIPv4Net(ipnet) rc := C.rte_lpm_add((*C.struct_rte_lpm)(r), C.uint32_t(ip), C.uint8_t(prefix), C.uint32_t(nextHop)) return common.IntToErr(rc) } // Delete a rule from LPM object. Panics if ipnet is not IPv4 subnet. -func (r *LPM) Delete(ipnet net.IPNet) error { +func (r *LPM) Delete(ipnet netip.Prefix) error { ip, prefix := cvtIPv4Net(ipnet) rc := C.rte_lpm_delete((*C.struct_rte_lpm)(r), C.uint32_t(ip), C.uint8_t(prefix)) return common.IntToErr(rc) } // Lookup an IP in LPM object. Panics if ip is not IPv4 subnet. -func (r *LPM) Lookup(ip net.IP) (uint32, error) { +func (r *LPM) Lookup(ip netip.Addr) (uint32, error) { b := cvtIPv4(ip) var res uint32 rc := C.rte_lpm_lookup((*C.struct_rte_lpm)(r), C.uint32_t(b), (*C.uint32_t)(&res)) @@ -123,7 +124,7 @@ func (r *LPM) DeleteAll() { // IsRulePresent checks if a rule present in the LPM and returns // nextHop if it is. Panics if ipnet is not IPv4 subnet. -func (r *LPM) IsRulePresent(ipnet net.IPNet, nextHop *uint32) (bool, error) { +func (r *LPM) IsRulePresent(ipnet netip.Prefix, nextHop *uint32) (bool, error) { ip, prefix := cvtIPv4Net(ipnet) rc := C.rte_lpm_is_rule_present((*C.struct_rte_lpm)(r), C.uint32_t(ip), C.uint8_t(prefix), (*C.uint32_t)(nextHop)) n, err := common.IntOrErr(rc) diff --git a/lpm/lpm6.go b/lpm/lpm6.go index 713291f..ee137fd 100644 --- a/lpm/lpm6.go +++ b/lpm/lpm6.go @@ -8,7 +8,7 @@ package lpm import "C" import ( - "net" + "net/netip" "unsafe" "github.com/yerden/go-dpdk/common" @@ -31,12 +31,13 @@ type Config6 struct { // containing the configuration. // // Returns handle to LPM6 object on success, and errno value: -// E_RTE_NO_CONFIG - function could not get pointer to rte_config structure -// E_RTE_SECONDARY - function was called from a secondary process instance -// EINVAL - invalid parameter passed to function -// ENOSPC - the maximum number of memzones has already been allocated -// EEXIST - a memzone with the same name already exists -// ENOMEM - no appropriate memory area found in which to create memzone +// +// E_RTE_NO_CONFIG - function could not get pointer to rte_config structure +// E_RTE_SECONDARY - function was called from a secondary process instance +// EINVAL - invalid parameter passed to function +// ENOSPC - the maximum number of memzones has already been allocated +// EEXIST - a memzone with the same name already exists +// ENOMEM - no appropriate memory area found in which to create memzone func Create6(name string, socket int, cfg *Config6) (*LPM6, error) { s := C.CString(name) defer C.free(unsafe.Pointer(s)) @@ -62,23 +63,24 @@ func (r *LPM6) Free() { // // ip/prefix is an IP address/subnet to add, nextHop is a value // associated with added IP subnet. Panics if ip is not IPv6. -func (r *LPM6) Add(ipnet net.IPNet, nextHop uint32) error { +func (r *LPM6) Add(ipnet netip.Prefix, nextHop uint32) error { b, prefix := cvtIPv6Net(ipnet) rc := C.rte_lpm6_add((*C.struct_rte_lpm6)(r), (*C.uint8_t)(&b[0]), C.uint8_t(prefix), C.uint32_t(nextHop)) return common.IntToErr(rc) } // Delete a rule from LPM6 object. Panics if ip is not IPv6. -func (r *LPM6) Delete(ipnet net.IPNet) error { +func (r *LPM6) Delete(ipnet netip.Prefix) error { b, prefix := cvtIPv6Net(ipnet) rc := C.rte_lpm6_delete((*C.struct_rte_lpm6)(r), (*C.uint8_t)(&b[0]), C.uint8_t(prefix)) return common.IntToErr(rc) } // Lookup an IP in LPM6 object. Panics if ip is not IPv6. -func (r *LPM6) Lookup(ip net.IP) (uint32, error) { +func (r *LPM6) Lookup(ip netip.Addr) (uint32, error) { var res uint32 - rc := C.rte_lpm6_lookup((*C.struct_rte_lpm6)(r), (*C.uint8_t)(&ip[0]), (*C.uint32_t)(&res)) + ip16 := ip.As16() + rc := C.rte_lpm6_lookup((*C.struct_rte_lpm6)(r), (*C.uint8_t)(&ip16[0]), (*C.uint32_t)(&res)) return res, common.IntToErr(rc) } @@ -89,7 +91,7 @@ func (r *LPM6) DeleteAll() { // IsRulePresent checks if a rule present in the LPM6 and returns // nextHop if it is. Panics if ip is not IPv6. -func (r *LPM6) IsRulePresent(ipnet net.IPNet, nextHop *uint32) (bool, error) { +func (r *LPM6) IsRulePresent(ipnet netip.Prefix, nextHop *uint32) (bool, error) { b, prefix := cvtIPv6Net(ipnet) rc := C.rte_lpm6_is_rule_present((*C.struct_rte_lpm6)(r), (*C.uint8_t)(&b[0]), C.uint8_t(prefix), (*C.uint32_t)(nextHop)) n, err := common.IntOrErr(rc) diff --git a/lpm/lpm_test.go b/lpm/lpm_test.go index 05d9191..d6be44d 100644 --- a/lpm/lpm_test.go +++ b/lpm/lpm_test.go @@ -1,7 +1,7 @@ package lpm_test import ( - "net" + "net/netip" "syscall" "testing" @@ -10,21 +10,6 @@ import ( "github.com/yerden/go-dpdk/lpm" ) -func mustParseCIDR(s string) net.IPNet { - _, x, err := net.ParseCIDR(s) - if err != nil { - panic(err) - } - return *x -} - -func mustParseIP(s string) net.IP { - if x := net.ParseIP(s); x != nil { - return x - } - panic(s) -} - var cidrs = []string{ "192.168.0.1/24", "10.0.1.2/8", @@ -66,7 +51,7 @@ func TestLpmCreate(t *testing.T) { // populate LPM object with IPv4 err = eal.ExecOnMain(func(ctx *eal.LcoreCtx) { for _, s := range cidrs { - if ipnet := mustParseCIDR(s); ipnet.IP.To4() != nil { + if ipnet := netip.MustParsePrefix(s); ipnet.Addr().Is4() { if e = myaddr.Add(ipnet, 1); e != nil { return } @@ -79,13 +64,13 @@ func TestLpmCreate(t *testing.T) { // test lookup var hop uint32 err = eal.ExecOnMain(func(ctx *eal.LcoreCtx) { - if hop, e = myaddr.Lookup(net.IPv4(10, 0, 0, 0)); e != nil { + if hop, e = myaddr.Lookup(netip.AddrFrom4([4]byte{10, 0, 0, 0})); e != nil { return } - if hop, e = myaddr.Lookup(net.IPv4(10, 1, 0, 0)); e != nil { + if hop, e = myaddr.Lookup(netip.AddrFrom4([4]byte{10, 1, 0, 0})); e != nil { return } - if hop, e = myaddr.Lookup(net.IPv4(10, 2, 0, 0)); e != nil { + if hop, e = myaddr.Lookup(netip.AddrFrom4([4]byte{10, 2, 0, 0})); e != nil { return } }) @@ -94,7 +79,7 @@ func TestLpmCreate(t *testing.T) { // test lookup err = eal.ExecOnMain(func(ctx *eal.LcoreCtx) { - hop, e = myaddr.Lookup(net.IPv4(11, 0, 0, 0)) + hop, e = myaddr.Lookup(netip.AddrFrom4([4]byte{11, 0, 0, 0})) }) assert(err == nil && e == syscall.ENOENT, err, e) } @@ -133,7 +118,7 @@ func TestLpm6Create(t *testing.T) { // populate LPM object with IPv6 err = eal.ExecOnMain(func(ctx *eal.LcoreCtx) { for _, s := range cidrs { - if ipnet := mustParseCIDR(s); len(ipnet.IP) == 16 { + if ipnet := netip.MustParsePrefix(s); ipnet.Addr().Is6() { if e = myaddr.Add(ipnet, 1); e != nil { return } @@ -146,13 +131,13 @@ func TestLpm6Create(t *testing.T) { // test lookup var hop uint32 err = eal.ExecOnMain(func(ctx *eal.LcoreCtx) { - if hop, e = myaddr.Lookup(mustParseIP("2001:db8:a0b:12f0::1")); e != nil { + if hop, e = myaddr.Lookup(netip.MustParseAddr("2001:db8:a0b:12f0::1")); e != nil { return } - if hop, e = myaddr.Lookup(mustParseIP("2001:db8:a0b:12f0::2")); e != nil { + if hop, e = myaddr.Lookup(netip.MustParseAddr("2001:db8:a0b:12f0::2")); e != nil { return } - if hop, e = myaddr.Lookup(mustParseIP("2001:db8:a0b:12f0:0a0a::2")); e != nil { + if hop, e = myaddr.Lookup(netip.MustParseAddr("2001:db8:a0b:12f0:0a0a::2")); e != nil { return } }) @@ -161,7 +146,7 @@ func TestLpm6Create(t *testing.T) { // test lookup err = eal.ExecOnMain(func(ctx *eal.LcoreCtx) { - hop, e = myaddr.Lookup(mustParseIP("2001:db9:a0b:12f0:0a0a::2")) + hop, e = myaddr.Lookup(netip.MustParseAddr("2001:db9:a0b:12f0:0a0a::2")) }) assert(err == nil && e == syscall.ENOENT, err, e) }