gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/link/fdbased/endpoint_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build linux 16 // +build linux 17 18 package fdbased 19 20 import ( 21 "bytes" 22 "fmt" 23 "math/rand" 24 "os" 25 "slices" 26 "testing" 27 "time" 28 "unsafe" 29 30 "github.com/google/go-cmp/cmp" 31 "golang.org/x/sys/unix" 32 "gvisor.dev/gvisor/pkg/buffer" 33 "gvisor.dev/gvisor/pkg/refs" 34 "gvisor.dev/gvisor/pkg/tcpip" 35 "gvisor.dev/gvisor/pkg/tcpip/header" 36 "gvisor.dev/gvisor/pkg/tcpip/stack" 37 ) 38 39 const ( 40 mtu = 1500 41 laddr = tcpip.LinkAddress("\x11\x22\x33\x44\x55\x66") 42 raddr = tcpip.LinkAddress("\x77\x88\x99\xaa\xbb\xcc") 43 proto = 10 44 csumOffset = 48 45 gsoMSS = 500 46 ) 47 48 type packetInfo struct { 49 Proto tcpip.NetworkProtocolNumber 50 Contents *stack.PacketBuffer 51 } 52 53 type packetContents struct { 54 LinkHeader []byte 55 NetworkHeader []byte 56 TransportHeader []byte 57 Data []byte 58 } 59 60 func checkPacketInfoEqual(t *testing.T, got, want packetInfo) { 61 t.Helper() 62 if diff := cmp.Diff( 63 want, got, 64 cmp.Transformer("ExtractPacketBuffer", func(pk *stack.PacketBuffer) *packetContents { 65 if pk == nil { 66 return nil 67 } 68 return &packetContents{ 69 LinkHeader: pk.LinkHeader().Slice(), 70 NetworkHeader: pk.NetworkHeader().Slice(), 71 TransportHeader: pk.TransportHeader().Slice(), 72 Data: pk.Data().AsRange().ToSlice(), 73 } 74 }), 75 ); diff != "" { 76 t.Errorf("unexpected packetInfo (-want +got):\n%s", diff) 77 } 78 } 79 80 type context struct { 81 t *testing.T 82 readFDs []int 83 writeFDs []int 84 ep stack.LinkEndpoint 85 ch chan packetInfo 86 done chan struct{} 87 } 88 89 func newContext(t *testing.T, opt *Options) *context { 90 firstFDPair, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_SEQPACKET, 0) 91 if err != nil { 92 t.Fatalf("Socketpair failed: %v", err) 93 } 94 secondFDPair, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_SEQPACKET, 0) 95 if err != nil { 96 t.Fatalf("Socketpair failed: %v", err) 97 } 98 99 done := make(chan struct{}, 2) 100 opt.ClosedFunc = func(tcpip.Error) { 101 done <- struct{}{} 102 } 103 104 opt.FDs = []int{firstFDPair[1], secondFDPair[1]} 105 ep, err := New(opt) 106 if err != nil { 107 t.Fatalf("Failed to create FD endpoint: %v", err) 108 } 109 110 c := &context{ 111 t: t, 112 readFDs: []int{firstFDPair[0], secondFDPair[0]}, 113 writeFDs: opt.FDs, 114 ep: ep, 115 ch: make(chan packetInfo, 100), 116 done: done, 117 } 118 119 ep.Attach(c) 120 121 return c 122 } 123 124 func (c *context) cleanup() { 125 for _, fd := range c.readFDs { 126 unix.Close(fd) 127 } 128 <-c.done 129 <-c.done 130 for _, fd := range c.writeFDs { 131 unix.Close(fd) 132 } 133 } 134 135 func (c *context) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 136 pkt.IncRef() 137 c.ch <- packetInfo{protocol, pkt} 138 } 139 140 func (c *context) DeliverLinkPacket(tcpip.NetworkProtocolNumber, *stack.PacketBuffer) { 141 c.t.Fatal("DeliverLinkPacket not implemented") 142 } 143 144 func TestNoEthernetProperties(t *testing.T) { 145 c := newContext(t, &Options{MTU: mtu}) 146 defer c.cleanup() 147 148 if want, v := uint16(0), c.ep.MaxHeaderLength(); want != v { 149 t.Fatalf("MaxHeaderLength() = %v, want %v", v, want) 150 } 151 152 if want, v := uint32(mtu), c.ep.MTU(); want != v { 153 t.Fatalf("MTU() = %v, want %v", v, want) 154 } 155 } 156 157 func TestEthernetProperties(t *testing.T) { 158 c := newContext(t, &Options{EthernetHeader: true, MTU: mtu}) 159 defer c.cleanup() 160 161 if want, v := uint16(header.EthernetMinimumSize), c.ep.MaxHeaderLength(); want != v { 162 t.Fatalf("MaxHeaderLength() = %v, want %v", v, want) 163 } 164 165 if want, v := uint32(mtu), c.ep.MTU(); want != v { 166 t.Fatalf("MTU() = %v, want %v", v, want) 167 } 168 } 169 170 func TestAddress(t *testing.T) { 171 addrs := []tcpip.LinkAddress{"", "abc", "def"} 172 for _, a := range addrs { 173 t.Run(fmt.Sprintf("Address: %q", a), func(t *testing.T) { 174 c := newContext(t, &Options{Address: a, MTU: mtu}) 175 defer c.cleanup() 176 177 if want, v := a, c.ep.LinkAddress(); want != v { 178 t.Fatalf("LinkAddress() = %v, want %v", v, want) 179 } 180 }) 181 } 182 } 183 184 func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32, hash uint32) { 185 c := newContext(t, &Options{Address: laddr, MTU: mtu, EthernetHeader: eth, GSOMaxSize: gsoMaxSize}) 186 defer c.cleanup() 187 188 // Build payload. 189 payload := make([]byte, plen) 190 if _, err := rand.Read(payload); err != nil { 191 t.Fatalf("rand.Read(payload): %s", err) 192 } 193 194 // Build packet buffer. 195 const netHdrLen = 100 196 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 197 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()) + netHdrLen, 198 Payload: buffer.MakeWithData(payload), 199 }) 200 defer pkt.DecRef() 201 pkt.Hash = hash 202 // Every PacketBuffer must have these set: 203 // See nic.writePacket. 204 pkt.EgressRoute.LocalLinkAddress = laddr 205 pkt.EgressRoute.RemoteLinkAddress = raddr 206 pkt.NetworkProtocolNumber = proto 207 208 // Build header. 209 b := pkt.NetworkHeader().Push(netHdrLen) 210 if _, err := rand.Read(b); err != nil { 211 t.Fatalf("rand.Read(b): %s", err) 212 } 213 214 // Write. 215 want := append(append([]byte{}, b...), payload...) 216 const l3HdrLen = header.IPv6MinimumSize 217 if gsoMaxSize != 0 { 218 pkt.GSOOptions = stack.GSO{ 219 Type: stack.GSOTCPv6, 220 NeedsCsum: true, 221 CsumOffset: csumOffset, 222 MSS: gsoMSS, 223 L3HdrLen: l3HdrLen, 224 } 225 } 226 227 c.ep.AddHeader(pkt) 228 229 var pkts stack.PacketBufferList 230 pkts.PushBack(pkt) 231 if _, err := c.ep.WritePackets(pkts); err != nil { 232 t.Fatalf("WritePackets failed: %s", err) 233 } 234 235 // Read from the corresponding FD, then compare with what we wrote. 236 b = make([]byte, mtu) 237 fd := c.readFDs[hash%uint32(len(c.readFDs))] 238 n, err := unix.Read(fd, b) 239 if err != nil { 240 t.Fatalf("Read failed: %v", err) 241 } 242 b = b[:n] 243 if gsoMaxSize != 0 { 244 vnetHdr := *(*virtioNetHdr)(unsafe.Pointer(&b[0])) 245 if vnetHdr.flags&_VIRTIO_NET_HDR_F_NEEDS_CSUM == 0 { 246 t.Fatalf("virtioNetHdr.flags %v doesn't contain %v", vnetHdr.flags, _VIRTIO_NET_HDR_F_NEEDS_CSUM) 247 } 248 const csumStart = header.EthernetMinimumSize + l3HdrLen 249 if vnetHdr.csumStart != csumStart { 250 t.Fatalf("vnetHdr.csumStart = %v, want %v", vnetHdr.csumStart, csumStart) 251 } 252 if vnetHdr.csumOffset != csumOffset { 253 t.Fatalf("vnetHdr.csumOffset = %v, want %v", vnetHdr.csumOffset, csumOffset) 254 } 255 gsoType := uint8(0) 256 if plen > gsoMSS { 257 gsoType = _VIRTIO_NET_HDR_GSO_TCPV6 258 } 259 if vnetHdr.gsoType != gsoType { 260 t.Fatalf("vnetHdr.gsoType = %v, want %v", vnetHdr.gsoType, gsoType) 261 } 262 b = b[virtioNetHdrSize:] 263 } 264 if eth { 265 h := header.Ethernet(b) 266 b = b[header.EthernetMinimumSize:] 267 268 if a := h.SourceAddress(); a != laddr { 269 t.Fatalf("SourceAddress() = %v, want %v", a, laddr) 270 } 271 272 if a := h.DestinationAddress(); a != raddr { 273 t.Fatalf("DestinationAddress() = %v, want %v", a, raddr) 274 } 275 276 if et := h.Type(); et != proto { 277 t.Fatalf("Type() = %v, want %v", et, proto) 278 } 279 } 280 if len(b) != len(want) { 281 t.Fatalf("Read returned %v bytes, want %v", len(b), len(want)) 282 } 283 if !bytes.Equal(b, want) { 284 t.Fatalf("Read returned %x, want %x", b, want) 285 } 286 } 287 288 func TestWritePacket(t *testing.T) { 289 lengths := []int{0, 100, 1000} 290 eths := []bool{true, false} 291 gsos := []uint32{0, 32768} 292 293 for _, eth := range eths { 294 for _, plen := range lengths { 295 for _, gso := range gsos { 296 t.Run( 297 fmt.Sprintf("Eth=%v,PayloadLen=%v,GSOMaxSize=%v", eth, plen, gso), 298 func(t *testing.T) { 299 testWritePacket(t, plen, eth, gso, 0) 300 }, 301 ) 302 } 303 } 304 } 305 } 306 307 func TestHashedWritePacket(t *testing.T) { 308 lengths := []int{0, 100, 1000} 309 eths := []bool{true, false} 310 gsos := []uint32{0, 32768} 311 hashes := []uint32{0, 1} 312 for _, eth := range eths { 313 for _, plen := range lengths { 314 for _, gso := range gsos { 315 for _, hash := range hashes { 316 t.Run( 317 fmt.Sprintf("Eth=%v,PayloadLen=%v,GSOMaxSize=%v,Hash=%d", eth, plen, gso, hash), 318 func(t *testing.T) { 319 testWritePacket(t, plen, eth, gso, hash) 320 }, 321 ) 322 } 323 } 324 } 325 } 326 } 327 328 func TestPreserveSrcAddress(t *testing.T) { 329 baddr := tcpip.LinkAddress("\xcc\xbb\xaa\x77\x88\x99") 330 331 c := newContext(t, &Options{Address: laddr, MTU: mtu, EthernetHeader: true}) 332 defer c.cleanup() 333 334 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 335 // WritePacket panics given a prependable with anything less than 336 // the minimum size of the ethernet header. 337 // TODO(b/153685824): Figure out if this should use c.ep.MaxHeaderLength(). 338 ReserveHeaderBytes: header.EthernetMinimumSize, 339 }) 340 defer pkt.DecRef() 341 // Every PacketBuffer must have these set: 342 // See nic.writePacket. 343 pkt.NetworkProtocolNumber = proto 344 // Set LocalLinkAddress in route to the value of the bridged address. 345 pkt.EgressRoute.LocalLinkAddress = baddr 346 pkt.EgressRoute.RemoteLinkAddress = raddr 347 c.ep.AddHeader(pkt) 348 349 var pkts stack.PacketBufferList 350 pkts.PushBack(pkt) 351 if _, err := c.ep.WritePackets(pkts); err != nil { 352 t.Fatalf("WritePackets failed: %s", err) 353 } 354 355 // Read from the FD, then compare with what we wrote. 356 b := make([]byte, mtu) 357 n, err := unix.Read(c.readFDs[0], b) 358 if err != nil { 359 t.Fatalf("Read failed: %v", err) 360 } 361 b = b[:n] 362 h := header.Ethernet(b) 363 364 if a := h.SourceAddress(); a != baddr { 365 t.Fatalf("SourceAddress() = %v, want %v", a, baddr) 366 } 367 } 368 369 func TestDeliverPacket(t *testing.T) { 370 lengths := []int{100, 1000} 371 eths := []bool{true, false} 372 373 for _, eth := range eths { 374 for _, plen := range lengths { 375 t.Run(fmt.Sprintf("Eth=%v,PayloadLen=%v", eth, plen), func(t *testing.T) { 376 c := newContext(t, &Options{Address: laddr, MTU: mtu, EthernetHeader: eth}) 377 defer c.cleanup() 378 379 // Build packet. 380 all := make([]byte, plen) 381 if _, err := rand.Read(all); err != nil { 382 t.Fatalf("rand.Read(all): %s", err) 383 } 384 // Make it look like an IPv4 packet. 385 all[0] = 0x40 386 387 wantPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 388 ReserveHeaderBytes: header.EthernetMinimumSize, 389 Payload: buffer.MakeWithData(all), 390 }) 391 defer wantPkt.DecRef() 392 if eth { 393 hdr := header.Ethernet(wantPkt.LinkHeader().Push(header.EthernetMinimumSize)) 394 hdr.Encode(&header.EthernetFields{ 395 SrcAddr: raddr, 396 DstAddr: laddr, 397 Type: proto, 398 }) 399 all = append(hdr, all...) 400 } 401 402 // Write packet via the file descriptor. 403 if _, err := unix.Write(c.readFDs[0], all); err != nil { 404 t.Fatalf("Write failed: %v", err) 405 } 406 407 // Receive packet through the endpoint. 408 select { 409 case pi := <-c.ch: 410 defer pi.Contents.DecRef() 411 want := packetInfo{ 412 Proto: proto, 413 Contents: wantPkt, 414 } 415 if !eth { 416 want.Proto = header.IPv4ProtocolNumber 417 } 418 checkPacketInfoEqual(t, pi, want) 419 case <-time.After(10 * time.Second): 420 t.Fatalf("Timed out waiting for packet") 421 } 422 }) 423 } 424 } 425 } 426 427 func TestBufConfigMaxLength(t *testing.T) { 428 got := 0 429 for _, i := range BufConfig { 430 got += i 431 } 432 want := header.MaxIPPacketSize // maximum TCP packet size 433 if got < want { 434 t.Errorf("total buffer size is invalid: got %d, want >= %d", got, want) 435 } 436 } 437 438 func TestBufConfigFirst(t *testing.T) { 439 // The stack assumes that the TCP/IP header is entirely contained in the first view. 440 // Therefore, the first view needs to be large enough to contain the maximum TCP/IP 441 // header, which is 120 bytes (60 bytes for IP + 60 bytes for TCP). 442 want := 120 443 got := BufConfig[0] 444 if got < want { 445 t.Errorf("first view has an invalid size: got %d, want >= %d", got, want) 446 } 447 } 448 449 var capLengthTestCases = []struct { 450 comment string 451 config []int 452 n int 453 wantUsed int 454 wantLengths []int 455 }{ 456 { 457 comment: "Single slice", 458 config: []int{256}, 459 n: 128, 460 wantUsed: 1, 461 wantLengths: []int{128}, 462 }, 463 { 464 comment: "Multiple slices", 465 config: []int{128, 256}, 466 n: 256, 467 wantUsed: 2, 468 wantLengths: []int{128, 128}, 469 }, 470 { 471 comment: "Entire buffer", 472 config: []int{128, 256}, 473 n: 384, 474 wantUsed: 2, 475 wantLengths: []int{128, 256}, 476 }, 477 { 478 comment: "Entire buffer but not on the last slice", 479 config: []int{128, 256, 512}, 480 n: 384, 481 wantUsed: 2, 482 wantLengths: []int{128, 256}, 483 }, 484 } 485 486 func TestIovecBuffer(t *testing.T) { 487 for _, c := range capLengthTestCases { 488 t.Run(c.comment, func(t *testing.T) { 489 b := newIovecBuffer(c.config, false /* skipsVnetHdr */) 490 defer b.release() 491 492 // Test initial allocation. 493 iovecs := b.nextIovecs() 494 if got, want := len(iovecs), len(c.config); got != want { 495 t.Fatalf("len(iovecs) = %d, want %d", got, want) 496 } 497 498 // Make a copy as iovecs points to internal slice. We will need this state 499 // later. 500 oldIovecs := append([]unix.Iovec(nil), iovecs...) 501 502 // Test the buffer that get pulled. 503 buf := b.pullBuffer(c.n) 504 defer buf.Release() 505 var lengths []int 506 buf.Apply(func(v *buffer.View) { 507 lengths = append(lengths, v.Size()) 508 }) 509 if !slices.Equal(lengths, c.wantLengths) { 510 t.Errorf("Pulled view lengths = %v, want %v", lengths, c.wantLengths) 511 } 512 513 // Test that new views get reallocated. 514 for i, newIov := range b.nextIovecs() { 515 if i < c.wantUsed { 516 if newIov.Base == oldIovecs[i].Base { 517 t.Errorf("b.views[%d] should have been reallocated", i) 518 } 519 } else { 520 if newIov.Base != oldIovecs[i].Base { 521 t.Errorf("b.views[%d] should not have been reallocated", i) 522 } 523 } 524 } 525 }) 526 } 527 } 528 529 func TestIovecBufferSkipVnetHdr(t *testing.T) { 530 for _, test := range []struct { 531 desc string 532 readN int 533 wantLen int 534 }{ 535 { 536 desc: "nothing read", 537 readN: 0, 538 wantLen: 0, 539 }, 540 { 541 desc: "smaller than vnet header", 542 readN: virtioNetHdrSize - 1, 543 wantLen: 0, 544 }, 545 { 546 desc: "header skipped", 547 readN: virtioNetHdrSize + 512, 548 wantLen: 512, 549 }, 550 } { 551 t.Run(test.desc, func(t *testing.T) { 552 b := newIovecBuffer([]int{128, 256, 512, 1024}, true) 553 defer b.release() 554 // Pretend a read happened. 555 b.nextIovecs() 556 buf := b.pullBuffer(test.readN) 557 defer buf.Release() 558 if got, want := int(buf.Size()), test.wantLen; got != want { 559 t.Errorf("b.pullView(%d).Size() = %d; want %d", test.readN, got, want) 560 } 561 if got, want := len(buf.Flatten()), test.wantLen; got != want { 562 t.Errorf("b.pullView(%d).ToOwnedView() has length %d; want %d", test.readN, got, want) 563 } 564 }) 565 } 566 } 567 568 // fakeNetworkDispatcher delivers packets to pkts. 569 type fakeNetworkDispatcher struct { 570 pkts []*stack.PacketBuffer 571 } 572 573 func (d *fakeNetworkDispatcher) DeliverNetworkPacket(_ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 574 pkt.IncRef() 575 d.pkts = append(d.pkts, pkt) 576 } 577 578 func (*fakeNetworkDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, *stack.PacketBuffer) { 579 panic("not implemented") 580 } 581 582 func TestDispatchPacketFormat(t *testing.T) { 583 for _, test := range []struct { 584 name string 585 newDispatcher func(fd int, e *endpoint, opts *Options) (linkDispatcher, error) 586 ethHdr []byte 587 netHdr []byte 588 }{ 589 { 590 name: "readVDispatcher", 591 newDispatcher: newReadVDispatcher, 592 ethHdr: []byte{ 593 1, 2, 3, 4, 5, 60, 594 1, 2, 3, 4, 5, 61, 595 8, 0, 596 }, 597 netHdr: []byte{0x40, 0, 0, 0}, 598 }, 599 { 600 name: "recvMMsgDispatcher", 601 newDispatcher: newRecvMMsgDispatcher, 602 ethHdr: []byte{ 603 1, 2, 3, 4, 5, 60, 604 1, 2, 3, 4, 5, 61, 605 8, 0, 606 }, 607 netHdr: []byte{0x40, 0, 0, 0}, 608 }, 609 { 610 name: "readVDispatcherNoEth", 611 newDispatcher: newReadVDispatcher, 612 netHdr: []byte{0x40, 0, 0, 0}, 613 }, 614 { 615 name: "readVDispatcherNoEthIPv6", 616 newDispatcher: newReadVDispatcher, 617 netHdr: []byte{ 618 0x60, 0, 0, 0, // IPv6 Preamble 619 0, 0x04, 0, 0, // IPv6 Preamble 620 byte(header.IPv6HopByHopOptionsExtHdrIdentifier), // Next header 621 0xff, // Hop limit 622 0, 0, 0, 0, 0, 0, 0, 0, // Src addr 623 0, 0, 0, 0, 0, 0, 0, 0, 624 0, 0, 0, 0, 0, 0, 0, 0, // Dst addr 625 0, 0, 0, 0, 0, 0, 0, 0, 626 627 // Hop by hop extension header. 628 byte(header.IPv6DestinationOptionsExtHdrIdentifier), 629 0x8, // Length. 630 0, 0, 0, 0, 0, 0, // Padding. 631 632 // Destination options extension header. 633 0, // Next header (none) 634 0x8, // Length. 635 0, 0, 0, 0, 0, 0, // Padding. 636 637 // payload data. 638 1, 2, 3, 4, 639 }, 640 }, 641 } { 642 t.Run(test.name, func(t *testing.T) { 643 // Create a socket pair to send/recv. 644 fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_DGRAM, 0) 645 if err != nil { 646 t.Fatal(err) 647 } 648 649 data := append(test.ethHdr, test.netHdr...) 650 err = unix.Sendmsg(fds[1], data, nil, nil, 0) 651 if err != nil { 652 t.Fatal(err) 653 } 654 655 // Create and run dispatcher once. 656 sink := &fakeNetworkDispatcher{} 657 d, err := test.newDispatcher(fds[0], &endpoint{ 658 hdrSize: len(test.ethHdr), 659 dispatcher: sink, 660 }, &Options{ProcessorsPerChannel: 1}) 661 if err != nil { 662 t.Fatal(err) 663 } 664 defer d.release() 665 if ok, err := d.dispatch(); !ok || err != nil { 666 t.Fatalf("d.dispatch() = %v, %v", ok, err) 667 } 668 669 // Verify packet. 670 if got, want := len(sink.pkts), 1; got != want { 671 t.Fatalf("len(sink.pkts) = %d, want %d", got, want) 672 } 673 pkt := sink.pkts[0] 674 defer pkt.DecRef() 675 if len(test.ethHdr) > 0 { 676 if got, want := len(pkt.LinkHeader().Slice()), header.EthernetMinimumSize; got != want { 677 t.Errorf("pkt.LinkHeader().View().Size() = %d, want %d", got, want) 678 } 679 } 680 if got, want := pkt.Data().Size(), len(test.netHdr); got != want { 681 t.Errorf("pkt.Data().Size() = %d, want %d", got, want) 682 } 683 wantProto := header.IPv4ProtocolNumber 684 if header.IPVersion(test.netHdr[:]) == header.IPv6Version { 685 wantProto = header.IPv6ProtocolNumber 686 } 687 if pkt.NetworkProtocolNumber != wantProto { 688 t.Errorf("pkt.NetworkProtocolNumber = %d, want %d", pkt.NetworkProtocolNumber, wantProto) 689 } 690 }) 691 } 692 } 693 694 func TestMain(m *testing.M) { 695 refs.SetLeakMode(refs.LeaksPanic) 696 code := m.Run() 697 refs.DoLeakCheck() 698 os.Exit(code) 699 }