Repository: prometheus/procfs
Pull request #284 (2020-04-30 15:16:04)

Add several Infiniband counters
Counters added:
* port_rcv_remote_physical_errors
* port_rcv_switch_relay_errors
* symbol_error
* VL15_dropped

I don't know if these are specific to Mellanox Infiniband but I see these on systems running Mellanox Infiniband.  The fixtures already existed for all but `VL15_dropped`.

Docs from Mellanox: https://community.mellanox.com/s/article/infiniband-port-counters


Patch:
diff --git a/bcache/bcache.go b/bcache/bcache.go
index df724ed..1176a55 100644
--- a/bcache/bcache.go
+++ b/bcache/bcache.go
@@ -43,10 +43,11 @@ type BcacheStats struct { // nolint:golint
 
 // BdevStats contains statistics for one backing device.
 type BdevStats struct {
-	Name      string
-	DirtyData uint64
-	FiveMin   PeriodStats
-	Total     PeriodStats
+	Name               string
+	DirtyData          uint64
+	FiveMin            PeriodStats
+	Total              PeriodStats
+	WritebackRateDebug WritebackRateDebugStats
 }
 
 // CacheStats contains statistics for one cache device.
@@ -82,3 +83,14 @@ type PeriodStats struct {
 	CacheMisses         uint64
 	CacheReadaheads     uint64
 }
+
+// WritebackRateDebugStats contains bcache writeback statistics.
+type WritebackRateDebugStats struct {
+	Rate         uint64
+	Dirty        uint64
+	Target       uint64
+	Proportional int64
+	Integral     int64
+	Change       int64
+	NextIO       int64
+}
diff --git a/bcache/get.go b/bcache/get.go
index 67fcf8b..c4747ea 100644
--- a/bcache/get.go
+++ b/bcache/get.go
@@ -174,6 +174,17 @@ func dehumanize(hbytes []byte) (uint64, error) {
 	return res, nil
 }
 
+func dehumanizeSigned(str string) (int64, error) {
+	value, err := dehumanize([]byte(strings.TrimPrefix(str, "-")))
+	if err != nil {
+		return 0, err
+	}
+	if strings.HasPrefix(str, "-") {
+		return int64(-value), nil
+	}
+	return int64(value), nil
+}
+
 type parser struct {
 	uuidPath   string
 	subDir     string
@@ -232,6 +243,72 @@ func parsePriorityStats(line string, ps *PriorityStats) error {
 	return nil
 }
 
+// ParseWritebackRateDebug parses lines from the writeback_rate_debug file.
+func parseWritebackRateDebug(line string, wrd *WritebackRateDebugStats) error {
+	switch {
+	case strings.HasPrefix(line, "rate:"):
+		fields := strings.Fields(line)
+		rawValue := fields[len(fields)-1]
+		valueStr := strings.TrimSuffix(rawValue, "/sec")
+		value, err := dehumanize([]byte(valueStr))
+		if err != nil {
+			return err
+		}
+		wrd.Rate = value
+	case strings.HasPrefix(line, "dirty:"):
+		fields := strings.Fields(line)
+		valueStr := fields[len(fields)-1]
+		value, err := dehumanize([]byte(valueStr))
+		if err != nil {
+			return err
+		}
+		wrd.Dirty = value
+	case strings.HasPrefix(line, "target:"):
+		fields := strings.Fields(line)
+		valueStr := fields[len(fields)-1]
+		value, err := dehumanize([]byte(valueStr))
+		if err != nil {
+			return err
+		}
+		wrd.Target = value
+	case strings.HasPrefix(line, "proportional:"):
+		fields := strings.Fields(line)
+		valueStr := fields[len(fields)-1]
+		value, err := dehumanizeSigned(valueStr)
+		if err != nil {
+			return err
+		}
+		wrd.Proportional = value
+	case strings.HasPrefix(line, "integral:"):
+		fields := strings.Fields(line)
+		valueStr := fields[len(fields)-1]
+		value, err := dehumanizeSigned(valueStr)
+		if err != nil {
+			return err
+		}
+		wrd.Integral = value
+	case strings.HasPrefix(line, "change:"):
+		fields := strings.Fields(line)
+		rawValue := fields[len(fields)-1]
+		valueStr := strings.TrimSuffix(rawValue, "/sec")
+		value, err := dehumanizeSigned(valueStr)
+		if err != nil {
+			return err
+		}
+		wrd.Change = value
+	case strings.HasPrefix(line, "next io:"):
+		fields := strings.Fields(line)
+		rawValue := fields[len(fields)-1]
+		valueStr := strings.TrimSuffix(rawValue, "ms")
+		value, err := strconv.ParseInt(valueStr, 10, 64)
+		if err != nil {
+			return err
+		}
+		wrd.NextIO = value
+	}
+	return nil
+}
+
 func (p *parser) getPriorityStats() PriorityStats {
 	var res PriorityStats
 
@@ -263,6 +340,35 @@ func (p *parser) getPriorityStats() PriorityStats {
 	return res
 }
 
+func (p *parser) getWritebackRateDebug() WritebackRateDebugStats {
+	var res WritebackRateDebugStats
+
+	if p.err != nil {
+		return res
+	}
+	path := path.Join(p.currentDir, "writeback_rate_debug")
+	file, err := os.Open(path)
+	if err != nil {
+		p.err = fmt.Errorf("failed to read: %s", path)
+		return res
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		err = parseWritebackRateDebug(scanner.Text(), &res)
+		if err != nil {
+			p.err = fmt.Errorf("failed to parse: %s (%s)", path, err)
+			return res
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		p.err = fmt.Errorf("failed to parse: %s (%s)", path, err)
+		return res
+	}
+	return res
+}
+
 // GetStats collects from sysfs files data tied to one bcache ID.
 func GetStats(uuidPath string, priorityStats bool) (*Stats, error) {
 	var bs Stats
@@ -339,6 +445,9 @@ func GetStats(uuidPath string, priorityStats bool) (*Stats, error) {
 		par.setSubDir(bds.Name)
 		bds.DirtyData = par.readValue("dirty_data")
 
+		wrd := par.getWritebackRateDebug()
+		bds.WritebackRateDebug = wrd
+
 		// dir <uuidPath>/<bds.Name>/stats_five_minute
 		par.setSubDir(bds.Name, "stats_five_minute")
 		bds.FiveMin.Bypassed = par.readValue("bypassed")
diff --git a/fixtures.ttar b/fixtures.ttar
index b2ca10c..8ea9cff 100644
--- a/fixtures.ttar
+++ b/fixtures.ttar
@@ -235,6 +235,11 @@ voluntary_ctxt_switches:	4742839
 nonvoluntary_ctxt_switches:	1727500
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/wchan
+Lines: 1
+poll_schedule_timeoutEOF
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/26232
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -310,6 +315,11 @@ Lines: 1
 33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/wchan
+Lines: 1
+0EOF
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/26233
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -2595,6 +2605,11 @@ Mode: 755
 Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/VL15_dropped
+Lines: 1
+0
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/excessive_buffer_overrun_errors
 Lines: 1
 0
@@ -2696,6 +2711,11 @@ Mode: 755
 Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/VL15_dropped
+Lines: 1
+0
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/excessive_buffer_overrun_errors
 Lines: 1
 0
@@ -4146,6 +4166,17 @@ Lines: 1
 0
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/writeback_rate_debug
+Lines: 7
+rate:           1.1M/sec
+dirty:          20.4G
+target:         20.4G
+proportional:   427.5k
+integral:       790.0k
+change:         321.5k/sec
+next io:        17ms
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/mountinfo.go b/mountinfo.go
index c350cbe..59f4d50 100644
--- a/mountinfo.go
+++ b/mountinfo.go
@@ -77,7 +77,7 @@ func parseMountInfoString(mountString string) (*MountInfo, error) {
 
 	mountInfo := strings.Split(mountString, " ")
 	mountInfoLength := len(mountInfo)
-	if mountInfoLength < 11 {
+	if mountInfoLength < 10 {
 		return nil, fmt.Errorf("couldn't find enough fields in mount string: %s", mountString)
 	}
 
diff --git a/proc.go b/proc.go
index 330e472..9f97b6e 100644
--- a/proc.go
+++ b/proc.go
@@ -134,6 +134,27 @@ func (p Proc) CmdLine() ([]string, error) {
 	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
 }
 
+// Wchan returns the wchan (wait channel) of a process.
+func (p Proc) Wchan() (string, error) {
+	f, err := os.Open(p.path("wchan"))
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	data, err := ioutil.ReadAll(f)
+	if err != nil {
+		return "", err
+	}
+
+	wchan := string(data)
+	if wchan == "" || wchan == "0" {
+		return "", nil
+	}
+
+	return wchan, nil
+}
+
 // Comm returns the command name of a process.
 func (p Proc) Comm() (string, error) {
 	data, err := util.ReadFileNoStat(p.path("comm"))
diff --git a/sysfs/class_infiniband.go b/sysfs/class_infiniband.go
index be900fa..0826e1c 100644
--- a/sysfs/class_infiniband.go
+++ b/sysfs/class_infiniband.go
@@ -42,22 +42,26 @@ type InfiniBandCounters struct {
 	LegacyPortXmitData64           *uint64 // counters_ext/port_xmit_data_64
 	LegacyPortXmitPackets64        *uint64 // counters_ext/port_xmit_packets_64
 
-	LinkDowned               *uint64 // counters/link_downed
-	LinkErrorRecovery        *uint64 // counters/link_error_recovery
-	MulticastRcvPackets      *uint64 // counters/multicast_rcv_packets
-	MulticastXmitPackets     *uint64 // counters/multicast_xmit_packets
-	PortRcvConstraintErrors  *uint64 // counters/port_rcv_constraint_errors
-	PortRcvData              *uint64 // counters/port_rcv_data
-	PortRcvDiscards          *uint64 // counters/port_rcv_discards
-	PortRcvErrors            *uint64 // counters/port_rcv_errors
-	PortRcvPackets           *uint64 // counters/port_rcv_packets
-	PortXmitConstraintErrors *uint64 // counters/port_xmit_constraint_errors
-	PortXmitData             *uint64 // counters/port_xmit_data
-	PortXmitDiscards         *uint64 // counters/port_xmit_discards
-	PortXmitPackets          *uint64 // counters/port_xmit_packets
-	PortXmitWait             *uint64 // counters/port_xmit_wait
-	UnicastRcvPackets        *uint64 // counters/unicast_rcv_packets
-	UnicastXmitPackets       *uint64 // counters/unicast_xmit_packets
+	LinkDowned                  *uint64 // counters/link_downed
+	LinkErrorRecovery           *uint64 // counters/link_error_recovery
+	MulticastRcvPackets         *uint64 // counters/multicast_rcv_packets
+	MulticastXmitPackets        *uint64 // counters/multicast_xmit_packets
+	PortRcvConstraintErrors     *uint64 // counters/port_rcv_constraint_errors
+	PortRcvData                 *uint64 // counters/port_rcv_data
+	PortRcvDiscards             *uint64 // counters/port_rcv_discards
+	PortRcvErrors               *uint64 // counters/port_rcv_errors
+	PortRcvPackets              *uint64 // counters/port_rcv_packets
+	PortRcvRemotePhysicalErrors *uint64 // counters/port_rcv_remote_physical_errors
+	PortRcvSwitchRelayErrors    *uint64 // counters/port_rcv_switch_relay_errors
+	PortXmitConstraintErrors    *uint64 // counters/port_xmit_constraint_errors
+	PortXmitData                *uint64 // counters/port_xmit_data
+	PortXmitDiscards            *uint64 // counters/port_xmit_discards
+	PortXmitPackets             *uint64 // counters/port_xmit_packets
+	PortXmitWait                *uint64 // counters/port_xmit_wait
+	SymbolError                 *uint64 // counters/symbol_error
+	UnicastRcvPackets           *uint64 // counters/unicast_rcv_packets
+	UnicastXmitPackets          *uint64 // counters/unicast_xmit_packets
+	VL15Dropped                 *uint64 // counters/VL15_dropped
 }
 
 // InfiniBandPort contains info from files in
@@ -287,6 +291,10 @@ func parseInfiniBandCounters(portPath string) (*InfiniBandCounters, error) {
 			counters.PortRcvErrors = vp.PUInt64()
 		case "port_rcv_packets":
 			counters.PortRcvPackets = vp.PUInt64()
+		case "port_rcv_remote_physical_errors":
+			counters.PortRcvRemotePhysicalErrors = vp.PUInt64()
+		case "port_rcv_switch_relay_errors":
+			counters.PortRcvSwitchRelayErrors = vp.PUInt64()
 		case "port_xmit_constraint_errors":
 			counters.PortXmitConstraintErrors = vp.PUInt64()
 		case "port_xmit_data":
@@ -300,10 +308,14 @@ func parseInfiniBandCounters(portPath string) (*InfiniBandCounters, error) {
 			counters.PortXmitPackets = vp.PUInt64()
 		case "port_xmit_wait":
 			counters.PortXmitWait = vp.PUInt64()
+		case "symbol_error":
+			counters.SymbolError = vp.PUInt64()
 		case "unicast_rcv_packets":
 			counters.UnicastRcvPackets = vp.PUInt64()
 		case "unicast_xmit_packets":
 			counters.UnicastXmitPackets = vp.PUInt64()
+		case "VL15_dropped":
+			counters.VL15Dropped = vp.PUInt64()
 		}
 
 		if err := vp.Err(); err != nil {


Test patch:
diff --git a/bcache/get_test.go b/bcache/get_test.go
index e448797..22f562e 100644
--- a/bcache/get_test.go
+++ b/bcache/get_test.go
@@ -158,3 +158,61 @@ func TestPriorityStats(t *testing.T) {
 		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.UnusedPercent, got.UnusedPercent)
 	}
 }
+
+func TestWritebackRateDebug(t *testing.T) {
+	var want = WritebackRateDebugStats{
+		Rate:         1765376,
+		Dirty:        21789409280,
+		Target:       21894266880,
+		Proportional: -1124,
+		Integral:     -257624,
+		Change:       2648,
+		NextIO:       -150773,
+	}
+	var (
+		in     string
+		gotErr error
+		got    WritebackRateDebugStats
+	)
+	in = "rate:           1.7M/sec"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.Rate != want.Rate {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.Rate, got.Rate)
+	}
+
+	in = "dirty:           20.3G"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.Dirty != want.Dirty {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.Dirty, got.Dirty)
+	}
+
+	in = "target:           20.4G"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.Target != want.Target {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.Target, got.Target)
+	}
+
+	in = "proportional:           -1.1k"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.Proportional != want.Proportional {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.Proportional, got.Proportional)
+	}
+
+	in = "integral:           -251.6k"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.Integral != want.Integral {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.Integral, got.Integral)
+	}
+
+	in = "change:           2.6k/sec"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.Change != want.Change {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.Change, got.Change)
+	}
+
+	in = "next io:           -150773ms"
+	gotErr = parseWritebackRateDebug(in, &got)
+	if gotErr != nil || got.NextIO != want.NextIO {
+		t.Errorf("parsePriorityStats: '%s', want %d, got %d", in, want.NextIO, got.NextIO)
+	}
+}
diff --git a/mountinfo_test.go b/mountinfo_test.go
index de0ecc1..fab4f44 100644
--- a/mountinfo_test.go
+++ b/mountinfo_test.go
@@ -131,6 +131,38 @@ func TestMountInfo(t *testing.T) {
 			},
 			invalid: false,
 		},
+		{
+			name: "Docker overlay with 10 fields (no optional fields)",
+			s:    "137 45 253:2 /lib/docker/overlay2 /var/lib/docker/overlay2 rw,relatime - ext4 /dev/mapper/vg0-lv_var rw,data=ordered",
+			mount: &MountInfo{
+				MountID:        137,
+				ParentID:       45,
+				MajorMinorVer:  "253:2",
+				Root:           "/lib/docker/overlay2",
+				MountPoint:     "/var/lib/docker/overlay2",
+				Options:        map[string]string{"rw": "", "relatime": ""},
+				OptionalFields: map[string]string{},
+				FSType:         "ext4",
+				Source:         "/dev/mapper/vg0-lv_var",
+				SuperOptions:   map[string]string{"rw": "", "data": "ordered"},
+			},
+		},
+		{
+			name: "bind chroot bind mount with 10 fields (no optional fields)",
+			s:    "157 47 253:2 /etc/named /var/named/chroot/etc/named rw,relatime - ext4 /dev/mapper/vg0-lv_root rw,data=ordered",
+			mount: &MountInfo{
+				MountID:        157,
+				ParentID:       47,
+				MajorMinorVer:  "253:2",
+				Root:           "/etc/named",
+				MountPoint:     "/var/named/chroot/etc/named",
+				Options:        map[string]string{"rw": "", "relatime": ""},
+				OptionalFields: map[string]string{},
+				FSType:         "ext4",
+				Source:         "/dev/mapper/vg0-lv_root",
+				SuperOptions:   map[string]string{"rw": "", "data": "ordered"},
+			},
+		},
 	}
 
 	for i, test := range tests {
diff --git a/proc_test.go b/proc_test.go
index 60279fd..239e35b 100644
--- a/proc_test.go
+++ b/proc_test.go
@@ -72,6 +72,28 @@ func TestCmdLine(t *testing.T) {
 	}
 }
 
+func TestWchan(t *testing.T) {
+	for _, tt := range []struct {
+		process int
+		want    string
+	}{
+		{process: 26231, want: "poll_schedule_timeout"},
+		{process: 26232, want: ""},
+	} {
+		p1, err := getProcFixtures(t).Proc(tt.process)
+		if err != nil {
+			t.Fatal(err)
+		}
+		c1, err := p1.Wchan()
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !reflect.DeepEqual(tt.want, c1) {
+			t.Errorf("want wchan %v, have %v", tt.want, c1)
+		}
+	}
+}
+
 func TestComm(t *testing.T) {
 	for _, tt := range []struct {
 		process int
diff --git a/sysfs/class_infiniband_test.go b/sysfs/class_infiniband_test.go
index 857b5de..3eff19a 100644
--- a/sysfs/class_infiniband_test.go
+++ b/sysfs/class_infiniband_test.go
@@ -59,29 +59,37 @@ func TestInfiniBandClass(t *testing.T) {
 	}
 
 	var (
-		port1LinkDowned               uint64
-		port1LinkErrorRecovery        uint64
-		port1PortRcvConstraintErrors  uint64
-		port1PortRcvData              uint64 = 8884894436
-		port1PortRcvErrors            uint64
-		port1PortRcvPackets           uint64 = 87169372
-		port1PortXmitConstraintErrors uint64
-		port1PortXmitData             uint64 = 106036453180
-		port1PortXmitDiscards         uint64
-		port1PortXmitPackets          uint64 = 85734114
-		port1PortXmitWait             uint64 = 3599
+		port1LinkDowned                  uint64
+		port1LinkErrorRecovery           uint64
+		port1PortRcvConstraintErrors     uint64
+		port1PortRcvData                 uint64 = 8884894436
+		port1PortRcvErrors               uint64
+		port1PortRcvPackets              uint64 = 87169372
+		port1PortRcvRemotePhysicalErrors uint64
+		port1PortRcvSwitchRelayErrors    uint64
+		port1PortXmitConstraintErrors    uint64
+		port1PortXmitData                uint64 = 106036453180
+		port1PortXmitDiscards            uint64
+		port1PortXmitPackets             uint64 = 85734114
+		port1PortXmitWait                uint64 = 3599
+		port1SymbolError                 uint64
+		port1VL15Dropped                 uint64
 
-		port2LinkDowned               uint64
-		port2LinkErrorRecovery        uint64
-		port2PortRcvConstraintErrors  uint64
-		port2PortRcvData              uint64 = 9841747136
-		port2PortRcvErrors            uint64
-		port2PortRcvPackets           uint64 = 89332064
-		port2PortXmitConstraintErrors uint64
-		port2PortXmitData             uint64 = 106161427560
-		port2PortXmitDiscards         uint64
-		port2PortXmitPackets          uint64 = 88622850
-		port2PortXmitWait             uint64 = 3846
+		port2LinkDowned                  uint64
+		port2LinkErrorRecovery           uint64
+		port2PortRcvConstraintErrors     uint64
+		port2PortRcvData                 uint64 = 9841747136
+		port2PortRcvErrors               uint64
+		port2PortRcvPackets              uint64 = 89332064
+		port2PortRcvRemotePhysicalErrors uint64
+		port2PortRcvSwitchRelayErrors    uint64
+		port2PortXmitConstraintErrors    uint64
+		port2PortXmitData                uint64 = 106161427560
+		port2PortXmitDiscards            uint64
+		port2PortXmitPackets             uint64 = 88622850
+		port2PortXmitWait                uint64 = 3846
+		port2SymbolError                 uint64
+		port2VL15Dropped                 uint64
 	)
 
 	want := InfiniBandClass{
@@ -100,17 +108,21 @@ func TestInfiniBandClass(t *testing.T) {
 					PhysStateID: 5,
 					Rate:        5000000000,
 					Counters: InfiniBandCounters{
-						LinkDowned:               &port1LinkDowned,
-						LinkErrorRecovery:        &port1LinkErrorRecovery,
-						PortRcvConstraintErrors:  &port1PortRcvConstraintErrors,
-						PortRcvData:              &port1PortRcvData,
-						PortRcvErrors:            &port1PortRcvErrors,
-						PortRcvPackets:           &port1PortRcvPackets,
-						PortXmitConstraintErrors: &port1PortXmitConstraintErrors,
-						PortXmitData:             &port1PortXmitData,
-						PortXmitDiscards:         &port1PortXmitDiscards,
-						PortXmitPackets:          &port1PortXmitPackets,
-						PortXmitWait:             &port1PortXmitWait,
+						LinkDowned:                  &port1LinkDowned,
+						LinkErrorRecovery:           &port1LinkErrorRecovery,
+						PortRcvConstraintErrors:     &port1PortRcvConstraintErrors,
+						PortRcvData:                 &port1PortRcvData,
+						PortRcvErrors:               &port1PortRcvErrors,
+						PortRcvPackets:              &port1PortRcvPackets,
+						PortRcvRemotePhysicalErrors: &port1PortRcvRemotePhysicalErrors,
+						PortRcvSwitchRelayErrors:    &port1PortRcvSwitchRelayErrors,
+						PortXmitConstraintErrors:    &port1PortXmitConstraintErrors,
+						PortXmitData:                &port1PortXmitData,
+						PortXmitDiscards:            &port1PortXmitDiscards,
+						PortXmitPackets:             &port1PortXmitPackets,
+						PortXmitWait:                &port1PortXmitWait,
+						SymbolError:                 &port1SymbolError,
+						VL15Dropped:                 &port1VL15Dropped,
 					},
 				},
 				2: {
@@ -122,17 +134,21 @@ func TestInfiniBandClass(t *testing.T) {
 					PhysStateID: 5,
 					Rate:        5000000000,
 					Counters: InfiniBandCounters{
-						LinkDowned:               &port2LinkDowned,
-						LinkErrorRecovery:        &port2LinkErrorRecovery,
-						PortRcvConstraintErrors:  &port2PortRcvConstraintErrors,
-						PortRcvData:              &port2PortRcvData,
-						PortRcvErrors:            &port2PortRcvErrors,
-						PortRcvPackets:           &port2PortRcvPackets,
-						PortXmitConstraintErrors: &port2PortXmitConstraintErrors,
-						PortXmitData:             &port2PortXmitData,
-						PortXmitDiscards:         &port2PortXmitDiscards,
-						PortXmitPackets:          &port2PortXmitPackets,
-						PortXmitWait:             &port2PortXmitWait,
+						LinkDowned:                  &port2LinkDowned,
+						LinkErrorRecovery:           &port2LinkErrorRecovery,
+						PortRcvConstraintErrors:     &port2PortRcvConstraintErrors,
+						PortRcvData:                 &port2PortRcvData,
+						PortRcvErrors:               &port2PortRcvErrors,
+						PortRcvPackets:              &port2PortRcvPackets,
+						PortRcvRemotePhysicalErrors: &port2PortRcvRemotePhysicalErrors,
+						PortRcvSwitchRelayErrors:    &port2PortRcvSwitchRelayErrors,
+						PortXmitConstraintErrors:    &port2PortXmitConstraintErrors,
+						PortXmitData:                &port2PortXmitData,
+						PortXmitDiscards:            &port2PortXmitDiscards,
+						PortXmitPackets:             &port2PortXmitPackets,
+						PortXmitWait:                &port2PortXmitWait,
+						SymbolError:                 &port2SymbolError,
+						VL15Dropped:                 &port2VL15Dropped,
 					},
 				},
 			},