github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/endpoint/bpf.go (about)

     1  // Copyright 2016-2020 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 endpoint
    16  
    17  import (
    18  	"bufio"
    19  	"context"
    20  	"fmt"
    21  	"io"
    22  	"os"
    23  	"path/filepath"
    24  	"syscall"
    25  	"time"
    26  
    27  	"github.com/cilium/cilium/api/v1/models"
    28  	"github.com/cilium/cilium/common"
    29  	"github.com/cilium/cilium/pkg/bpf"
    30  	"github.com/cilium/cilium/pkg/completion"
    31  	"github.com/cilium/cilium/pkg/controller"
    32  	"github.com/cilium/cilium/pkg/datapath/loader"
    33  	"github.com/cilium/cilium/pkg/endpoint/regeneration"
    34  	"github.com/cilium/cilium/pkg/loadinfo"
    35  	"github.com/cilium/cilium/pkg/logging/logfields"
    36  	bpfconfig "github.com/cilium/cilium/pkg/maps/configmap"
    37  	"github.com/cilium/cilium/pkg/maps/ctmap"
    38  	"github.com/cilium/cilium/pkg/maps/eppolicymap"
    39  	"github.com/cilium/cilium/pkg/maps/lxcmap"
    40  	"github.com/cilium/cilium/pkg/maps/policymap"
    41  	"github.com/cilium/cilium/pkg/option"
    42  	"github.com/cilium/cilium/pkg/policy"
    43  	"github.com/cilium/cilium/pkg/policy/trafficdirection"
    44  	"github.com/cilium/cilium/pkg/revert"
    45  	"github.com/cilium/cilium/pkg/version"
    46  
    47  	"github.com/sirupsen/logrus"
    48  )
    49  
    50  const (
    51  	// EndpointGenerationTimeout specifies timeout for proxy completion context
    52  	EndpointGenerationTimeout = 330 * time.Second
    53  )
    54  
    55  // PolicyMapPathLocked returns the path to the policy map of endpoint.
    56  func (e *Endpoint) PolicyMapPathLocked() string {
    57  	return bpf.LocalMapPath(policymap.MapName, e.ID)
    58  }
    59  
    60  // CallsMapPathLocked returns the path to cilium tail calls map of an endpoint.
    61  func (e *Endpoint) CallsMapPathLocked() string {
    62  	return bpf.LocalMapPath(loader.CallsMapName, e.ID)
    63  }
    64  
    65  // BPFConfigMapPath returns the path to the BPF config map of endpoint.
    66  func (e *Endpoint) BPFConfigMapPath() string {
    67  	return bpf.LocalMapPath(bpfconfig.MapNamePrefix, e.ID)
    68  }
    69  
    70  // BPFIpvlanMapPath returns the path to the ipvlan tail call map of an endpoint.
    71  func (e *Endpoint) BPFIpvlanMapPath() string {
    72  	return bpf.LocalMapPath(IpvlanMapName, e.ID)
    73  }
    74  
    75  // writeInformationalComments writes annotations to the specified writer,
    76  // including a base64 encoding of the endpoint object, and human-readable
    77  // strings describing the configuration of the datapath.
    78  //
    79  // For configuration of actual datapath behavior, see WriteEndpointConfig().
    80  func (e *Endpoint) writeInformationalComments(w io.Writer) error {
    81  	fw := bufio.NewWriter(w)
    82  
    83  	fmt.Fprint(fw, "/*\n")
    84  
    85  	epStr64, err := e.base64()
    86  	if err == nil {
    87  		var verBase64 string
    88  		verBase64, err = version.Base64()
    89  		if err == nil {
    90  			fmt.Fprintf(fw, " * %s%s:%s\n * \n", common.CiliumCHeaderPrefix,
    91  				verBase64, epStr64)
    92  		}
    93  	}
    94  	if err != nil {
    95  		e.logStatusLocked(BPF, Warning, fmt.Sprintf("Unable to create a base64: %s", err))
    96  	}
    97  
    98  	if e.ContainerID == "" {
    99  		fmt.Fprintf(fw, " * Docker Network ID: %s\n", e.DockerNetworkID)
   100  		fmt.Fprintf(fw, " * Docker Endpoint ID: %s\n", e.DockerEndpointID)
   101  	} else {
   102  		fmt.Fprintf(fw, " * Container ID: %s\n", e.ContainerID)
   103  	}
   104  
   105  	fmt.Fprintf(fw, ""+
   106  		" * IPv6 address: %s\n"+
   107  		" * IPv4 address: %s\n"+
   108  		" * Identity: %d\n"+
   109  		" * PolicyMap: %s\n"+
   110  		" * NodeMAC: %s\n"+
   111  		" */\n\n",
   112  		e.IPv6.String(), e.IPv4.String(),
   113  		e.GetIdentity(), bpf.LocalMapName(policymap.MapName, e.ID),
   114  		e.NodeMAC)
   115  
   116  	fw.WriteString("/*\n")
   117  	fw.WriteString(" * Labels:\n")
   118  	if e.SecurityIdentity != nil {
   119  		if len(e.SecurityIdentity.Labels) == 0 {
   120  			fmt.Fprintf(fw, " * - %s\n", "(no labels)")
   121  		} else {
   122  			for _, v := range e.SecurityIdentity.Labels {
   123  				fmt.Fprintf(fw, " * - %s\n", v)
   124  			}
   125  		}
   126  	}
   127  	fw.WriteString(" */\n\n")
   128  
   129  	return fw.Flush()
   130  }
   131  
   132  func (e *Endpoint) writeHeaderfile(prefix string) error {
   133  	headerPath := filepath.Join(prefix, common.CHeaderFileName)
   134  	e.getLogger().WithFields(logrus.Fields{
   135  		logfields.Path: headerPath,
   136  	}).Debug("writing header file")
   137  	f, err := os.Create(headerPath)
   138  	if err != nil {
   139  		return fmt.Errorf("failed to open file %s for writing: %s", headerPath, err)
   140  
   141  	}
   142  	defer f.Close()
   143  
   144  	if err = e.writeInformationalComments(f); err != nil {
   145  		return err
   146  	}
   147  	return e.owner.Datapath().WriteEndpointConfig(f, e)
   148  }
   149  
   150  // addNewRedirectsFromMap must be called while holding the endpoint lock for
   151  // writing. On success, returns nil; otherwise, returns an error  indicating the
   152  // problem that occurred while adding an l7 redirect for the specified policy.
   153  // Must be called with endpoint.Mutex held.
   154  func (e *Endpoint) addNewRedirectsFromMap(m policy.L4PolicyMap, desiredRedirects map[string]bool, proxyWaitGroup *completion.WaitGroup) (error, revert.FinalizeFunc, revert.RevertFunc) {
   155  	if option.Config.DryMode {
   156  		return nil, nil, nil
   157  	}
   158  
   159  	var finalizeList revert.FinalizeList
   160  	var revertStack revert.RevertStack
   161  	var updatedStats []*models.ProxyStatistics
   162  	insertedDesiredMapState := make(map[policy.Key]struct{})
   163  	updatedDesiredMapState := make(policy.MapState)
   164  
   165  	for _, l4 := range m {
   166  		if l4.IsRedirect() {
   167  			var redirectPort uint16
   168  			var err error
   169  			// Only create a redirect if the proxy is NOT running in a sidecar
   170  			// container. If running in a sidecar container, just allow traffic
   171  			// to the port at L4 by setting the proxy port to 0.
   172  			if !e.hasSidecarProxy || l4.L7Parser != policy.ParserTypeHTTP {
   173  				var finalizeFunc revert.FinalizeFunc
   174  				var revertFunc revert.RevertFunc
   175  				redirectPort, err, finalizeFunc, revertFunc = e.owner.UpdateProxyRedirect(e, l4, proxyWaitGroup)
   176  				if err != nil {
   177  					revertStack.Revert() // Ignore errors while reverting. This is best-effort.
   178  					return err, nil, nil
   179  				}
   180  				finalizeList.Append(finalizeFunc)
   181  				revertStack.Push(revertFunc)
   182  
   183  				proxyID := e.ProxyID(l4)
   184  				if e.realizedRedirects == nil {
   185  					e.realizedRedirects = make(map[string]uint16)
   186  				}
   187  				if _, found := e.realizedRedirects[proxyID]; !found {
   188  					revertStack.Push(func() error {
   189  						delete(e.realizedRedirects, proxyID)
   190  						return nil
   191  					})
   192  				}
   193  				e.realizedRedirects[proxyID] = redirectPort
   194  
   195  				desiredRedirects[proxyID] = true
   196  
   197  				// Update the endpoint API model to report that Cilium manages a
   198  				// redirect for that port.
   199  				e.proxyStatisticsMutex.Lock()
   200  				proxyStats := e.getProxyStatisticsLocked(proxyID, string(l4.L7Parser), uint16(l4.Port), l4.Ingress)
   201  				proxyStats.AllocatedProxyPort = int64(redirectPort)
   202  				e.proxyStatisticsMutex.Unlock()
   203  
   204  				updatedStats = append(updatedStats, proxyStats)
   205  			}
   206  
   207  			// Set the proxy port in the policy map.
   208  			var direction trafficdirection.TrafficDirection
   209  			if l4.Ingress {
   210  				direction = trafficdirection.Ingress
   211  			} else {
   212  				direction = trafficdirection.Egress
   213  			}
   214  
   215  			keysFromFilter := l4.ToKeys(direction)
   216  
   217  			for _, keyFromFilter := range keysFromFilter {
   218  				if oldEntry, ok := e.desiredPolicy.PolicyMapState[keyFromFilter]; ok {
   219  					updatedDesiredMapState[keyFromFilter] = oldEntry
   220  				} else {
   221  					insertedDesiredMapState[keyFromFilter] = struct{}{}
   222  				}
   223  
   224  				e.desiredPolicy.PolicyMapState[keyFromFilter] = policy.MapStateEntry{ProxyPort: redirectPort}
   225  			}
   226  
   227  		}
   228  	}
   229  
   230  	revertStack.Push(func() error {
   231  		// Restore the proxy stats.
   232  		e.proxyStatisticsMutex.Lock()
   233  		for _, stats := range updatedStats {
   234  			stats.AllocatedProxyPort = 0
   235  		}
   236  		e.proxyStatisticsMutex.Unlock()
   237  
   238  		// Restore the desired policy map state.
   239  		for key := range insertedDesiredMapState {
   240  			delete(e.desiredPolicy.PolicyMapState, key)
   241  		}
   242  		for key, entry := range updatedDesiredMapState {
   243  			e.desiredPolicy.PolicyMapState[key] = entry
   244  		}
   245  		return nil
   246  	})
   247  
   248  	return nil, finalizeList.Finalize, revertStack.Revert
   249  }
   250  
   251  // addNewRedirects must be called while holding the endpoint lock for writing.
   252  // On success, returns nil; otherwise, returns an error indicating the problem
   253  // that occurred while adding an l7 redirect for the specified policy.
   254  // The returned map contains the exact set of IDs of proxy redirects that is
   255  // required to implement the given L4 policy.
   256  // Must be called with endpoint.Mutex held.
   257  func (e *Endpoint) addNewRedirects(m *policy.L4Policy, proxyWaitGroup *completion.WaitGroup) (desiredRedirects map[string]bool, err error, finalizeFunc revert.FinalizeFunc, revertFunc revert.RevertFunc) {
   258  	desiredRedirects = make(map[string]bool)
   259  	var finalizeList revert.FinalizeList
   260  	var revertStack revert.RevertStack
   261  
   262  	var ff revert.FinalizeFunc
   263  	var rf revert.RevertFunc
   264  
   265  	err, ff, rf = e.addNewRedirectsFromMap(m.Ingress, desiredRedirects, proxyWaitGroup)
   266  	if err != nil {
   267  		return desiredRedirects, fmt.Errorf("unable to allocate ingress redirects: %s", err), nil, nil
   268  	}
   269  	finalizeList.Append(ff)
   270  	revertStack.Push(rf)
   271  
   272  	err, ff, rf = e.addNewRedirectsFromMap(m.Egress, desiredRedirects, proxyWaitGroup)
   273  	if err != nil {
   274  		revertStack.Revert() // Ignore errors while reverting. This is best-effort.
   275  		return desiredRedirects, fmt.Errorf("unable to allocate egress redirects: %s", err), nil, nil
   276  	}
   277  	finalizeList.Append(ff)
   278  	revertStack.Push(rf)
   279  
   280  	return desiredRedirects, nil, finalizeList.Finalize, func() error {
   281  		e.getLogger().Debug("Reverting proxy redirect additions")
   282  
   283  		err := revertStack.Revert()
   284  
   285  		e.getLogger().Debug("Finished reverting proxy redirect additions")
   286  
   287  		return err
   288  	}
   289  }
   290  
   291  // Must be called with endpoint.Mutex held.
   292  func (e *Endpoint) removeOldRedirects(desiredRedirects map[string]bool, proxyWaitGroup *completion.WaitGroup) (revert.FinalizeFunc, revert.RevertFunc) {
   293  	if option.Config.DryMode {
   294  		return nil, nil
   295  	}
   296  
   297  	var finalizeList revert.FinalizeList
   298  	var revertStack revert.RevertStack
   299  	removedRedirects := make(map[string]uint16, len(e.realizedRedirects))
   300  	updatedStats := make(map[uint16]*models.ProxyStatistics, len(e.realizedRedirects))
   301  
   302  	for id, redirectPort := range e.realizedRedirects {
   303  		// Remove only the redirects that are not required.
   304  		if desiredRedirects[id] {
   305  			continue
   306  		}
   307  
   308  		err, finalizeFunc, revertFunc := e.owner.RemoveProxyRedirect(e, id, proxyWaitGroup)
   309  		if err != nil {
   310  			e.getLogger().WithError(err).WithField(logfields.L4PolicyID, id).Warn("Error while removing proxy redirect")
   311  			continue
   312  		}
   313  		finalizeList.Append(finalizeFunc)
   314  		revertStack.Push(revertFunc)
   315  
   316  		delete(e.realizedRedirects, id)
   317  		removedRedirects[id] = redirectPort
   318  
   319  		// Update the endpoint API model to report that no redirect is
   320  		// active or known for that port anymore. We never delete stats
   321  		// until an endpoint is deleted, so we only set the redirect port
   322  		// to 0.
   323  		e.proxyStatisticsMutex.Lock()
   324  		if proxyStats, ok := e.proxyStatistics[id]; ok {
   325  			updatedStats[redirectPort] = proxyStats
   326  			proxyStats.AllocatedProxyPort = 0
   327  		} else {
   328  			e.getLogger().WithField(logfields.L4PolicyID, id).Warn("Proxy stats not found")
   329  		}
   330  		e.proxyStatisticsMutex.Unlock()
   331  	}
   332  
   333  	return finalizeList.Finalize,
   334  		func() error {
   335  			e.getLogger().Debug("Reverting proxy redirect removals")
   336  
   337  			// Restore the proxy stats.
   338  			e.proxyStatisticsMutex.Lock()
   339  			for redirectPort, stats := range updatedStats {
   340  				stats.AllocatedProxyPort = int64(redirectPort)
   341  			}
   342  			e.proxyStatisticsMutex.Unlock()
   343  
   344  			for id, redirectPort := range removedRedirects {
   345  				e.realizedRedirects[id] = redirectPort
   346  			}
   347  
   348  			err := revertStack.Revert()
   349  
   350  			e.getLogger().Debug("Finished reverting proxy redirect removals")
   351  
   352  			return err
   353  		}
   354  }
   355  
   356  // regenerateBPF rewrites all headers and updates all BPF maps to reflect the
   357  // specified endpoint.
   358  // ReloadDatapath forces the datapath programs to be reloaded. It does
   359  // not guarantee recompilation of the programs.
   360  // Must be called with endpoint.Mutex not held and endpoint.buildMutex held.
   361  //
   362  // Returns the policy revision number when the regeneration has called,
   363  // Whether the new state dir is populated with all new BPF state files, and
   364  // and an error if something failed.
   365  func (e *Endpoint) regenerateBPF(regenContext *regenerationContext) (revnum uint64, stateDirComplete bool, reterr error) {
   366  	var (
   367  		err                 error
   368  		compilationExecuted bool
   369  		headerfileChanged   bool
   370  	)
   371  
   372  	stats := &regenContext.Stats
   373  	stats.waitingForLock.Start()
   374  
   375  	datapathRegenCtxt := regenContext.datapathRegenerationContext
   376  
   377  	// Make sure that owner is not compiling base programs while we are
   378  	// regenerating an endpoint.
   379  	e.owner.GetCompilationLock().RLock()
   380  	stats.waitingForLock.End(true)
   381  	defer e.owner.GetCompilationLock().RUnlock()
   382  
   383  	datapathRegenCtxt.prepareForProxyUpdates(regenContext.parentContext)
   384  	defer datapathRegenCtxt.completionCancel()
   385  
   386  	headerfileChanged, err = e.runPreCompilationSteps(regenContext)
   387  
   388  	// Keep track of the side-effects of the regeneration that need to be
   389  	// reverted in case of failure.
   390  	// Also keep track of the regeneration finalization code that can't be
   391  	// reverted, and execute it in case of regeneration success.
   392  	defer func() {
   393  		// Ignore finalizing of proxy state in dry mode.
   394  		if !option.Config.DryMode {
   395  			e.finalizeProxyState(regenContext, reterr)
   396  		}
   397  	}()
   398  
   399  	if err != nil {
   400  		return 0, compilationExecuted, err
   401  	}
   402  
   403  	// No need to compile BPF in dry mode.
   404  	if option.Config.DryMode {
   405  		return e.nextPolicyRevision, false, nil
   406  	}
   407  
   408  	// Wait for connection tracking cleaning to complete
   409  	stats.waitingForCTClean.Start()
   410  	<-datapathRegenCtxt.ctCleaned
   411  	stats.waitingForCTClean.End(true)
   412  
   413  	stats.prepareBuild.End(true)
   414  
   415  	compilationExecuted, err = e.realizeBPFState(regenContext)
   416  	if err != nil {
   417  		return datapathRegenCtxt.epInfoCache.revision, compilationExecuted, err
   418  	}
   419  
   420  	// Hook the endpoint into the endpoint and endpoint to policy tables then expose it
   421  	stats.mapSync.Start()
   422  	epErr := eppolicymap.WriteEndpoint(datapathRegenCtxt.epInfoCache.keys, e.PolicyMap)
   423  	err = lxcmap.WriteEndpoint(datapathRegenCtxt.epInfoCache)
   424  	stats.mapSync.End(err == nil)
   425  	if epErr != nil {
   426  		e.logStatusLocked(BPF, Warning, fmt.Sprintf("Unable to sync EpToPolicy Map continue with Sockmap support: %s", epErr))
   427  	}
   428  	if err != nil {
   429  		return 0, compilationExecuted, fmt.Errorf("Exposing new BPF failed: %s", err)
   430  	}
   431  
   432  	// Signal that BPF program has been generated.
   433  	// The endpoint has at least L3/L4 connectivity at this point.
   434  	e.CloseBPFProgramChannel()
   435  
   436  	// Allow another builder to start while we wait for the proxy
   437  	if regenContext.DoneFunc != nil {
   438  		regenContext.DoneFunc()
   439  	}
   440  
   441  	stats.proxyWaitForAck.Start()
   442  	err = e.WaitForProxyCompletions(datapathRegenCtxt.proxyWaitGroup)
   443  	stats.proxyWaitForAck.End(err == nil)
   444  	if err != nil {
   445  		return 0, compilationExecuted, fmt.Errorf("Error while configuring proxy redirects: %s", err)
   446  	}
   447  
   448  	stats.waitingForLock.Start()
   449  	err = e.LockAlive()
   450  	stats.waitingForLock.End(err == nil)
   451  	if err != nil {
   452  		return 0, compilationExecuted, err
   453  	}
   454  	defer e.Unlock()
   455  
   456  	e.ctCleaned = true
   457  
   458  	// Synchronously try to update PolicyMap for this endpoint. If any
   459  	// part of updating the PolicyMap fails, bail out.
   460  	// Unfortunately, this means that the map will be in an inconsistent
   461  	// state with the current program (if it exists) for this endpoint.
   462  	// GH-3897 would fix this by creating a new map to do an atomic swap
   463  	// with the old one.
   464  	//
   465  	// This must be done after allocating the new redirects, to update the
   466  	// policy map with the new proxy ports.
   467  	stats.mapSync.Start()
   468  	err = e.syncPolicyMap()
   469  	stats.mapSync.End(err == nil)
   470  	if err != nil {
   471  		return 0, compilationExecuted, fmt.Errorf("unable to regenerate policy because PolicyMap synchronization failed: %s", err)
   472  	}
   473  
   474  	stateDirComplete = headerfileChanged && compilationExecuted
   475  	return datapathRegenCtxt.epInfoCache.revision, stateDirComplete, err
   476  }
   477  
   478  func (e *Endpoint) realizeBPFState(regenContext *regenerationContext) (compilationExecuted bool, err error) {
   479  	stats := &regenContext.Stats
   480  	datapathRegenCtxt := regenContext.datapathRegenerationContext
   481  
   482  	e.getLogger().WithField(fieldRegenLevel, datapathRegenCtxt.regenerationLevel).Debug("Preparing to compile BPF")
   483  
   484  	if datapathRegenCtxt.regenerationLevel > regeneration.RegenerateWithoutDatapath {
   485  		if e.Options.IsEnabled(option.Debug) {
   486  			debugFunc := log.WithFields(logrus.Fields{logfields.EndpointID: e.StringID()}).Debugf
   487  			ctx, cancel := context.WithCancel(regenContext.parentContext)
   488  			defer cancel()
   489  			loadinfo.LogPeriodicSystemLoad(ctx, debugFunc, time.Second)
   490  		}
   491  
   492  		// Compile and install BPF programs for this endpoint
   493  		if datapathRegenCtxt.regenerationLevel == regeneration.RegenerateWithDatapathRebuild {
   494  			err = loader.CompileAndLoad(datapathRegenCtxt.completionCtx, datapathRegenCtxt.epInfoCache, &stats.datapathRealization)
   495  			e.getLogger().WithError(err).Info("Regenerated endpoint BPF program")
   496  			compilationExecuted = true
   497  		} else if datapathRegenCtxt.regenerationLevel == regeneration.RegenerateWithDatapathRewrite {
   498  			err = loader.CompileOrLoad(datapathRegenCtxt.completionCtx, datapathRegenCtxt.epInfoCache, &stats.datapathRealization)
   499  			if err == nil {
   500  				e.getLogger().Info("Rewrote endpoint BPF program")
   501  			} else {
   502  				e.getLogger().WithError(err).Error("Error while rewriting endpoint BPF program")
   503  			}
   504  			compilationExecuted = true
   505  		} else { // RegenerateWithDatapathLoad
   506  			err = loader.ReloadDatapath(datapathRegenCtxt.completionCtx, datapathRegenCtxt.epInfoCache, &stats.datapathRealization)
   507  			if err == nil {
   508  				e.getLogger().Info("Reloaded endpoint BPF program")
   509  			} else {
   510  				e.getLogger().WithError(err).Error("Error while reloading endpoint BPF program")
   511  			}
   512  		}
   513  
   514  		if err != nil {
   515  			return compilationExecuted, err
   516  		}
   517  		e.bpfHeaderfileHash = datapathRegenCtxt.bpfHeaderfilesHash
   518  	} else {
   519  		e.getLogger().WithField(logfields.BPFHeaderfileHash, datapathRegenCtxt.bpfHeaderfilesHash).
   520  			Debug("BPF header file unchanged, skipping BPF compilation and installation")
   521  	}
   522  
   523  	return compilationExecuted, nil
   524  }
   525  
   526  // runPreCompilationSteps runs all of the regeneration steps that are necessary
   527  // right before compiling the BPF for the given endpoint.
   528  // The endpoint mutex must not be held.
   529  //
   530  // Returns whether the headerfile changed and/or an error.
   531  func (e *Endpoint) runPreCompilationSteps(regenContext *regenerationContext) (headerfileChanged bool, preCompilationError error) {
   532  	stats := &regenContext.Stats
   533  	datapathRegenCtxt := regenContext.datapathRegenerationContext
   534  
   535  	stats.waitingForLock.Start()
   536  	err := e.LockAlive()
   537  	stats.waitingForLock.End(err == nil)
   538  	if err != nil {
   539  		return false, err
   540  	}
   541  
   542  	defer e.Unlock()
   543  
   544  	currentDir := datapathRegenCtxt.currentDir
   545  	nextDir := datapathRegenCtxt.nextDir
   546  
   547  	// In the first ever regeneration of the endpoint, the conntrack table
   548  	// is cleaned from the new endpoint IPs as it is guaranteed that any
   549  	// pre-existing connections using that IP are now invalid.
   550  	if !e.ctCleaned {
   551  		go func() {
   552  			if !option.Config.DryMode {
   553  				ipv4 := option.Config.EnableIPv4
   554  				ipv6 := option.Config.EnableIPv6
   555  				created := ctmap.Exists(nil, ipv4, ipv6)
   556  				if e.ConntrackLocal() {
   557  					created = ctmap.Exists(e, ipv4, ipv6)
   558  				}
   559  				if created {
   560  					e.scrubIPsInConntrackTable()
   561  				}
   562  			}
   563  			close(datapathRegenCtxt.ctCleaned)
   564  		}()
   565  	} else {
   566  		close(datapathRegenCtxt.ctCleaned)
   567  	}
   568  
   569  	// If dry mode is enabled, no further changes to BPF maps are performed
   570  	if option.Config.DryMode {
   571  
   572  		// Compute policy for this endpoint.
   573  		if err = e.regeneratePolicy(); err != nil {
   574  			return false, fmt.Errorf("Unable to regenerate policy: %s", err)
   575  		}
   576  
   577  		_ = e.updateAndOverrideEndpointOptions(nil)
   578  
   579  		// Dry mode needs Network Policy Updates, but the proxy wait group must
   580  		// not be initialized, as there is no proxy ACKing the changes.
   581  		if err, _ = e.updateNetworkPolicy(nil); err != nil {
   582  			return false, err
   583  		}
   584  
   585  		if err = e.writeHeaderfile(nextDir); err != nil {
   586  			return false, fmt.Errorf("Unable to write header file: %s", err)
   587  		}
   588  
   589  		log.WithField(logfields.EndpointID, e.ID).Debug("Skipping bpf updates due to dry mode")
   590  		return false, nil
   591  	}
   592  
   593  	if e.PolicyMap == nil {
   594  		e.PolicyMap, _, err = policymap.OpenOrCreate(e.PolicyMapPathLocked())
   595  		if err != nil {
   596  			return false, err
   597  		}
   598  		// Clean up map contents
   599  		e.getLogger().Debug("flushing old PolicyMap")
   600  		err = e.PolicyMap.DeleteAll()
   601  		if err != nil {
   602  			return false, err
   603  		}
   604  
   605  		// Also reset the in-memory state of the realized state as the
   606  		// BPF map content is guaranteed to be empty right now.
   607  		e.realizedPolicy.PolicyMapState = make(policy.MapState)
   608  	}
   609  
   610  	if e.bpfConfigMap == nil {
   611  		e.bpfConfigMap, _, err = bpfconfig.OpenMapWithName(e.BPFConfigMapPath())
   612  		if err != nil {
   613  			return false, err
   614  		}
   615  		// Also reset the in-memory state of the realized state as the
   616  		// BPF map content is guaranteed to be empty right now.
   617  		e.realizedBPFConfig = &bpfconfig.EndpointConfig{}
   618  	}
   619  
   620  	// Only generate & populate policy map if a security identity is set up for
   621  	// this endpoint.
   622  	if e.SecurityIdentity != nil {
   623  		stats.policyCalculation.Start()
   624  		err = e.regeneratePolicy()
   625  		stats.policyCalculation.End(err == nil)
   626  		if err != nil {
   627  			return false, fmt.Errorf("unable to regenerate policy for '%s': %s", e.StringID(), err)
   628  		}
   629  
   630  		_ = e.updateAndOverrideEndpointOptions(nil)
   631  
   632  		// Configure the new network policy with the proxies.
   633  		// Do this before updating the bpf policy maps, so that the proxy listeners have a chance to be
   634  		// ready when new traffic is redirected to them.
   635  		stats.proxyPolicyCalculation.Start()
   636  		err, networkPolicyRevertFunc := e.updateNetworkPolicy(datapathRegenCtxt.proxyWaitGroup)
   637  		stats.proxyPolicyCalculation.End(err == nil)
   638  		if err != nil {
   639  			return false, err
   640  		}
   641  		datapathRegenCtxt.revertStack.Push(networkPolicyRevertFunc)
   642  
   643  		// Walk the L4Policy to add new redirects and update the desired policy for existing redirects.
   644  		// Do this before updating the bpf policy maps, so that the proxies are ready when new traffic
   645  		// is redirected to them.
   646  		var desiredRedirects map[string]bool
   647  		var finalizeFunc revert.FinalizeFunc
   648  		var revertFunc revert.RevertFunc
   649  		if e.desiredPolicy != nil && e.desiredPolicy.L4Policy != nil && e.desiredPolicy.L4Policy.HasRedirect() {
   650  			stats.proxyConfiguration.Start()
   651  			desiredRedirects, err, finalizeFunc, revertFunc = e.addNewRedirects(e.desiredPolicy.L4Policy, datapathRegenCtxt.proxyWaitGroup)
   652  			stats.proxyConfiguration.End(err == nil)
   653  			if err != nil {
   654  				return false, err
   655  			}
   656  			datapathRegenCtxt.finalizeList.Append(finalizeFunc)
   657  			datapathRegenCtxt.revertStack.Push(revertFunc)
   658  		}
   659  
   660  		// realizedBPFConfig may be updated at any point after we figure out
   661  		// whether ingress/egress policy is enabled.
   662  		e.desiredBPFConfig = bpfconfig.GetConfig(e)
   663  
   664  		// Synchronously try to update PolicyMap for this endpoint. If any
   665  		// part of updating the PolicyMap fails, bail out and do not generate
   666  		// BPF. Unfortunately, this means that the map will be in an inconsistent
   667  		// state with the current program (if it exists) for this endpoint.
   668  		// GH-3897 would fix this by creating a new map to do an atomic swap
   669  		// with the old one.
   670  		stats.mapSync.Start()
   671  		err = e.syncPolicyMap()
   672  		stats.mapSync.End(err == nil)
   673  		if err != nil {
   674  			return false, fmt.Errorf("unable to regenerate policy because PolicyMap synchronization failed: %s", err)
   675  		}
   676  
   677  		// Synchronously update the BPF ConfigMap for this endpoint.
   678  		// This is unlikely to fail, but will have the same
   679  		// inconsistency issues as above if there is a failure. Long
   680  		// term the solution to this is to templatize this map in the
   681  		// ELF file, but there's no solution to this just yet.
   682  		if err = e.bpfConfigMap.Update(e.desiredBPFConfig); err != nil {
   683  			e.getLogger().WithError(err).Error("unable to update BPF config map")
   684  			return false, err
   685  		}
   686  
   687  		datapathRegenCtxt.revertStack.Push(func() error {
   688  			return e.bpfConfigMap.Update(e.realizedBPFConfig)
   689  		})
   690  
   691  		// At this point, traffic is no longer redirected to the proxy for
   692  		// now-obsolete redirects, since we synced the updated policy map above.
   693  		// It's now safe to remove the redirects from the proxy's configuration.
   694  		stats.proxyConfiguration.Start()
   695  		finalizeFunc, revertFunc = e.removeOldRedirects(desiredRedirects, datapathRegenCtxt.proxyWaitGroup)
   696  		datapathRegenCtxt.finalizeList.Append(finalizeFunc)
   697  		datapathRegenCtxt.revertStack.Push(revertFunc)
   698  		stats.proxyConfiguration.End(true)
   699  	}
   700  
   701  	stats.prepareBuild.Start()
   702  	defer func() {
   703  		stats.prepareBuild.End(preCompilationError == nil)
   704  	}()
   705  
   706  	// Avoid BPF program compilation and installation if the headerfile for the endpoint
   707  	// or the node have not changed.
   708  	datapathRegenCtxt.bpfHeaderfilesHash, err = loader.EndpointHash(e)
   709  	if err != nil {
   710  		e.getLogger().WithError(err).Warn("Unable to hash header file")
   711  		datapathRegenCtxt.bpfHeaderfilesHash = ""
   712  		headerfileChanged = true
   713  	} else {
   714  		headerfileChanged = (datapathRegenCtxt.bpfHeaderfilesHash != e.bpfHeaderfileHash)
   715  		e.getLogger().WithField(logfields.BPFHeaderfileHash, datapathRegenCtxt.bpfHeaderfilesHash).
   716  			Debugf("BPF header file hashed (was: %q)", e.bpfHeaderfileHash)
   717  	}
   718  	if headerfileChanged {
   719  		datapathRegenCtxt.regenerationLevel = regeneration.RegenerateWithDatapathRewrite
   720  		if err = e.writeHeaderfile(nextDir); err != nil {
   721  			return false, fmt.Errorf("unable to write header file: %s", err)
   722  		}
   723  	}
   724  
   725  	// Cache endpoint information so that we can release the endpoint lock.
   726  	if datapathRegenCtxt.regenerationLevel >= regeneration.RegenerateWithDatapathRewrite {
   727  		datapathRegenCtxt.epInfoCache = e.createEpInfoCache(nextDir)
   728  	} else {
   729  		datapathRegenCtxt.epInfoCache = e.createEpInfoCache(currentDir)
   730  	}
   731  	if datapathRegenCtxt.epInfoCache == nil {
   732  		return headerfileChanged, fmt.Errorf("Unable to cache endpoint information")
   733  	}
   734  
   735  	return headerfileChanged, nil
   736  }
   737  
   738  func (e *Endpoint) finalizeProxyState(regenContext *regenerationContext, err error) {
   739  	datapathRegenCtx := regenContext.datapathRegenerationContext
   740  	if err == nil {
   741  		// Always execute the finalization code, even if the endpoint is
   742  		// terminating, in order to properly release resources.
   743  		e.UnconditionalLock()
   744  		e.getLogger().Debug("Finalizing successful endpoint regeneration")
   745  		datapathRegenCtx.finalizeList.Finalize()
   746  		e.Unlock()
   747  	} else {
   748  		if err := e.LockAlive(); err != nil {
   749  			e.getLogger().WithError(err).Debug("Skipping unnecessary reverting of endpoint regeneration changes")
   750  			return
   751  		}
   752  		e.getLogger().Debug("Reverting endpoint changes after BPF regeneration failed")
   753  		if err := datapathRegenCtx.revertStack.Revert(); err != nil {
   754  			e.getLogger().WithError(err).Error("Reverting endpoint regeneration changes failed")
   755  		}
   756  		e.getLogger().Debug("Finished reverting endpoint changes after BPF regeneration failed")
   757  		e.Unlock()
   758  	}
   759  }
   760  
   761  // DeleteMapsLocked releases references to all BPF maps associated with this
   762  // endpoint.
   763  //
   764  // For each error that occurs while releasing these references, an error is
   765  // added to the resulting error slice which is returned.
   766  //
   767  // Returns nil on success.
   768  func (e *Endpoint) DeleteMapsLocked() []error {
   769  	var errors []error
   770  
   771  	maps := map[string]string{
   772  		"config": e.BPFConfigMapPath(),
   773  		"policy": e.PolicyMapPathLocked(),
   774  		"calls":  e.CallsMapPathLocked(),
   775  		"egress": e.BPFIpvlanMapPath(),
   776  	}
   777  	for name, path := range maps {
   778  		if err := os.RemoveAll(path); err != nil {
   779  			errors = append(errors, fmt.Errorf("unable to remove %s map file %s: %s", name, path, err))
   780  		}
   781  	}
   782  
   783  	if e.ConntrackLocalLocked() {
   784  		// Remove local connection tracking maps
   785  		for _, m := range ctmap.LocalMaps(e, option.Config.EnableIPv4, option.Config.EnableIPv6) {
   786  			ctPath, err := m.Path()
   787  			if err == nil {
   788  				err = os.RemoveAll(ctPath)
   789  			}
   790  			if err != nil {
   791  				errors = append(errors, fmt.Errorf("unable to remove CT map %s: %s", ctPath, err))
   792  			}
   793  		}
   794  	}
   795  
   796  	// Remove handle_policy() tail call entry for EP
   797  	if err := policymap.RemoveGlobalMapping(uint32(e.ID)); err != nil {
   798  		errors = append(errors, fmt.Errorf("unable to remove endpoint from global policy map: %s", err))
   799  	}
   800  
   801  	return errors
   802  }
   803  
   804  // DeleteBPFProgramLocked delete the BPF program associated with the endpoint's
   805  // veth interface.
   806  func (e *Endpoint) DeleteBPFProgramLocked() error {
   807  	e.getLogger().Debug("deleting bpf program from endpoint")
   808  	return loader.DeleteDatapath(context.TODO(), e.IfName, "ingress")
   809  }
   810  
   811  // garbageCollectConntrack will run the ctmap.GC() on either the endpoint's
   812  // local conntrack table or the global conntrack table.
   813  //
   814  // The endpoint lock must be held
   815  func (e *Endpoint) garbageCollectConntrack(filter *ctmap.GCFilter) {
   816  	var maps []*ctmap.Map
   817  
   818  	if e.ConntrackLocalLocked() {
   819  		maps = ctmap.LocalMaps(e, option.Config.EnableIPv4, option.Config.EnableIPv6)
   820  	} else {
   821  		maps = ctmap.GlobalMaps(option.Config.EnableIPv4, option.Config.EnableIPv6)
   822  	}
   823  	for _, m := range maps {
   824  		if err := m.Open(); err != nil {
   825  			// If the CT table doesn't exist, there's nothing to GC.
   826  			scopedLog := log.WithError(err).WithField(logfields.EndpointID, e.ID)
   827  			if os.IsNotExist(err) {
   828  				scopedLog.WithError(err).Debug("Skipping GC for endpoint")
   829  			} else {
   830  				scopedLog.WithError(err).Warn("Unable to open map")
   831  			}
   832  			continue
   833  		}
   834  		defer m.Close()
   835  
   836  		ctmap.GC(m, filter)
   837  	}
   838  }
   839  
   840  func (e *Endpoint) scrubIPsInConntrackTableLocked() {
   841  	e.garbageCollectConntrack(&ctmap.GCFilter{
   842  		MatchIPs: map[string]struct{}{
   843  			e.IPv4.String(): {},
   844  			e.IPv6.String(): {},
   845  		},
   846  	})
   847  }
   848  
   849  func (e *Endpoint) scrubIPsInConntrackTable() {
   850  	e.UnconditionalLock()
   851  	e.scrubIPsInConntrackTableLocked()
   852  	e.Unlock()
   853  }
   854  
   855  // SkipStateClean can be called on a endpoint before its first build to skip
   856  // the cleaning of state such as the conntrack table. This is useful when an
   857  // endpoint is being restored from state and the datapath state should not be
   858  // claned.
   859  //
   860  // The endpoint lock must NOT be held.
   861  func (e *Endpoint) SkipStateClean() {
   862  	// Mark conntrack as already cleaned
   863  	e.UnconditionalLock()
   864  	e.ctCleaned = true
   865  	e.Unlock()
   866  }
   867  
   868  // GetBPFKeys returns all keys which should represent this endpoint in the BPF
   869  // endpoints map
   870  func (e *Endpoint) GetBPFKeys() []*lxcmap.EndpointKey {
   871  	keys := []*lxcmap.EndpointKey{}
   872  	if e.IPv6.IsSet() {
   873  		keys = append(keys, lxcmap.NewEndpointKey(e.IPv6.IP()))
   874  	}
   875  
   876  	if e.IPv4.IsSet() {
   877  		keys = append(keys, lxcmap.NewEndpointKey(e.IPv4.IP()))
   878  	}
   879  
   880  	return keys
   881  }
   882  
   883  // GetBPFValue returns the value which should represent this endpoint in the
   884  // BPF endpoints map
   885  func (e *Endpoint) GetBPFValue() (*lxcmap.EndpointInfo, error) {
   886  	mac, err := e.LXCMAC.Uint64()
   887  	if err != nil {
   888  		return nil, fmt.Errorf("invalid LXC MAC: %v", err)
   889  	}
   890  
   891  	nodeMAC, err := e.NodeMAC.Uint64()
   892  	if err != nil {
   893  		return nil, fmt.Errorf("invalid node MAC: %v", err)
   894  	}
   895  
   896  	info := &lxcmap.EndpointInfo{
   897  		IfIndex: uint32(e.IfIndex),
   898  		// Store security identity in network byte order so it can be
   899  		// written into the packet without an additional byte order
   900  		// conversion.
   901  		LxcID:   e.ID,
   902  		MAC:     lxcmap.MAC(mac),
   903  		NodeMAC: lxcmap.MAC(nodeMAC),
   904  	}
   905  
   906  	return info, nil
   907  }
   908  
   909  // The bool pointed by hadProxy, if not nil, will be set to 'true' if
   910  // the deleted entry had a proxy port assigned to it.  *hadProxy is
   911  // not otherwise changed (e.g., it is never set to 'false').
   912  func (e *Endpoint) deletePolicyKey(keyToDelete policy.Key, incremental bool, hadProxy *bool) bool {
   913  	// Convert from policy.Key to policymap.Key
   914  	policymapKey := policymap.PolicyKey{
   915  		Identity:         keyToDelete.Identity,
   916  		DestPort:         keyToDelete.DestPort,
   917  		Nexthdr:          keyToDelete.Nexthdr,
   918  		TrafficDirection: keyToDelete.TrafficDirection,
   919  	}
   920  
   921  	// Do not error out if the map entry was already deleted from the bpf map.
   922  	// Incremental updates depend on this being OK in cases where identity change
   923  	// events overlap with full policy computation.
   924  	// In other cases we only delete entries that exist, but even in that case it
   925  	// is better to not error out if somebody else has deleted the map entry in the
   926  	// meanwhile.
   927  	err, errno := e.PolicyMap.DeleteKeyWithErrno(policymapKey)
   928  	if err != nil && errno != syscall.ENOENT {
   929  		e.getLogger().WithError(err).WithField(logfields.BPFMapKey, policymapKey).Error("Failed to delete PolicyMap key")
   930  		return false
   931  	}
   932  
   933  	if hadProxy != nil {
   934  		if entry, ok := e.realizedPolicy.PolicyMapState[keyToDelete]; ok && entry.ProxyPort != 0 {
   935  			*hadProxy = true
   936  		}
   937  	}
   938  
   939  	// Operation was successful, remove from realized state.
   940  	delete(e.realizedPolicy.PolicyMapState, keyToDelete)
   941  
   942  	// Incremental updates need to update the desired state as well.
   943  	if incremental && e.desiredPolicy != e.realizedPolicy {
   944  		delete(e.desiredPolicy.PolicyMapState, keyToDelete)
   945  	}
   946  
   947  	return true
   948  }
   949  
   950  func (e *Endpoint) addPolicyKey(keyToAdd policy.Key, entry policy.MapStateEntry, incremental bool) bool {
   951  	// Convert from policy.Key to policymap.Key
   952  	policymapKey := policymap.PolicyKey{
   953  		Identity:         keyToAdd.Identity,
   954  		DestPort:         keyToAdd.DestPort,
   955  		Nexthdr:          keyToAdd.Nexthdr,
   956  		TrafficDirection: keyToAdd.TrafficDirection,
   957  	}
   958  
   959  	err := e.PolicyMap.AllowKey(policymapKey, entry.ProxyPort)
   960  	if err != nil {
   961  		e.getLogger().WithError(err).WithFields(logrus.Fields{
   962  			logfields.BPFMapKey: policymapKey,
   963  			logfields.Port:      entry.ProxyPort,
   964  		}).Error("Failed to add PolicyMap key")
   965  		return false
   966  	}
   967  
   968  	// Operation was successful, add to realized state.
   969  	e.realizedPolicy.PolicyMapState[keyToAdd] = entry
   970  
   971  	// Incremental updates need to update the desired state as well.
   972  	if incremental && e.desiredPolicy != e.realizedPolicy {
   973  		e.desiredPolicy.PolicyMapState[keyToAdd] = entry
   974  	}
   975  
   976  	return true
   977  }
   978  
   979  // ApplyPolicyMapChanges updates the Endpoint's PolicyMap with the changes
   980  // that have accumulated for the PolicyMap via various outside events (e.g.,
   981  // identities added / deleted).
   982  // 'proxyWaitGroup' may not be nil.
   983  func (e *Endpoint) ApplyPolicyMapChanges(proxyWaitGroup *completion.WaitGroup) error {
   984  	if err := e.LockAlive(); err != nil {
   985  		return err
   986  	}
   987  	defer e.Unlock()
   988  
   989  	proxyChanges, err := e.applyPolicyMapChanges()
   990  	if err != nil {
   991  		return err
   992  	}
   993  
   994  	if proxyChanges {
   995  		// Ignoring the revertFunc; keep all successful changes even if some fail.
   996  		err, _ = e.updateNetworkPolicy(proxyWaitGroup)
   997  	} else {
   998  		// Allow caller to wait for the current network policy to be acked
   999  		e.useCurrentNetworkPolicy(proxyWaitGroup)
  1000  	}
  1001  
  1002  	return err
  1003  }
  1004  
  1005  // applyPolicyMapChanges applies any incremental policy map changes
  1006  // collected on the desired policy.
  1007  func (e *Endpoint) applyPolicyMapChanges() (proxyChanges bool, err error) {
  1008  	errors := 0
  1009  
  1010  	//  Note that after successful endpoint regeneration the
  1011  	//  desired and realized policies are the same pointer. During
  1012  	//  the bpf regeneration possible incremental updates are
  1013  	//  collected on the newly computed desired policy, which is
  1014  	//  not fully realized yet. This is why we get the map changes
  1015  	//  from the desired policy here.
  1016  	adds, deletes := e.desiredPolicy.PolicyMapChanges.ConsumeMapChanges()
  1017  
  1018  	// Add policy map entries before deleting to avoid transient drops
  1019  	for keyToAdd, entry := range adds {
  1020  		// Keep the existing proxy port, if any
  1021  		entry.ProxyPort = e.realizedRedirects[policy.ProxyIDFromKey(e.ID, keyToAdd)]
  1022  		if entry.ProxyPort != 0 {
  1023  			proxyChanges = true
  1024  		}
  1025  		if !e.addPolicyKey(keyToAdd, entry, true) {
  1026  			errors++
  1027  		}
  1028  	}
  1029  
  1030  	for keyToDelete := range deletes {
  1031  		if !e.deletePolicyKey(keyToDelete, true, &proxyChanges) {
  1032  			errors++
  1033  		}
  1034  	}
  1035  
  1036  	if errors > 0 {
  1037  		return proxyChanges, fmt.Errorf("updating desired PolicyMap state failed")
  1038  	} else if len(adds)+len(deletes) > 0 {
  1039  		e.getLogger().WithFields(logrus.Fields{
  1040  			logfields.AddedPolicyID:   adds,
  1041  			logfields.DeletedPolicyID: deletes,
  1042  		}).Debug("Applied policy map updates due identity changes")
  1043  	}
  1044  
  1045  	return proxyChanges, nil
  1046  }
  1047  
  1048  // syncPolicyMap updates the bpf policy map state based on the
  1049  // difference between the realized and desired policy state without
  1050  // dumping the bpf policy map.
  1051  func (e *Endpoint) syncPolicyMap() error {
  1052  	// Nothing to do if the desired policy is already fully realized.
  1053  	if e.realizedPolicy != e.desiredPolicy {
  1054  		errors := 0
  1055  
  1056  		// Add policy map entries before deleting to avoid transient drops
  1057  		err := e.addPolicyMapDelta()
  1058  		if err != nil {
  1059  			errors++
  1060  		}
  1061  
  1062  		// Delete policy keys present in the realized state, but not present in the desired state
  1063  		for keyToDelete := range e.realizedPolicy.PolicyMapState {
  1064  			// If key that is in realized state is not in desired state, just remove it.
  1065  			if _, ok := e.desiredPolicy.PolicyMapState[keyToDelete]; !ok {
  1066  				if !e.deletePolicyKey(keyToDelete, false, nil) {
  1067  					errors++
  1068  				}
  1069  			}
  1070  		}
  1071  
  1072  		if errors > 0 {
  1073  			return fmt.Errorf("syncPolicyMapDelta failed")
  1074  		}
  1075  	}
  1076  
  1077  	// Still may have changes due to identities added and/or
  1078  	// deleted after the desired policy was computed.
  1079  	_, err := e.applyPolicyMapChanges()
  1080  	return err
  1081  }
  1082  
  1083  // addPolicyMapDelta adds new or updates existing bpf policy map state based
  1084  // on the difference between the realized and desired policy state without
  1085  // dumping the bpf policy map.
  1086  func (e *Endpoint) addPolicyMapDelta() error {
  1087  	// Nothing to do if the desired policy is already fully realized.
  1088  	if e.realizedPolicy == e.desiredPolicy {
  1089  		return nil
  1090  	}
  1091  
  1092  	errors := 0
  1093  
  1094  	for keyToAdd, entry := range e.desiredPolicy.PolicyMapState {
  1095  		if oldEntry, ok := e.realizedPolicy.PolicyMapState[keyToAdd]; !ok || oldEntry != entry {
  1096  			if !e.addPolicyKey(keyToAdd, entry, false) {
  1097  				errors++
  1098  			}
  1099  		}
  1100  	}
  1101  
  1102  	if errors > 0 {
  1103  		return fmt.Errorf("updating desired PolicyMap state failed")
  1104  	}
  1105  
  1106  	return nil
  1107  }
  1108  
  1109  // syncPolicyMapWithDump attempts to synchronize the PolicyMap for this endpoint to
  1110  // contain the set of PolicyKeys represented by the endpoint's desiredMapState.
  1111  // It checks the current contents of the endpoint's PolicyMap and deletes any
  1112  // PolicyKeys that are not present in the endpoint's desiredMapState. It then
  1113  // adds any keys that are not present in the map. When a key from desiredMapState
  1114  // is inserted successfully to the endpoint's BPF PolicyMap, it is added to the
  1115  // endpoint's realizedMapState field. Returns an error if the endpoint's BPF
  1116  // PolicyMap is unable to be dumped, or any update operation to the map fails.
  1117  // Must be called with e.Mutex locked.
  1118  func (e *Endpoint) syncPolicyMapWithDump() error {
  1119  
  1120  	if e.realizedPolicy.PolicyMapState == nil {
  1121  		e.realizedPolicy.PolicyMapState = make(policy.MapState)
  1122  	}
  1123  
  1124  	if e.desiredPolicy.PolicyMapState == nil {
  1125  		e.desiredPolicy.PolicyMapState = make(policy.MapState)
  1126  	}
  1127  
  1128  	if e.PolicyMap == nil {
  1129  		return fmt.Errorf("not syncing PolicyMap state for endpoint because PolicyMap is nil")
  1130  	}
  1131  
  1132  	currentMapContents, err := e.PolicyMap.DumpToSlice()
  1133  
  1134  	// If map is unable to be dumped, attempt to close map and open it again.
  1135  	// See GH-4229.
  1136  	if err != nil {
  1137  		e.getLogger().WithError(err).Error("unable to dump PolicyMap when trying to sync desired and realized PolicyMap state")
  1138  
  1139  		// Close to avoid leaking of file descriptors, but still continue in case
  1140  		// Close() does not succeed, because otherwise the map will never be
  1141  		// opened again unless the agent is restarted.
  1142  		err := e.PolicyMap.Close()
  1143  		if err != nil {
  1144  			e.getLogger().WithError(err).Error("unable to close PolicyMap which was not able to be dumped")
  1145  		}
  1146  
  1147  		e.PolicyMap, _, err = policymap.OpenOrCreate(e.PolicyMapPathLocked())
  1148  		if err != nil {
  1149  			return fmt.Errorf("unable to open PolicyMap for endpoint: %s", err)
  1150  		}
  1151  
  1152  		// Try to dump again, fail if error occurs.
  1153  		currentMapContents, err = e.PolicyMap.DumpToSlice()
  1154  		if err != nil {
  1155  			return err
  1156  		}
  1157  	}
  1158  
  1159  	errors := 0
  1160  
  1161  	for _, entry := range currentMapContents {
  1162  		// Convert key to host-byte order for lookup in the desiredMapState.
  1163  		keyHostOrder := entry.Key.ToHost()
  1164  
  1165  		// Convert from policymap.Key to policy.Key
  1166  		keyToDelete := policy.Key{
  1167  			Identity:         keyHostOrder.Identity,
  1168  			DestPort:         keyHostOrder.DestPort,
  1169  			Nexthdr:          keyHostOrder.Nexthdr,
  1170  			TrafficDirection: keyHostOrder.TrafficDirection,
  1171  		}
  1172  
  1173  		// If key that is in policy map is not in desired state, just remove it.
  1174  		if _, ok := e.desiredPolicy.PolicyMapState[keyToDelete]; !ok {
  1175  			e.getLogger().WithField(logfields.BPFMapKey, entry.Key.String()).Debug("syncPolicyMapWithDump removing a bpf policy entry not in the desired state")
  1176  			if !e.deletePolicyKey(keyToDelete, false, nil) {
  1177  				errors++
  1178  			}
  1179  		}
  1180  	}
  1181  
  1182  	err = e.addPolicyMapDelta()
  1183  
  1184  	if errors > 0 {
  1185  		return fmt.Errorf("synchronizing desired PolicyMap state failed")
  1186  	}
  1187  
  1188  	return err
  1189  }
  1190  
  1191  func (e *Endpoint) syncPolicyMapController() {
  1192  	ctrlName := fmt.Sprintf("sync-policymap-%d", e.ID)
  1193  	e.controllers.UpdateController(ctrlName,
  1194  		controller.ControllerParams{
  1195  			DoFunc: func(ctx context.Context) (reterr error) {
  1196  				// Failure to lock is not an error, it means
  1197  				// that the endpoint was disconnected and we
  1198  				// should exit gracefully.
  1199  				if err := e.LockAlive(); err != nil {
  1200  					return controller.NewExitReason("Endpoint disappeared")
  1201  				}
  1202  				defer e.Unlock()
  1203  				return e.syncPolicyMapWithDump()
  1204  			},
  1205  			RunInterval: 1 * time.Minute,
  1206  		},
  1207  	)
  1208  }
  1209  
  1210  // RequireARPPassthrough returns true if the datapath must implement ARP
  1211  // passthrough for this endpoint
  1212  func (e *Endpoint) RequireARPPassthrough() bool {
  1213  	return e.DatapathConfiguration.RequireArpPassthrough
  1214  }
  1215  
  1216  // RequireEgressProg returns true if the endpoint requires bpf_lxc with esction
  1217  // "to-container" to be attached at egress on the host facing veth pair
  1218  func (e *Endpoint) RequireEgressProg() bool {
  1219  	return e.DatapathConfiguration.RequireEgressProg
  1220  }
  1221  
  1222  // RequireRouting returns true if the endpoint requires BPF routing to be
  1223  // enabled, when disabled, routing is delegated to Linux routing
  1224  func (e *Endpoint) RequireRouting() (required bool) {
  1225  	required = true
  1226  	if e.DatapathConfiguration.RequireRouting != nil {
  1227  		required = *e.DatapathConfiguration.RequireRouting
  1228  	}
  1229  	return
  1230  }
  1231  
  1232  // RequireEndpointRoute returns if the endpoint wants a per endpoint route
  1233  func (e *Endpoint) RequireEndpointRoute() bool {
  1234  	return e.DatapathConfiguration.InstallEndpointRoute
  1235  }