@@ -17,12 +17,15 @@ limitations under the License.
1717package memory
1818
1919import (
20+ "errors"
2021 "fmt"
2122 "os"
2223 "path/filepath"
2324 "strconv"
2425 "strings"
2526
27+ corev1 "k8s.io/api/core/v1"
28+ "k8s.io/apimachinery/pkg/api/resource"
2629 "k8s.io/klog/v2"
2730
2831 nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
@@ -40,9 +43,12 @@ const NvFeature = "nv"
4043// NumaFeature is the name of the feature set that holds all NUMA related features.
4144const NumaFeature = "numa"
4245
43- // SwapFeature is the name of the feature set that holds all Swap related features
46+ // SwapFeature is the name of the feature set that holds all Swap related features.
4447const SwapFeature = "swap"
4548
49+ // HugePages is the name of the feature set that holds information about huge pages.
50+ const HugePages = "hugepages"
51+
4652// memorySource implements the FeatureSource and LabelSource interfaces.
4753type memorySource struct {
4854 features * nfdv1alpha1.Features
@@ -115,6 +121,13 @@ func (s *memorySource) Discover() error {
115121 s .features .Instances [NvFeature ] = nfdv1alpha1.InstanceFeatureSet {Elements : nv }
116122 }
117123
124+ // Detect Huge Pages
125+ if hp , err := detectHugePages (); err != nil {
126+ klog .ErrorS (err , "failed to detect huge pages" )
127+ } else {
128+ s .features .Attributes [HugePages ] = nfdv1alpha1.AttributeFeatureSet {Elements : hp }
129+ }
130+
118131 klog .V (3 ).InfoS ("discovered features" , "featureSource" , s .Name (), "features" , utils .DelayedDumper (s .features ))
119132
120133 return nil
@@ -179,6 +192,57 @@ func detectNv() ([]nfdv1alpha1.InstanceFeature, error) {
179192 return info , nil
180193}
181194
195+ // detectHugePages checks whether huge pages are enabled on the node
196+ // and retrieves the configured huge page sizes.
197+ func detectHugePages () (map [string ]string , error ) {
198+ hugePages := map [string ]string {
199+ "enabled" : "false" ,
200+ }
201+
202+ basePath := hostpath .SysfsDir .Path ("kernel/mm/hugepages" )
203+ subdirs , err := os .ReadDir (basePath )
204+ if err != nil {
205+ if errors .Is (err , os .ErrNotExist ) {
206+ return hugePages , nil
207+ }
208+ return nil , fmt .Errorf ("unable to read huge pages size: %w" , err )
209+ }
210+
211+ for _ , entry := range subdirs {
212+ if ! entry .IsDir () {
213+ continue
214+ }
215+
216+ totalPages , err := getHugePagesTotalCount (basePath , entry .Name ())
217+ if err != nil {
218+ klog .ErrorS (err , "unable to read hugepages total count" , "hugepages" , entry .Name ())
219+ }
220+ pageSize := strings .TrimRight (strings .TrimPrefix (entry .Name (), "hugepages-" ), "kB" )
221+ quantity , err := resource .ParseQuantity (pageSize + "Ki" )
222+ if err != nil {
223+ klog .ErrorS (err , "unable to parse quantity" , "hugepages" , entry .Name (), "pageSize" , pageSize )
224+ continue
225+ }
226+
227+ hugePages [corev1 .ResourceHugePagesPrefix + quantity .String ()] = totalPages
228+ if v , err := strconv .Atoi (totalPages ); err == nil && v > 0 {
229+ hugePages ["enabled" ] = "true"
230+ }
231+ }
232+
233+ return hugePages , nil
234+ }
235+
236+ func getHugePagesTotalCount (basePath , dirname string ) (string , error ) {
237+ totalPagesFile := filepath .Join (basePath , dirname , "nr_hugepages" )
238+ totalPages , err := os .ReadFile (totalPagesFile )
239+ if err != nil {
240+ return "" , fmt .Errorf ("unable to read total number of huge pages from the file: %s" , totalPagesFile )
241+ }
242+
243+ return strings .TrimSpace (string (totalPages )), nil
244+ }
245+
182246// ndDevAttrs is the list of sysfs files (under each nd device) that we're trying to read
183247var ndDevAttrs = []string {"devtype" , "mode" }
184248
0 commit comments