github.com/elfadel/cilium@v1.6.12/pkg/bpf/map.go (about)

     1  // Copyright 2016-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package bpf
    16  
    17  import (
    18  	"bufio"
    19  	"bytes"
    20  	"fmt"
    21  	"os"
    22  	"regexp"
    23  	"time"
    24  
    25  	"github.com/cilium/cilium/pkg/controller"
    26  	"github.com/cilium/cilium/pkg/logging/logfields"
    27  
    28  	"github.com/sirupsen/logrus"
    29  )
    30  
    31  // MapType is an enumeration for valid BPF map types
    32  type MapType int
    33  
    34  // This enumeration must be in sync with enum bpf_prog_type in <linux/bpf.h>
    35  const (
    36  	MapTypeUnspec MapType = iota
    37  	MapTypeHash
    38  	MapTypeArray
    39  	MapTypeProgArray
    40  	MapTypePerfEventArray
    41  	MapTypePerCPUHash
    42  	MapTypePerCPUArray
    43  	MapTypeStackTrace
    44  	MapTypeCgroupArray
    45  	MapTypeLRUHash
    46  	MapTypeLRUPerCPUHash
    47  	MapTypeLPMTrie
    48  	MapTypeArrayOfMaps
    49  	MapTypeHashOfMaps
    50  	MapTypeDevMap
    51  	MapTypeSockMap
    52  	MapTypeCPUMap
    53  	MapTypeXSKMap
    54  	MapTypeSockHash
    55  	// MapTypeMaximum is the maximum supported known map type.
    56  	MapTypeMaximum
    57  
    58  	// maxSyncErrors is the maximum consecutive errors syncing before the
    59  	// controller bails out
    60  	maxSyncErrors = 512
    61  
    62  	// errorResolverSchedulerMinInterval is the minimum interval for the
    63  	// error resolver to be scheduled. This minimum interval ensures not to
    64  	// overschedule if a large number of updates fail in a row.
    65  	errorResolverSchedulerMinInterval = 5 * time.Second
    66  
    67  	// errorResolverSchedulerDelay is the delay to update the controller
    68  	// after determination that a run is needed. The delay allows to
    69  	// schedule the resolver after series of updates have failed.
    70  	errorResolverSchedulerDelay = 200 * time.Millisecond
    71  )
    72  
    73  var (
    74  	mapControllers = controller.NewManager()
    75  
    76  	// supportedMapTypes maps from a MapType to a bool indicating whether
    77  	// the currently running kernel supports the map type.
    78  	supportedMapTypes = make(map[MapType]bool)
    79  )
    80  
    81  func (t MapType) String() string {
    82  	switch t {
    83  	case MapTypeHash:
    84  		return "Hash"
    85  	case MapTypeArray:
    86  		return "Array"
    87  	case MapTypeProgArray:
    88  		return "Program array"
    89  	case MapTypePerfEventArray:
    90  		return "Event array"
    91  	case MapTypePerCPUHash:
    92  		return "Per-CPU hash"
    93  	case MapTypePerCPUArray:
    94  		return "Per-CPU array"
    95  	case MapTypeStackTrace:
    96  		return "Stack trace"
    97  	case MapTypeCgroupArray:
    98  		return "Cgroup array"
    99  	case MapTypeLRUHash:
   100  		return "LRU hash"
   101  	case MapTypeLRUPerCPUHash:
   102  		return "LRU per-CPU hash"
   103  	case MapTypeLPMTrie:
   104  		return "Longest prefix match trie"
   105  	case MapTypeArrayOfMaps:
   106  		return "Array of maps"
   107  	case MapTypeHashOfMaps:
   108  		return "Hash of maps"
   109  	case MapTypeDevMap:
   110  		return "Device Map"
   111  	case MapTypeSockMap:
   112  		return "Socket Map"
   113  	case MapTypeCPUMap:
   114  		return "CPU Redirect Map"
   115  	case MapTypeSockHash:
   116  		return "Socket Hash"
   117  	}
   118  
   119  	return "Unknown"
   120  }
   121  
   122  func (t MapType) allowsPreallocation() bool {
   123  	return t != MapTypeLPMTrie
   124  }
   125  
   126  func (t MapType) requiresPreallocation() bool {
   127  	switch t {
   128  	case MapTypeHash, MapTypePerCPUHash, MapTypeLPMTrie, MapTypeHashOfMaps:
   129  		return false
   130  	}
   131  	return true
   132  }
   133  
   134  // DesiredAction is the action to be performed on the BPF map
   135  type DesiredAction int
   136  
   137  const (
   138  	// OK indicates that to further action is required and the entry is in
   139  	// sync
   140  	OK DesiredAction = iota
   141  
   142  	// Insert indicates that the entry needs to be created or updated
   143  	Insert
   144  
   145  	// Delete indicates that the entry needs to be deleted
   146  	Delete
   147  )
   148  
   149  func (d DesiredAction) String() string {
   150  	switch d {
   151  	case OK:
   152  		return "sync"
   153  	case Insert:
   154  		return "to-be-inserted"
   155  	case Delete:
   156  		return "to-be-deleted"
   157  	default:
   158  		return "unknown"
   159  	}
   160  }
   161  
   162  // mapTypeToFeatureString maps a MapType into a string defined by run_probes.sh
   163  func mapTypeToFeatureString(mt MapType) string {
   164  	var featureString string
   165  	switch mt {
   166  	case MapTypeLPMTrie:
   167  		featureString = fmt.Sprintf("#define HAVE_LPM_MAP_TYPE")
   168  	case MapTypeLRUHash:
   169  		featureString = fmt.Sprintf("#define HAVE_LRU_MAP_TYPE")
   170  	default:
   171  		break
   172  	}
   173  	return featureString
   174  }
   175  
   176  // ReadFeatureProbes reads the bpf_features.h file at the specified path (as
   177  // generated by bpf/run_probes.sh), and stores the results of the kernel
   178  // feature probing.
   179  func ReadFeatureProbes(filename string) {
   180  	f, err := os.Open(filename)
   181  	if err != nil {
   182  		// Should not happen; the caller ensured that the file exists
   183  		log.WithFields(logrus.Fields{
   184  			logfields.Path: filename,
   185  		}).WithError(err).Fatal("Failed to read feature probes")
   186  	}
   187  	defer f.Close()
   188  	scanner := bufio.NewScanner(f)
   189  	for scanner.Scan() {
   190  		for mapType := MapTypeHash; mapType < MapTypeMaximum; mapType++ {
   191  			featureString := mapTypeToFeatureString(mapType)
   192  			if featureString != "" &&
   193  				bytes.Equal(scanner.Bytes(), []byte(featureString)) {
   194  				log.Debugf("Detected support for map type %s", mapType.String())
   195  				supportedMapTypes[mapType] = true
   196  			}
   197  		}
   198  	}
   199  
   200  	for mapType := MapTypeHash; mapType < MapTypeMaximum; mapType++ {
   201  		if mapTypeToFeatureString(mapType) == "" {
   202  			log.Debugf("Skipping support detection for map type %s", mapType.String())
   203  		} else if _, probed := supportedMapTypes[mapType]; !probed {
   204  			log.Debugf("Detected no support for map type %s", mapType.String())
   205  			supportedMapTypes[mapType] = false
   206  		}
   207  	}
   208  }
   209  
   210  // GetMapType determines whether the specified map type is supported by the
   211  // kernel (as determined by ReadFeatureProbes()), and if the map type is not
   212  // supported, returns a more primitive map type that may be used to implement
   213  // the map on older implementations. Otherwise, returns the specified map type.
   214  func GetMapType(t MapType) MapType {
   215  	switch t {
   216  	case MapTypeLPMTrie:
   217  		fallthrough
   218  	case MapTypeLRUHash:
   219  		if !supportedMapTypes[t] {
   220  			return MapTypeHash
   221  		}
   222  	}
   223  	return t
   224  }
   225  
   226  var commonNameRegexps = []*regexp.Regexp{
   227  	regexp.MustCompile(`^(cilium_)(.+)_reserved_[0-9]+$`),
   228  	regexp.MustCompile(`^(cilium_)(.+)_netdev_ns_[0-9]+$`),
   229  	regexp.MustCompile(`^(cilium_)(.+)_overlay_[0-9]+$`),
   230  	regexp.MustCompile(`^(cilium_)(.+)_[0-9]+$`),
   231  	regexp.MustCompile(`^(cilium_)(.+)+$`),
   232  }
   233  
   234  func extractCommonName(name string) string {
   235  	for _, r := range commonNameRegexps {
   236  		if replaced := r.ReplaceAllString(name, `$2`); replaced != name {
   237  			return replaced
   238  		}
   239  	}
   240  
   241  	return name
   242  }