From 360c73c6fdd22c39033ee2887bc69fadc357ae92 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Thu, 26 Nov 2015 10:45:10 +0000 Subject: [PATCH] Improve perf of interface stats parsing --- container/libcontainer/helpers.go | 65 +++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/container/libcontainer/helpers.go b/container/libcontainer/helpers.go index a4da5743..83dcfc75 100644 --- a/container/libcontainer/helpers.go +++ b/container/libcontainer/helpers.go @@ -149,38 +149,70 @@ func isIgnoredDevice(ifName string) bool { const netstatsLine = `%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d` func scanInterfaceStats(netStatsFile string) ([]info.InterfaceStats, error) { - var ( - bkt uint64 - ) - - stats := []info.InterfaceStats{} - file, err := os.Open(netStatsFile) if err != nil { - return stats, fmt.Errorf("failure opening %s: %v", netStatsFile, err) + return nil, fmt.Errorf("failure opening %s: %v", netStatsFile, err) } defer file.Close() scanner := bufio.NewScanner(file) + // Discard header lines + for i := 0; i < 2; i++ { + if b := scanner.Scan(); !b { + return nil, scanner.Err() + } + } + + stats := []info.InterfaceStats{} for scanner.Scan() { line := scanner.Text() line = strings.Replace(line, ":", "", -1) - i := info.InterfaceStats{} - - _, err := fmt.Sscanf(line, netstatsLine, - &i.Name, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt, - &bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt) - - if err == nil && !isIgnoredDevice(i.Name) { - stats = append(stats, i) + fields := strings.Fields(line) + // If the format of the line is invalid then don't trust any of the stats + // in this file. + if len(fields) != 17 { + return nil, fmt.Errorf("invalid interface stats line: %v", line) } + + devName := fields[0] + if isIgnoredDevice(devName) { + continue + } + + i := info.InterfaceStats{ + Name: devName, + } + + statFields := append(fields[1:5], fields[9:13]...) + statPointers := []*uint64{ + &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, + &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, + } + + err := setInterfaceStatValues(statFields, statPointers) + if err != nil { + return nil, fmt.Errorf("cannot parse interface stats (%v): %v", err, line) + } + + stats = append(stats, i) } return stats, nil } +func setInterfaceStatValues(fields []string, pointers []*uint64) error { + for i, v := range fields { + val, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return err + } + *pointers[i] = val + } + return nil +} + func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error) { tcpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file) @@ -221,8 +253,7 @@ func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) { scanner.Split(bufio.ScanLines) // Discard header line - b := scanner.Scan() - if !b { + if b := scanner.Scan(); !b { return stats, scanner.Err() }