// Copyright 2020 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package procfs

import (
	
	
	
	
	

	
)

// A ConntrackStatEntry represents one line from net/stat/nf_conntrack
// and contains netfilter conntrack statistics at one CPU core.
type ConntrackStatEntry struct {
	Entries       uint64
	Searched      uint64
	Found         uint64
	New           uint64
	Invalid       uint64
	Ignore        uint64
	Delete        uint64
	DeleteList    uint64
	Insert        uint64
	InsertFailed  uint64
	Drop          uint64
	EarlyDrop     uint64
	SearchRestart uint64
}

// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores.
func ( FS) () ([]ConntrackStatEntry, error) {
	return readConntrackStat(.proc.Path("net", "stat", "nf_conntrack"))
}

// Parses a slice of ConntrackStatEntries from the given filepath.
func readConntrackStat( string) ([]ConntrackStatEntry, error) {
	// This file is small and can be read with one syscall.
	,  := util.ReadFileNoStat()
	if  != nil {
		// Do not wrap this error so the caller can detect os.IsNotExist and
		// similar conditions.
		return nil, 
	}

	,  := parseConntrackStat(bytes.NewReader())
	if  != nil {
		return nil, fmt.Errorf("%w: Cannot read file: %v: %w", ErrFileRead, , )
	}

	return , nil
}

// Reads the contents of a conntrack statistics file and parses a slice of ConntrackStatEntries.
func parseConntrackStat( io.Reader) ([]ConntrackStatEntry, error) {
	var  []ConntrackStatEntry

	 := bufio.NewScanner()
	.Scan()
	for .Scan() {
		 := strings.Fields(.Text())
		,  := parseConntrackStatEntry()
		if  != nil {
			return nil, 
		}
		 = append(, *)
	}

	return , nil
}

// Parses a ConntrackStatEntry from given array of fields.
func parseConntrackStatEntry( []string) (*ConntrackStatEntry, error) {
	,  := util.ParseHexUint64s()
	if  != nil {
		return nil, fmt.Errorf("%w: Cannot parse entry: %d: %w", ErrFileParse, , )
	}
	 := len()
	if  < 16 ||  > 17 {
		return nil,
			fmt.Errorf("%w: invalid conntrackstat entry, invalid number of fields: %d", ErrFileParse, )
	}

	 := &ConntrackStatEntry{
		Entries:      *[0],
		Searched:     *[1],
		Found:        *[2],
		New:          *[3],
		Invalid:      *[4],
		Ignore:       *[5],
		Delete:       *[6],
		DeleteList:   *[7],
		Insert:       *[8],
		InsertFailed: *[9],
		Drop:         *[10],
		EarlyDrop:    *[11],
	}

	// Ignore missing search_restart on Linux < 2.6.35.
	if  == 17 {
		.SearchRestart = *[16]
	}

	return , nil
}