github.com/elfadel/cilium@v1.6.12/pkg/datapath/maps/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 maps
    16  
    17  import (
    18  	"os"
    19  	"path"
    20  	"path/filepath"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/cilium/cilium/pkg/bpf"
    25  	"github.com/cilium/cilium/pkg/datapath/loader"
    26  	"github.com/cilium/cilium/pkg/endpoint"
    27  	"github.com/cilium/cilium/pkg/endpointmanager"
    28  	"github.com/cilium/cilium/pkg/logging"
    29  	"github.com/cilium/cilium/pkg/logging/logfields"
    30  	bpfconfig "github.com/cilium/cilium/pkg/maps/configmap"
    31  	"github.com/cilium/cilium/pkg/maps/ctmap"
    32  	"github.com/cilium/cilium/pkg/maps/policymap"
    33  	"github.com/cilium/cilium/pkg/option"
    34  )
    35  
    36  var (
    37  	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")
    38  
    39  	globalSweeper = newMapSweeper(&realEPManager{})
    40  )
    41  
    42  // endpointManager checks against its list of the current endpoints to determine
    43  // whether map paths should be removed, and implements map removal.
    44  //
    45  // This interface is provided to abstract epmanager/filesystem access for unit
    46  // testing.
    47  type endpointManager interface {
    48  	endpointExists(endpointID uint16) bool
    49  	removeDatapathMapping(endpointID uint16) error
    50  	removeMapPath(path string)
    51  }
    52  
    53  // realEPManager provides an implementation of endpointManager that is backed
    54  // by the endpointmanager and policymap packages, and when removeMapPath is
    55  // invoked, it cleans up paths on the actual filesystem.
    56  type realEPManager struct{}
    57  
    58  func (gw *realEPManager) endpointExists(endpointID uint16) bool {
    59  	if ep := endpointmanager.LookupCiliumID(endpointID); ep != nil {
    60  		return true
    61  	}
    62  	return false
    63  }
    64  
    65  // removeDatapathMapping unlinks the endpointID from the global policy map, preventing
    66  // packets that arrive on this node from being forwarded to the endpoint that
    67  // used to exist with the specified ID.
    68  func (gw *realEPManager) removeDatapathMapping(endpointID uint16) error {
    69  	return policymap.RemoveGlobalMapping(uint32(endpointID))
    70  }
    71  
    72  // removeMapPath removes the specified path from the filesystem.
    73  func (gw *realEPManager) removeMapPath(path string) {
    74  	if err := os.RemoveAll(path); err != nil {
    75  		log.WithError(err).WithField(logfields.Path, path).Warn("Error while deleting stale map file")
    76  	} else {
    77  		log.WithField(logfields.Path, path).Info("Removed stale bpf map")
    78  	}
    79  }
    80  
    81  // mapSweeper is responsible for checking stale map paths on the filesystem
    82  // and garbage collecting the endpoint if the corresponding endpoint no longer
    83  // exists.
    84  type mapSweeper struct {
    85  	endpointManager
    86  }
    87  
    88  // newMapSweeper creates an object that walks map paths and garbage-collects
    89  // them.
    90  func newMapSweeper(g endpointManager) *mapSweeper {
    91  	return &mapSweeper{
    92  		endpointManager: g,
    93  	}
    94  }
    95  
    96  // deleteMapIfStale uses the endpointManager implementation to determine for
    97  // the given path whether it should be deleted, and if so deletes the path.
    98  func (ms *mapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
    99  	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
   100  		epID := uint16(tmp)
   101  		if ms.endpointExists(epID) {
   102  			prefix := strings.TrimSuffix(filename, endpointID)
   103  			if filename != bpf.LocalMapName(prefix, epID) {
   104  				ms.removeMapPath(path)
   105  			}
   106  		} else {
   107  			err2 := ms.removeDatapathMapping(epID)
   108  			if err2 != nil {
   109  				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
   110  			}
   111  			ms.removeMapPath(path)
   112  		}
   113  	}
   114  }
   115  
   116  func (ms *mapSweeper) checkStaleGlobalMap(path string, filename string) {
   117  	globalCTinUse := endpointmanager.HasGlobalCT() || option.Config.EnableNodePort ||
   118  		!option.Config.InstallIptRules && option.Config.Masquerade
   119  
   120  	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
   121  		ms.removeMapPath(path)
   122  	}
   123  }
   124  
   125  func (ms *mapSweeper) walk(path string, _ os.FileInfo, _ error) error {
   126  	filename := filepath.Base(path)
   127  
   128  	mapPrefix := []string{
   129  		policymap.MapName,
   130  		ctmap.MapNameTCP6,
   131  		ctmap.MapNameTCP4,
   132  		ctmap.MapNameAny6,
   133  		ctmap.MapNameAny4,
   134  		loader.CallsMapName,
   135  		bpfconfig.MapNamePrefix,
   136  		endpoint.IpvlanMapName,
   137  	}
   138  
   139  	ms.checkStaleGlobalMap(path, filename)
   140  
   141  	for _, m := range mapPrefix {
   142  		if strings.HasPrefix(filename, m) {
   143  			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
   144  				ms.deleteMapIfStale(path, filename, endpointID)
   145  			}
   146  		}
   147  	}
   148  
   149  	return nil
   150  }
   151  
   152  // CollectStaleMapGarbage cleans up stale content in the BPF maps from the
   153  // datapath.
   154  func CollectStaleMapGarbage() {
   155  	if err := filepath.Walk(bpf.MapPrefixPath(), globalSweeper.walk); err != nil {
   156  		log.WithError(err).Warn("Error while scanning for stale maps")
   157  	}
   158  }
   159  
   160  // RemoveDisabledMaps removes BPF maps in the filesystem for features that have
   161  // been disabled. The maps may still be in use in which case they will continue
   162  // to live until the BPF program using them is being replaced.
   163  func RemoveDisabledMaps() {
   164  	maps := []string{}
   165  
   166  	if !option.Config.EnableIPv6 {
   167  		maps = append(maps, []string{
   168  			"cilium_ct6_global",
   169  			"cilium_ct_any6_global",
   170  			"cilium_lb6_reverse_nat",
   171  			"cilium_lb6_rr_seq",
   172  			"cilium_lb6_services",
   173  			"cilium_lb6_services_v2",
   174  			"cilium_lb6_rr_seq_v2",
   175  			"cilium_lb6_backends",
   176  			"cilium_lb6_reverse_sk",
   177  			"cilium_snat_v6_external",
   178  			"cilium_proxy6"}...)
   179  	}
   180  
   181  	if !option.Config.EnableIPv4 {
   182  		maps = append(maps, []string{
   183  			"cilium_ct4_global",
   184  			"cilium_ct_any4_global",
   185  			"cilium_lb4_reverse_nat",
   186  			"cilium_lb4_rr_seq",
   187  			"cilium_lb4_services",
   188  			"cilium_lb4_services_v2",
   189  			"cilium_lb4_rr_seq_v2",
   190  			"cilium_lb4_backends",
   191  			"cilium_lb4_reverse_sk",
   192  			"cilium_snat_v4_external",
   193  			"cilium_proxy4"}...)
   194  	}
   195  
   196  	for _, m := range maps {
   197  		p := path.Join(bpf.MapPrefixPath(), m)
   198  		if _, err := os.Stat(p); !os.IsNotExist(err) {
   199  			globalSweeper.removeMapPath(p)
   200  		}
   201  	}
   202  }