go.net/ipv4: fix sprious lookahead on IPConn-based PacketConn
Also improves test coverage for both payload and datagram I/O.
R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/7304091
diff --git a/ipv4/header_test.go b/ipv4/header_test.go
index 0ac02ed..cc2fd8e 100644
--- a/ipv4/header_test.go
+++ b/ipv4/header_test.go
@@ -44,27 +44,24 @@
}
// TODO(mikio): Add platform dependent wire header formats when
// we support new platforms.
+
+ testHeader = &ipv4.Header{
+ Version: ipv4.Version,
+ Len: ipv4.HeaderLen,
+ TOS: 1,
+ TotalLen: 0xbeef,
+ ID: 0xcafe,
+ FragOff: 1500,
+ TTL: 255,
+ Protocol: 1,
+ Checksum: 0xdead,
+ Src: net.IPv4(172, 16, 254, 254),
+ Dst: net.IPv4(192, 168, 0, 1),
+ }
)
-func testHeader() *ipv4.Header {
- h := &ipv4.Header{}
- h.Version = ipv4.Version
- h.Len = ipv4.HeaderLen
- h.TOS = 1
- h.TotalLen = 0xbeef
- h.ID = 0xcafe
- h.FragOff = 1500
- h.TTL = 255
- h.Protocol = 1
- h.Checksum = 0xdead
- h.Src = net.IPv4(172, 16, 254, 254)
- h.Dst = net.IPv4(192, 168, 0, 1)
- return h
-}
-
func TestMarshalHeader(t *testing.T) {
- th := testHeader()
- b, err := th.Marshal()
+ b, err := testHeader.Marshal()
if err != nil {
t.Fatalf("ipv4.Header.Marshal failed: %v", err)
}
@@ -92,8 +89,7 @@
if err != nil {
t.Fatalf("ipv4.ParseHeader failed: %v", err)
}
- th := testHeader()
- if !reflect.DeepEqual(h, th) {
- t.Fatalf("ipv4.ParseHeader failed: %#v not equal %#v", h, th)
+ if !reflect.DeepEqual(h, testHeader) {
+ t.Fatalf("ipv4.ParseHeader failed: %#v not equal %#v", h, testHeader)
}
}
diff --git a/ipv4/mockicmp_test.go b/ipv4/mockicmp_test.go
index 5bf8920..7b9ee06 100644
--- a/ipv4/mockicmp_test.go
+++ b/ipv4/mockicmp_test.go
@@ -5,43 +5,117 @@
package ipv4_test
import (
- "bytes"
+ "errors"
"flag"
)
var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
-func newICMPEchoRequest(id, seqnum, msglen int, filler []byte) []byte {
- b := newICMPInfoMessage(id, seqnum, msglen, filler)
- b[0] = 8
- // calculate ICMP checksum
- cklen := len(b)
- s := uint32(0)
- for i := 0; i < cklen-1; i += 2 {
- s += uint32(b[i+1])<<8 | uint32(b[i])
- }
- if cklen&1 == 1 {
- s += uint32(b[cklen-1])
- }
- s = (s >> 16) + (s & 0xffff)
- s = s + (s >> 16)
- // place checksum back in header; using ^= avoids the
- // assumption the checksum bytes are zero
- b[2] ^= byte(^s & 0xff)
- b[3] ^= byte(^s >> 8)
- return b
+const (
+ icmpv4EchoRequest = 8
+ icmpv4EchoReply = 0
+ icmpv6EchoRequest = 128
+ icmpv6EchoReply = 129
+)
+
+// icmpMessage represents an ICMP message.
+type icmpMessage struct {
+ Type int // type
+ Code int // code
+ Checksum int // checksum
+ Body icmpMessageBody // body
}
-func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
- b := make([]byte, msglen)
- copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
- b[0] = 0 // type
- b[1] = 0 // code
- b[2] = 0 // checksum
- b[3] = 0 // checksum
- b[4] = byte(id >> 8) // identifier
- b[5] = byte(id & 0xff) // identifier
- b[6] = byte(seqnum >> 8) // sequence number
- b[7] = byte(seqnum & 0xff) // sequence number
- return b
+// icmpMessageBody represents an ICMP message body.
+type icmpMessageBody interface {
+ Len() int
+ Marshal() ([]byte, error)
+}
+
+// Marshal returns the binary enconding of the ICMP echo request or
+// reply message m.
+func (m *icmpMessage) Marshal() ([]byte, error) {
+ b := []byte{byte(m.Type), byte(m.Code), 0, 0}
+ if m.Body != nil && m.Body.Len() != 0 {
+ mb, err := m.Body.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ b = append(b, mb...)
+ }
+ switch m.Type {
+ case icmpv6EchoRequest, icmpv6EchoReply:
+ return b, nil
+ }
+ csumcv := len(b) - 1 // checksum coverage
+ s := uint32(0)
+ for i := 0; i < csumcv; i += 2 {
+ s += uint32(b[i+1])<<8 | uint32(b[i])
+ }
+ if csumcv&1 == 0 {
+ s += uint32(b[csumcv])
+ }
+ s = s>>16 + s&0xffff
+ s = s + s>>16
+ // Place checksum back in header; using ^= avoids the
+ // assumption the checksum bytes are zero.
+ b[2] ^= byte(^s & 0xff)
+ b[3] ^= byte(^s >> 8)
+ return b, nil
+}
+
+// parseICMPMessage parses b as an ICMP message.
+func parseICMPMessage(b []byte) (*icmpMessage, error) {
+ msglen := len(b)
+ if msglen < 4 {
+ return nil, errors.New("message too short")
+ }
+ m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
+ if msglen > 4 {
+ var err error
+ switch m.Type {
+ case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
+ m.Body, err = parseICMPEcho(b[4:])
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return m, nil
+}
+
+// imcpEcho represenets an ICMP echo request or reply message body.
+type icmpEcho struct {
+ ID int // identifier
+ Seq int // sequence number
+ Data []byte // data
+}
+
+func (p *icmpEcho) Len() int {
+ if p == nil {
+ return 0
+ }
+ return 4 + len(p.Data)
+}
+
+// Marshal returns the binary enconding of the ICMP echo request or
+// reply message body p.
+func (p *icmpEcho) Marshal() ([]byte, error) {
+ b := make([]byte, 4+len(p.Data))
+ b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
+ b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
+ copy(b[4:], p.Data)
+ return b, nil
+}
+
+// parseICMPEcho parses b as an ICMP echo request or reply message
+// body.
+func parseICMPEcho(b []byte) (*icmpEcho, error) {
+ bodylen := len(b)
+ p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
+ if bodylen > 4 {
+ p.Data = make([]byte, bodylen-4)
+ copy(p.Data, b[4:])
+ }
+ return p, nil
}
diff --git a/ipv4/mocktransponder_test.go b/ipv4/mocktransponder_test.go
index ef682bd..357721d 100644
--- a/ipv4/mocktransponder_test.go
+++ b/ipv4/mocktransponder_test.go
@@ -13,77 +13,70 @@
"time"
)
-// runPayloadTransponder transmits IPv4 datagram payloads to the
+// writeThenReadPayload transmits IPv4 datagram payloads to the
// loopback address or interface and captures the loopback'd datagram
// payloads.
-func runPayloadTransponder(t *testing.T, c *ipv4.PacketConn, wb []byte, dst net.Addr) {
- cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+func writeThenReadPayload(t *testing.T, i int, c *ipv4.PacketConn, wb []byte, dst net.Addr) []byte {
rb := make([]byte, 1500)
- for i, toggle := range []bool{true, false, true} {
- if err := c.SetControlMessage(cf, toggle); err != nil {
- t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
- }
- c.SetTOS(i + 1)
- var ip net.IP
- switch v := dst.(type) {
- case *net.UDPAddr:
- ip = v.IP
- case *net.IPAddr:
- ip = v.IP
- }
- if ip.IsMulticast() {
- c.SetMulticastTTL(i + 1)
- } else {
- c.SetTTL(i + 1)
- }
- c.SetDeadline(time.Now().Add(100 * time.Millisecond))
- if _, err := c.WriteTo(wb, nil, dst); err != nil {
- t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
- }
- _, cm, _, err := c.ReadFrom(rb)
- if err != nil {
- t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
- }
- t.Logf("rcvd cmsg: %v", cm)
+ c.SetTOS(i + 1)
+ var ip net.IP
+ switch v := dst.(type) {
+ case *net.UDPAddr:
+ ip = v.IP
+ case *net.IPAddr:
+ ip = v.IP
}
+ if ip.IsMulticast() {
+ c.SetMulticastTTL(i + 1)
+ } else {
+ c.SetTTL(i + 1)
+ }
+ c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+ if _, err := c.WriteTo(wb, nil, dst); err != nil {
+ t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
+ }
+ n, cm, _, err := c.ReadFrom(rb)
+ if err != nil {
+ t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
+ }
+ t.Logf("rcvd cmsg: %v", cm)
+ return rb[:n]
}
-// runDatagramTransponder transmits ICMP for IPv4 datagrams to the
+// writeThenReadDatagram transmits ICMP for IPv4 datagrams to the
// loopback address or interface and captures the response datagrams
// from the protocol stack within the kernel.
-func runDatagramTransponder(t *testing.T, c *ipv4.RawConn, wb []byte, src, dst net.Addr) {
- cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+func writeThenReadDatagram(t *testing.T, i int, c *ipv4.RawConn, wb []byte, src, dst net.Addr) []byte {
rb := make([]byte, ipv4.HeaderLen+len(wb))
- for i, toggle := range []bool{true, false, true} {
- if err := c.SetControlMessage(cf, toggle); err != nil {
- t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
- }
- wh := &ipv4.Header{}
- wh.Version = ipv4.Version
- wh.Len = ipv4.HeaderLen
- wh.TOS = i + 1
- wh.TotalLen = ipv4.HeaderLen + len(wb)
- wh.TTL = i + 1
- wh.Protocol = 1
- if src != nil {
- wh.Src = src.(*net.IPAddr).IP
- }
- if dst != nil {
- wh.Dst = dst.(*net.IPAddr).IP
- }
- c.SetDeadline(time.Now().Add(100 * time.Millisecond))
- if err := c.WriteTo(wh, wb, nil); err != nil {
- t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
- }
- rh, _, cm, err := c.ReadFrom(rb)
- if err != nil {
- t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
- }
- t.Logf("rcvd cmsg: %v", cm.String())
- t.Logf("rcvd hdr: %v", rh.String())
+ wh := &ipv4.Header{
+ Version: ipv4.Version,
+ Len: ipv4.HeaderLen,
+ TOS: i + 1,
+ TotalLen: ipv4.HeaderLen + len(wb),
+ TTL: i + 1,
+ Protocol: 1,
}
+ if src != nil {
+ wh.Src = src.(*net.IPAddr).IP
+ }
+ if dst != nil {
+ wh.Dst = dst.(*net.IPAddr).IP
+ }
+ c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+ if err := c.WriteTo(wh, wb, nil); err != nil {
+ t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
+ }
+ rh, b, cm, err := c.ReadFrom(rb)
+ if err != nil {
+ t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
+ }
+ t.Logf("rcvd cmsg: %v", cm.String())
+ t.Logf("rcvd hdr: %v", rh.String())
+ return b
}
+// LoopbackInterface returns a logical network interface for loopback
+// tests.
func loopbackInterface() *net.Interface {
ift, err := net.Interfaces()
if err != nil {
@@ -97,12 +90,13 @@
return nil
}
-func isGoodForMulticast(ifi *net.Interface) (net.IP, bool) {
- if ifi.Flags&net.FlagUp == 0 {
+// isMulticastAvailable returns true if ifi is a multicast access
+// enabled network interface. It also returns a unicast IPv4 address
+// that can be used for listening on ifi.
+func isMulticastAvailable(ifi *net.Interface) (net.IP, bool) {
+ if ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
return nil, false
}
- // We need a unicast IPv4 address that can be used to specify
- // the IPv4 multicast interface.
ifat, err := ifi.Addrs()
if err != nil {
return nil, false
@@ -126,8 +120,5 @@
}
break
}
- if ip == nil {
- return nil, false
- }
return ip, true
}
diff --git a/ipv4/multicast_test.go b/ipv4/multicast_test.go
index 01cc2a1..a5c470d 100644
--- a/ipv4/multicast_test.go
+++ b/ipv4/multicast_test.go
@@ -45,7 +45,13 @@
if err := p.SetMulticastLoopback(true); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
}
- runPayloadTransponder(t, p, []byte("HELLO-R-U-THERE"), dst)
+ cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+ for i, toggle := range []bool{true, false, true} {
+ if err := p.SetControlMessage(cf, toggle); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
+ }
+ writeThenReadPayload(t, i, p, []byte("HELLO-R-U-THERE"), dst)
+ }
}
func TestReadWriteMulticastIPPayloadICMP(t *testing.T) {
@@ -81,9 +87,30 @@
if err := p.SetMulticastInterface(ifi); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
}
- id := os.Getpid() & 0xffff
- pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
- runPayloadTransponder(t, p, pld, dst)
+ cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+ for i, toggle := range []bool{true, false, true} {
+ wb, err := (&icmpMessage{
+ Type: icmpv4EchoRequest, Code: 0,
+ Body: &icmpEcho{
+ ID: os.Getpid() & 0xffff, Seq: i + 1,
+ Data: []byte("HELLO-R-U-THERE"),
+ },
+ }).Marshal()
+ if err != nil {
+ t.Fatalf("icmpMessage.Marshal failed: %v", err)
+ }
+ if err := p.SetControlMessage(cf, toggle); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
+ }
+ rb := writeThenReadPayload(t, i, p, wb, dst)
+ m, err := parseICMPMessage(rb)
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ if m.Type != icmpv4EchoReply || m.Code != 0 {
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
+ }
+ }
}
func TestReadWriteMulticastIPDatagram(t *testing.T) {
@@ -122,7 +149,28 @@
if err := r.SetMulticastInterface(ifi); err != nil {
t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
}
- id := os.Getpid() & 0xffff
- pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
- runDatagramTransponder(t, r, pld, nil, dst)
+ cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+ for i, toggle := range []bool{true, false, true} {
+ wb, err := (&icmpMessage{
+ Type: icmpv4EchoRequest, Code: 0,
+ Body: &icmpEcho{
+ ID: os.Getpid() & 0xffff, Seq: i + 1,
+ Data: []byte("HELLO-R-U-THERE"),
+ },
+ }).Marshal()
+ if err != nil {
+ t.Fatalf("icmpMessage.Marshal failed: %v", err)
+ }
+ if err := r.SetControlMessage(cf, toggle); err != nil {
+ t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
+ }
+ rb := writeThenReadDatagram(t, i, r, wb, nil, dst)
+ m, err := parseICMPMessage(rb)
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ if m.Type != icmpv4EchoReply || m.Code != 0 {
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
+ }
+ }
}
diff --git a/ipv4/multicastlistener_test.go b/ipv4/multicastlistener_test.go
index 4199c05..2ece9a7 100644
--- a/ipv4/multicastlistener_test.go
+++ b/ipv4/multicastlistener_test.go
@@ -43,7 +43,7 @@
t.Fatalf("net.Interfaces failed: %v", err)
}
for i, ifi := range ift {
- if _, ok := isGoodForMulticast(&ifi); !ok {
+ if _, ok := isMulticastAvailable(&ifi); !ok {
continue
}
if err := p.JoinGroup(&ifi, tt.gaddr); err != nil {
@@ -90,7 +90,7 @@
t.Fatalf("net.Interfaces failed: %v", err)
}
for i, ifi := range ift {
- if _, ok := isGoodForMulticast(&ifi); !ok {
+ if _, ok := isMulticastAvailable(&ifi); !ok {
continue
}
for _, p := range ps {
@@ -139,7 +139,7 @@
t.Fatalf("net.Interfaces failed: %v", err)
}
for i, ifi := range ift {
- if _, ok := isGoodForMulticast(&ifi); !ok {
+ if _, ok := isMulticastAvailable(&ifi); !ok {
continue
}
if err := r.JoinGroup(&ifi, gaddr); err != nil {
@@ -172,7 +172,7 @@
t.Fatalf("net.Interfaces failed: %v", err)
}
for i, ifi := range ift {
- ip, ok := isGoodForMulticast(&ifi)
+ ip, ok := isMulticastAvailable(&ifi)
if !ok {
continue
}
@@ -217,7 +217,7 @@
t.Fatalf("net.Interfaces failed: %v", err)
}
for i, ifi := range ift {
- ip, ok := isGoodForMulticast(&ifi)
+ ip, ok := isMulticastAvailable(&ifi)
if !ok {
continue
}
diff --git a/ipv4/payload.go b/ipv4/payload.go
index 9b3c2c9..7580d78 100644
--- a/ipv4/payload.go
+++ b/ipv4/payload.go
@@ -33,11 +33,11 @@
return 0, nil, nil, err
}
case *net.IPConn:
- nb := make([]byte, len(b)+maxHeaderLen)
+ nb := make([]byte, maxHeaderLen+len(b))
if n, oobn, _, src, err = rd.ReadMsgIP(nb, oob); err != nil {
return 0, nil, nil, err
}
- hdrlen := (int(b[0]) & 0x0f) << 2
+ hdrlen := int(nb[0]&0x0f) << 2
copy(b, nb[hdrlen:])
n -= hdrlen
default:
diff --git a/ipv4/unicast_test.go b/ipv4/unicast_test.go
index 3b905a0..bddfb97 100644
--- a/ipv4/unicast_test.go
+++ b/ipv4/unicast_test.go
@@ -24,9 +24,14 @@
if err != nil {
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
}
-
p := ipv4.NewPacketConn(c)
- runPayloadTransponder(t, p, []byte("HELLO-R-U-THERE"), dst)
+ cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+ for i, toggle := range []bool{true, false, true} {
+ if err := p.SetControlMessage(cf, toggle); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
+ }
+ writeThenReadPayload(t, i, p, []byte("HELLO-R-U-THERE"), dst)
+ }
}
func TestReadWriteUnicastIPPayloadICMP(t *testing.T) {
@@ -45,11 +50,31 @@
if err != nil {
t.Fatalf("ResolveIPAddr failed: %v", err)
}
-
p := ipv4.NewPacketConn(c)
- id := os.Getpid() & 0xffff
- pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
- runPayloadTransponder(t, p, pld, dst)
+ cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+ for i, toggle := range []bool{true, false, true} {
+ wb, err := (&icmpMessage{
+ Type: icmpv4EchoRequest, Code: 0,
+ Body: &icmpEcho{
+ ID: os.Getpid() & 0xffff, Seq: i + 1,
+ Data: []byte("HELLO-R-U-THERE"),
+ },
+ }).Marshal()
+ if err != nil {
+ t.Fatalf("icmpMessage.Marshal failed: %v", err)
+ }
+ if err := p.SetControlMessage(cf, toggle); err != nil {
+ t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
+ }
+ rb := writeThenReadPayload(t, i, p, wb, dst)
+ m, err := parseICMPMessage(rb)
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ if m.Type != icmpv4EchoReply || m.Code != 0 {
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
+ }
+ }
}
func TestReadWriteUnicastIPDatagram(t *testing.T) {
@@ -68,12 +93,32 @@
if err != nil {
t.Fatalf("ResolveIPAddr failed: %v", err)
}
-
r, err := ipv4.NewRawConn(c)
if err != nil {
t.Fatalf("ipv4.NewRawConn failed: %v", err)
}
- id := os.Getpid() & 0xffff
- pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
- runDatagramTransponder(t, r, pld, nil, dst)
+ cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
+ for i, toggle := range []bool{true, false, true} {
+ wb, err := (&icmpMessage{
+ Type: icmpv4EchoRequest, Code: 0,
+ Body: &icmpEcho{
+ ID: os.Getpid() & 0xffff, Seq: i + 1,
+ Data: []byte("HELLO-R-U-THERE"),
+ },
+ }).Marshal()
+ if err != nil {
+ t.Fatalf("icmpMessage.Marshal failed: %v", err)
+ }
+ if err := r.SetControlMessage(cf, toggle); err != nil {
+ t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
+ }
+ rb := writeThenReadDatagram(t, i, r, wb, nil, dst)
+ m, err := parseICMPMessage(rb)
+ if err != nil {
+ t.Fatalf("parseICMPMessage failed: %v", err)
+ }
+ if m.Type != icmpv4EchoReply || m.Code != 0 {
+ t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
+ }
+ }
}