...

Source file src/github.com/prometheus/procfs/sysfs/class_fibrechannel.go

Documentation: github.com/prometheus/procfs/sysfs

     1  // Copyright 2020 The Prometheus Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  //go:build linux
    15  // +build linux
    16  
    17  package sysfs
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  
    25  	"github.com/prometheus/procfs/internal/util"
    26  )
    27  
    28  const fibrechannelClassPath = "class/fc_host"
    29  
    30  type FibreChannelCounters struct {
    31  	DumpedFrames          uint64 // /sys/class/fc_host/<Name>/statistics/dumped_frames
    32  	ErrorFrames           uint64 // /sys/class/fc_host/<Name>/statistics/error_frames
    33  	InvalidCRCCount       uint64 // /sys/class/fc_host/<Name>/statistics/invalid_crc_count
    34  	RXFrames              uint64 // /sys/class/fc_host/<Name>/statistics/rx_frames
    35  	RXWords               uint64 // /sys/class/fc_host/<Name>/statistics/rx_words
    36  	TXFrames              uint64 // /sys/class/fc_host/<Name>/statistics/tx_frames
    37  	TXWords               uint64 // /sys/class/fc_host/<Name>/statistics/tx_words
    38  	SecondsSinceLastReset uint64 // /sys/class/fc_host/<Name>/statistics/seconds_since_last_reset
    39  	InvalidTXWordCount    uint64 // /sys/class/fc_host/<Name>/statistics/invalid_tx_word_count
    40  	LinkFailureCount      uint64 // /sys/class/fc_host/<Name>/statistics/link_failure_count
    41  	LossOfSyncCount       uint64 // /sys/class/fc_host/<Name>/statistics/loss_of_sync_count
    42  	LossOfSignalCount     uint64 // /sys/class/fc_host/<Name>/statistics/loss_of_signal_count
    43  	NosCount              uint64 // /sys/class/fc_host/<Name>/statistics/nos_count
    44  	FCPPacketAborts       uint64 // / sys/class/fc_host/<Name>/statistics/fcp_packet_aborts
    45  }
    46  
    47  type FibreChannelHost struct {
    48  	Name             string               // /sys/class/fc_host/<Name>
    49  	Speed            string               // /sys/class/fc_host/<Name>/speed
    50  	PortState        string               // /sys/class/fc_host/<Name>/port_state
    51  	PortType         string               // /sys/class/fc_host/<Name>/port_type
    52  	SymbolicName     string               // /sys/class/fc_host/<Name>/symbolic_name
    53  	NodeName         string               // /sys/class/fc_host/<Name>/node_name
    54  	PortID           string               // /sys/class/fc_host/<Name>/port_id
    55  	PortName         string               // /sys/class/fc_host/<Name>/port_name
    56  	FabricName       string               // /sys/class/fc_host/<Name>/fabric_name
    57  	DevLossTMO       string               // /sys/class/fc_host/<Name>/dev_loss_tmo
    58  	SupportedClasses string               // /sys/class/fc_host/<Name>/supported_classes
    59  	SupportedSpeeds  string               // /sys/class/fc_host/<Name>/supported_speeds
    60  	Counters         FibreChannelCounters // /sys/class/fc_host/<Name>/statistics/*
    61  }
    62  
    63  type FibreChannelClass map[string]FibreChannelHost
    64  
    65  // FibreChannelClass parses everything in /sys/class/fc_host.
    66  func (fs FS) FibreChannelClass() (FibreChannelClass, error) {
    67  	path := fs.sys.Path(fibrechannelClassPath)
    68  
    69  	dirs, err := os.ReadDir(path)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	fcc := make(FibreChannelClass, len(dirs))
    75  	for _, d := range dirs {
    76  		host, err := fs.parseFibreChannelHost(d.Name())
    77  		if err != nil {
    78  			return nil, err
    79  		}
    80  
    81  		fcc[host.Name] = *host
    82  	}
    83  
    84  	return fcc, nil
    85  }
    86  
    87  // Parse a single FC host.
    88  func (fs FS) parseFibreChannelHost(name string) (*FibreChannelHost, error) {
    89  	path := fs.sys.Path(fibrechannelClassPath, name)
    90  	host := FibreChannelHost{Name: name}
    91  
    92  	for _, f := range [...]string{"speed", "port_state", "port_type", "node_name", "port_id", "port_name", "fabric_name", "dev_loss_tmo", "symbolic_name", "supported_classes", "supported_speeds"} {
    93  		name := filepath.Join(path, f)
    94  		value, err := util.SysReadFile(name)
    95  		if err != nil {
    96  			// drivers can choose not to expose some attributes to sysfs.
    97  			// See: https://github.com/prometheus/node_exporter/issues/2919.
    98  			if os.IsNotExist(err) {
    99  				continue
   100  			}
   101  			return nil, fmt.Errorf("failed to read file %q: %w", name, err)
   102  		}
   103  
   104  		switch f {
   105  		case "speed":
   106  			host.Speed = value
   107  		case "port_state":
   108  			host.PortState = value
   109  		case "port_type":
   110  			host.PortType = value
   111  		case "node_name":
   112  			if len(value) > 2 {
   113  				value = value[2:]
   114  			}
   115  			host.NodeName = value
   116  		case "port_id":
   117  			if len(value) > 2 {
   118  				value = value[2:]
   119  			}
   120  			host.PortID = value
   121  		case "port_name":
   122  			if len(value) > 2 {
   123  				value = value[2:]
   124  			}
   125  			host.PortName = value
   126  		case "fabric_name":
   127  			if len(value) > 2 {
   128  				value = value[2:]
   129  			}
   130  			host.FabricName = value
   131  		case "dev_loss_tmo":
   132  			host.DevLossTMO = value
   133  		case "supported_classes":
   134  			host.SupportedClasses = value
   135  		case "supported_speeds":
   136  			host.SupportedSpeeds = value
   137  		case "symbolic_name":
   138  			host.SymbolicName = value
   139  		}
   140  	}
   141  
   142  	counters, err := parseFibreChannelStatistics(path)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	host.Counters = *counters
   147  
   148  	return &host, nil
   149  }
   150  
   151  // parseFibreChannelStatistics parses metrics from a single FC host.
   152  func parseFibreChannelStatistics(hostPath string) (*FibreChannelCounters, error) {
   153  	var counters FibreChannelCounters
   154  
   155  	path := filepath.Join(hostPath, "statistics")
   156  	files, err := os.ReadDir(path)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	for _, f := range files {
   162  		if !f.Type().IsRegular() || f.Name() == "reset_statistics" {
   163  			continue
   164  		}
   165  
   166  		name := filepath.Join(path, f.Name())
   167  		value, err := util.SysReadFile(name)
   168  		if err != nil {
   169  			// there are some write-only files in this directory; we can safely skip over them
   170  			if os.IsNotExist(err) || err.Error() == "operation not supported" || errors.Is(err, os.ErrInvalid) {
   171  				continue
   172  			}
   173  			return nil, fmt.Errorf("failed to read file %q: %w", name, err)
   174  		}
   175  
   176  		vp := util.NewValueParser(value)
   177  
   178  		// Below switch was automatically generated. Don't need everything in there yet, so the unwanted bits are commented out.
   179  		switch f.Name() {
   180  		case "dumped_frames":
   181  			counters.DumpedFrames = *vp.PUInt64()
   182  		case "error_frames":
   183  			counters.ErrorFrames = *vp.PUInt64()
   184  		/*
   185  			case "fc_no_free_exch":
   186  				counters.FcNoFreeExch = *vp.PUInt64()
   187  			case "fc_no_free_exch_xid":
   188  				counters.FcNoFreeExchXid = *vp.PUInt64()
   189  			case "fc_non_bls_resp":
   190  				counters.FcNonBlsResp = *vp.PUInt64()
   191  			case "fc_seq_not_found":
   192  				counters.FcSeqNotFound = *vp.PUInt64()
   193  			case "fc_xid_busy":
   194  				counters.FcXidBusy = *vp.PUInt64()
   195  			case "fc_xid_not_found":
   196  				counters.FcXidNotFound = *vp.PUInt64()
   197  			case "fcp_control_requests":
   198  				counters.FcpControlRequests = *vp.PUInt64()
   199  			case "fcp_frame_alloc_failures":
   200  				counters.FcpFrameAllocFailures = *vp.PUInt64()
   201  			case "fcp_input_megabytes":
   202  				counters.FcpInputMegabytes = *vp.PUInt64()
   203  			case "fcp_input_requests":
   204  				counters.FcpInputRequests = *vp.PUInt64()
   205  			case "fcp_output_megabytes":
   206  				counters.FcpOutputMegabytes = *vp.PUInt64()
   207  			case "fcp_output_requests":
   208  				counters.FcpOutputRequests = *vp.PUInt64()
   209  		*/
   210  		case "fcp_packet_aborts":
   211  			counters.FCPPacketAborts = *vp.PUInt64()
   212  			/*
   213  				case "fcp_packet_alloc_failures":
   214  					counters.FcpPacketAllocFailures = *vp.PUInt64()
   215  			*/
   216  		case "invalid_tx_word_count":
   217  			counters.InvalidTXWordCount = *vp.PUInt64()
   218  		case "invalid_crc_count":
   219  			counters.InvalidCRCCount = *vp.PUInt64()
   220  		case "link_failure_count":
   221  			counters.LinkFailureCount = *vp.PUInt64()
   222  		/*
   223  			case "lip_count":
   224  					counters.LipCount = *vp.PUInt64()
   225  		*/
   226  		case "loss_of_signal_count":
   227  			counters.LossOfSignalCount = *vp.PUInt64()
   228  		case "loss_of_sync_count":
   229  			counters.LossOfSyncCount = *vp.PUInt64()
   230  		case "nos_count":
   231  			counters.NosCount = *vp.PUInt64()
   232  		/*
   233  			case "prim_seq_protocol_err_count":
   234  				counters.PrimSeqProtocolErrCount = *vp.PUInt64()
   235  		*/
   236  		case "rx_frames":
   237  			counters.RXFrames = *vp.PUInt64()
   238  		case "rx_words":
   239  			counters.RXWords = *vp.PUInt64()
   240  		case "seconds_since_last_reset":
   241  			counters.SecondsSinceLastReset = *vp.PUInt64()
   242  		case "tx_frames":
   243  			counters.TXFrames = *vp.PUInt64()
   244  		case "tx_words":
   245  			counters.TXWords = *vp.PUInt64()
   246  		}
   247  
   248  		if err := vp.Err(); err != nil {
   249  			return nil, err
   250  		}
   251  
   252  	}
   253  
   254  	return &counters, nil
   255  }
   256  

View as plain text