github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/cmd/container/stats_linux.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package container 18 19 import ( 20 "errors" 21 "fmt" 22 "net" 23 "strings" 24 "time" 25 26 v1 "github.com/containerd/cgroups/v3/cgroup1/stats" 27 v2 "github.com/containerd/cgroups/v3/cgroup2/stats" 28 "github.com/containerd/nerdctl/v2/pkg/inspecttypes/native" 29 "github.com/containerd/nerdctl/v2/pkg/statsutil" 30 "github.com/vishvananda/netlink" 31 "github.com/vishvananda/netns" 32 ) 33 34 //nolint:nakedret 35 func setContainerStatsAndRenderStatsEntry(previousStats *statsutil.ContainerStats, firstSet bool, anydata interface{}, pid int, interfaces []native.NetInterface) (statsEntry statsutil.StatsEntry, err error) { 36 37 var ( 38 data *v1.Metrics 39 data2 *v2.Metrics 40 ) 41 42 switch v := anydata.(type) { 43 case *v1.Metrics: 44 data = v 45 case *v2.Metrics: 46 data2 = v 47 default: 48 err = errors.New("cannot convert metric data to cgroups.Metrics") 49 return 50 } 51 52 var nlinks []netlink.Link 53 54 if !firstSet { 55 var ( 56 nlink netlink.Link 57 nlHandle *netlink.Handle 58 ns netns.NsHandle 59 ) 60 61 ns, err = netns.GetFromPid(pid) 62 if err != nil { 63 err = fmt.Errorf("failed to retrieve the statistics in netns %s: %v", ns, err) 64 return 65 } 66 defer func() { 67 err = ns.Close() 68 }() 69 70 nlHandle, err = netlink.NewHandleAt(ns) 71 if err != nil { 72 err = fmt.Errorf("failed to retrieve the statistics in netns %s: %v", ns, err) 73 return 74 } 75 defer nlHandle.Close() 76 77 for _, v := range interfaces { 78 nlink, err = nlHandle.LinkByIndex(v.Index) 79 if err != nil { 80 err = fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", v.Name, ns, err) 81 return 82 } 83 //exclude inactive interface 84 if nlink.Attrs().Flags&net.FlagUp != 0 { 85 86 //exclude loopback interface 87 if nlink.Attrs().Flags&net.FlagLoopback != 0 || strings.HasPrefix(nlink.Attrs().Name, "lo") { 88 continue 89 } 90 nlinks = append(nlinks, nlink) 91 } 92 } 93 } 94 95 if data != nil { 96 if !firstSet { 97 statsEntry, err = statsutil.SetCgroupStatsFields(previousStats, data, nlinks) 98 } 99 previousStats.CgroupCPU = data.CPU.Usage.Total 100 previousStats.CgroupSystem = data.CPU.Usage.Kernel 101 if err != nil { 102 return 103 } 104 } else if data2 != nil { 105 if !firstSet { 106 statsEntry, err = statsutil.SetCgroup2StatsFields(previousStats, data2, nlinks) 107 } 108 previousStats.Cgroup2CPU = data2.CPU.UsageUsec * 1000 109 previousStats.Cgroup2System = data2.CPU.SystemUsec * 1000 110 if err != nil { 111 return 112 } 113 } 114 previousStats.Time = time.Now() 115 116 return 117 }