github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/endpoint/endpoint.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 endpoint
    16  
    17  import (
    18  	"context"
    19  	"encoding/base64"
    20  	"encoding/json"
    21  	"fmt"
    22  	"net"
    23  	"os"
    24  	"runtime"
    25  	"sort"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  	"unsafe"
    30  
    31  	"github.com/cilium/cilium/api/v1/models"
    32  	"github.com/cilium/cilium/common/addressing"
    33  	"github.com/cilium/cilium/pkg/bpf"
    34  	"github.com/cilium/cilium/pkg/completion"
    35  	"github.com/cilium/cilium/pkg/controller"
    36  	"github.com/cilium/cilium/pkg/datapath/loader"
    37  	"github.com/cilium/cilium/pkg/endpoint/regeneration"
    38  	"github.com/cilium/cilium/pkg/eventqueue"
    39  	"github.com/cilium/cilium/pkg/fqdn"
    40  	identityPkg "github.com/cilium/cilium/pkg/identity"
    41  	"github.com/cilium/cilium/pkg/identity/cache"
    42  	"github.com/cilium/cilium/pkg/identity/identitymanager"
    43  	ciliumio "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
    44  	"github.com/cilium/cilium/pkg/labels"
    45  	pkgLabels "github.com/cilium/cilium/pkg/labels"
    46  	"github.com/cilium/cilium/pkg/labels/model"
    47  	"github.com/cilium/cilium/pkg/lock"
    48  	"github.com/cilium/cilium/pkg/logging/logfields"
    49  	"github.com/cilium/cilium/pkg/mac"
    50  	bpfconfig "github.com/cilium/cilium/pkg/maps/configmap"
    51  	"github.com/cilium/cilium/pkg/maps/ctmap"
    52  	"github.com/cilium/cilium/pkg/maps/policymap"
    53  	"github.com/cilium/cilium/pkg/metrics"
    54  	"github.com/cilium/cilium/pkg/monitor/notifications"
    55  	"github.com/cilium/cilium/pkg/option"
    56  	"github.com/cilium/cilium/pkg/policy"
    57  	"github.com/cilium/cilium/pkg/policy/trafficdirection"
    58  	"github.com/cilium/cilium/pkg/proxy/accesslog"
    59  	"github.com/cilium/cilium/pkg/trigger"
    60  
    61  	"github.com/sirupsen/logrus"
    62  	"golang.org/x/sys/unix"
    63  )
    64  
    65  const (
    66  	maxLogs = 256
    67  )
    68  
    69  var (
    70  	EndpointMutableOptionLibrary = option.GetEndpointMutableOptionLibrary()
    71  )
    72  
    73  const (
    74  	// StateCreating is used to set the endpoint is being created.
    75  	StateCreating = string(models.EndpointStateCreating)
    76  
    77  	// StateWaitingForIdentity is used to set if the endpoint is waiting
    78  	// for an identity from the KVStore.
    79  	StateWaitingForIdentity = string(models.EndpointStateWaitingForIdentity)
    80  
    81  	// StateReady specifies if the endpoint is ready to be used.
    82  	StateReady = string(models.EndpointStateReady)
    83  
    84  	// StateWaitingToRegenerate specifies when the endpoint needs to be regenerated, but regeneration has not started yet.
    85  	StateWaitingToRegenerate = string(models.EndpointStateWaitingToRegenerate)
    86  
    87  	// StateRegenerating specifies when the endpoint is being regenerated.
    88  	StateRegenerating = string(models.EndpointStateRegenerating)
    89  
    90  	// StateDisconnecting indicates that the endpoint is being disconnected
    91  	StateDisconnecting = string(models.EndpointStateDisconnecting)
    92  
    93  	// StateDisconnected is used to set the endpoint is disconnected.
    94  	StateDisconnected = string(models.EndpointStateDisconnected)
    95  
    96  	// StateRestoring is used to set the endpoint is being restored.
    97  	StateRestoring = string(models.EndpointStateRestoring)
    98  
    99  	// StateInvalid is used when an endpoint failed during creation due to
   100  	// invalid data.
   101  	StateInvalid = string(models.EndpointStateInvalid)
   102  
   103  	// IpvlanMapName specifies the tail call map for EP on egress used with ipvlan.
   104  	IpvlanMapName = "cilium_lxc_ipve_"
   105  
   106  	// HealthCEPPrefix is the prefix used to name the cilium health endpoints' CEP
   107  	HealthCEPPrefix = "cilium-health-"
   108  )
   109  
   110  // compile time interface check
   111  var _ notifications.RegenNotificationInfo = &Endpoint{}
   112  
   113  // Endpoint represents a container or similar which can be individually
   114  // addresses on L3 with its own IP addresses. This structured is managed by the
   115  // endpoint manager in pkg/endpointmanager.
   116  //
   117  //
   118  // WARNING - STABLE API
   119  // This structure is written as JSON to StateDir/{ID}/lxc_config.h to allow to
   120  // restore endpoints when the agent is being restarted. The restore operation
   121  // will read the file and re-create all endpoints with all fields which are not
   122  // marked as private to JSON marshal. Do NOT modify this structure in ways which
   123  // is not JSON forward compatible.
   124  //
   125  type Endpoint struct {
   126  	owner regeneration.Owner
   127  
   128  	// ID of the endpoint, unique in the scope of the node
   129  	ID uint16
   130  
   131  	// mutex protects write operations to this endpoint structure except
   132  	// for the logger field which has its own mutex
   133  	mutex lock.RWMutex
   134  
   135  	// ContainerName is the name given to the endpoint by the container runtime
   136  	ContainerName string
   137  
   138  	// ContainerID is the container ID that docker has assigned to the endpoint
   139  	// Note: The JSON tag was kept for backward compatibility.
   140  	ContainerID string `json:"dockerID,omitempty"`
   141  
   142  	// DockerNetworkID is the network ID of the libnetwork network if the
   143  	// endpoint is a docker managed container which uses libnetwork
   144  	DockerNetworkID string
   145  
   146  	// DockerEndpointID is the Docker network endpoint ID if managed by
   147  	// libnetwork
   148  	DockerEndpointID string
   149  
   150  	// Corresponding BPF map identifier for tail call map of ipvlan datapath
   151  	DatapathMapID int
   152  
   153  	// isDatapathMapPinned denotes whether the datapath map has been pinned.
   154  	isDatapathMapPinned bool
   155  
   156  	// IfName is the name of the host facing interface (veth pair) which
   157  	// connects into the endpoint
   158  	IfName string
   159  
   160  	// IfIndex is the interface index of the host face interface (veth pair)
   161  	IfIndex int
   162  
   163  	// OpLabels is the endpoint's label configuration
   164  	//
   165  	// FIXME: Rename this field to Labels
   166  	OpLabels pkgLabels.OpLabels
   167  
   168  	// identityRevision is incremented each time the identity label
   169  	// information of the endpoint has changed
   170  	identityRevision int
   171  
   172  	// LXCMAC is the MAC address of the endpoint
   173  	//
   174  	// FIXME: Rename this field to MAC
   175  	LXCMAC mac.MAC // Container MAC address.
   176  
   177  	// IPv6 is the IPv6 address of the endpoint
   178  	IPv6 addressing.CiliumIPv6
   179  
   180  	// IPv4 is the IPv4 address of the endpoint
   181  	IPv4 addressing.CiliumIPv4
   182  
   183  	// NodeMAC is the MAC of the node (agent). The MAC is different for every endpoint.
   184  	NodeMAC mac.MAC
   185  
   186  	// SecurityIdentity is the security identity of this endpoint. This is computed from
   187  	// the endpoint's labels.
   188  	SecurityIdentity *identityPkg.Identity `json:"SecLabel"`
   189  
   190  	// hasSidecarProxy indicates whether the endpoint has been injected by
   191  	// Istio with a Cilium-compatible sidecar proxy. If true, the sidecar proxy
   192  	// will be used to apply L7 policy rules. Otherwise, Cilium's node-wide
   193  	// proxy will be used.
   194  	// TODO: Currently this applies only to HTTP L7 rules. Kafka L7 rules are still enforced by Cilium's node-wide Kafka proxy.
   195  	hasSidecarProxy bool
   196  
   197  	// PolicyMap is the policy related state of the datapath including
   198  	// reference to all policy related BPF
   199  	PolicyMap *policymap.PolicyMap `json:"-"`
   200  
   201  	// Options determine the datapath configuration of the endpoint.
   202  	Options *option.IntOptions
   203  
   204  	// Status are the last n state transitions this endpoint went through
   205  	Status *EndpointStatus `json:"-"`
   206  
   207  	// DNSHistory is the collection of still-valid DNS responses intercepted for
   208  	// this endpoint.
   209  	DNSHistory *fqdn.DNSCache
   210  
   211  	// dnsHistoryTrigger is the trigger to write down the lxc_config.h to make
   212  	// sure that restores when DNS policy is in there are correct
   213  	dnsHistoryTrigger *trigger.Trigger
   214  
   215  	// state is the state the endpoint is in. See SetStateLocked()
   216  	state string
   217  
   218  	// bpfHeaderfileHash is the hash of the last BPF headerfile that has been
   219  	// compiled and installed.
   220  	bpfHeaderfileHash string
   221  
   222  	// K8sPodName is the Kubernetes pod name of the endpoint
   223  	K8sPodName string
   224  
   225  	// K8sNamespace is the Kubernetes namespace of the endpoint
   226  	K8sNamespace string
   227  
   228  	// policyRevision is the policy revision this endpoint is currently on
   229  	// to modify this field please use endpoint.setPolicyRevision instead
   230  	policyRevision uint64
   231  
   232  	// policyRevisionSignals contains a map of PolicyRevision signals that
   233  	// should be triggered once the policyRevision reaches the wanted wantedRev.
   234  	policyRevisionSignals map[*policySignal]bool
   235  
   236  	// proxyPolicyRevision is the policy revision that has been applied to
   237  	// the proxy.
   238  	proxyPolicyRevision uint64
   239  
   240  	// proxyStatisticsMutex is the mutex that must be held to read or write
   241  	// proxyStatistics.
   242  	proxyStatisticsMutex lock.RWMutex
   243  
   244  	// proxyStatistics contains statistics of proxy redirects.
   245  	// They keys in this map are policy.ProxyIDs.
   246  	// You must hold Endpoint.proxyStatisticsMutex to read or write it.
   247  	proxyStatistics map[string]*models.ProxyStatistics
   248  
   249  	// nextPolicyRevision is the policy revision that the endpoint has
   250  	// updated to and that will become effective with the next regenerate
   251  	nextPolicyRevision uint64
   252  
   253  	// forcePolicyCompute full endpoint policy recomputation
   254  	// Set when endpoint options have been changed. Cleared right before releasing the
   255  	// endpoint mutex after policy recalculation.
   256  	forcePolicyCompute bool
   257  
   258  	// BuildMutex synchronizes builds of individual endpoints and locks out
   259  	// deletion during builds
   260  	//
   261  	// FIXME: Mark private once endpoint deletion can be moved into
   262  	// `pkg/endpoint`
   263  	BuildMutex lock.Mutex `json:"-"`
   264  
   265  	// logger is a logrus object with fields set to report an endpoints information.
   266  	// You must hold Endpoint.Mutex to read or write it (but not to log with it).
   267  	logger unsafe.Pointer
   268  
   269  	// controllers is the list of async controllers syncing the endpoint to
   270  	// other resources
   271  	controllers *controller.Manager
   272  
   273  	// realizedRedirects maps the ID of each proxy redirect that has been
   274  	// successfully added into a proxy for this endpoint, to the redirect's
   275  	// proxy port number.
   276  	// You must hold Endpoint.Mutex to read or write it.
   277  	realizedRedirects map[string]uint16
   278  
   279  	// BPFConfigMap provides access to the endpoint's BPF configuration.
   280  	bpfConfigMap *bpfconfig.EndpointConfigMap
   281  
   282  	// desiredBPFConfig is the BPF Configuration computed from the endpoint.
   283  	desiredBPFConfig *bpfconfig.EndpointConfig
   284  
   285  	// realizedBPFConfig is the config currently active in the BPF datapath.
   286  	realizedBPFConfig *bpfconfig.EndpointConfig
   287  
   288  	// ctCleaned indicates whether the conntrack table has already been
   289  	// cleaned when this endpoint was first created
   290  	ctCleaned bool
   291  
   292  	hasBPFProgram chan struct{}
   293  
   294  	// selectorPolicy represents a reference to the shared SelectorPolicy
   295  	// for all endpoints that have the same Identity.
   296  	selectorPolicy policy.SelectorPolicy
   297  
   298  	desiredPolicy *policy.EndpointPolicy
   299  
   300  	realizedPolicy *policy.EndpointPolicy
   301  
   302  	EventQueue *eventqueue.EventQueue `json:"-"`
   303  
   304  	// DatapathConfiguration is the endpoint's datapath configuration as
   305  	// passed in via the plugin that created the endpoint, e.g. the CNI
   306  	// plugin which performed the plumbing will enable certain datapath
   307  	// features according to the mode selected.
   308  	DatapathConfiguration models.EndpointDatapathConfiguration
   309  
   310  	regenFailedChan chan struct{}
   311  }
   312  
   313  // UpdateController updates the controller with the specified name with the
   314  // provided list of parameters in endpoint's list of controllers.
   315  func (e *Endpoint) UpdateController(name string, params controller.ControllerParams) *controller.Controller {
   316  	return e.controllers.UpdateController(name, params)
   317  }
   318  
   319  // CloseBPFProgramChannel closes the channel that signals whether the endpoint
   320  // has had its BPF program compiled. If the channel is already closed, this is
   321  // a no-op.
   322  func (e *Endpoint) CloseBPFProgramChannel() {
   323  	select {
   324  	case <-e.hasBPFProgram:
   325  	default:
   326  		close(e.hasBPFProgram)
   327  	}
   328  }
   329  
   330  // HasBPFProgram returns whether a BPF program has been generated for this
   331  // endpoint.
   332  func (e *Endpoint) HasBPFProgram() bool {
   333  	select {
   334  	case <-e.hasBPFProgram:
   335  		return true
   336  	default:
   337  		return false
   338  	}
   339  }
   340  
   341  // HasIpvlanDataPath returns whether the daemon is running in ipvlan mode.
   342  func (e *Endpoint) HasIpvlanDataPath() bool {
   343  	if e.DatapathMapID > 0 {
   344  		return true
   345  	}
   346  	return false
   347  }
   348  
   349  // GetIngressPolicyEnabledLocked returns whether ingress policy enforcement is
   350  // enabled for endpoint or not. The endpoint's mutex must be held.
   351  func (e *Endpoint) GetIngressPolicyEnabledLocked() bool {
   352  	return e.desiredPolicy.IngressPolicyEnabled
   353  }
   354  
   355  // GetEgressPolicyEnabledLocked returns whether egress policy enforcement is
   356  // enabled for endpoint or not. The endpoint's mutex must be held.
   357  func (e *Endpoint) GetEgressPolicyEnabledLocked() bool {
   358  	return e.desiredPolicy.EgressPolicyEnabled
   359  }
   360  
   361  // SetDesiredIngressPolicyEnabled sets Endpoint's ingress policy enforcement
   362  // configuration to the specified value. The endpoint's mutex must not be held.
   363  func (e *Endpoint) SetDesiredIngressPolicyEnabled(ingress bool) {
   364  	e.UnconditionalLock()
   365  	e.desiredPolicy.IngressPolicyEnabled = ingress
   366  	e.Unlock()
   367  
   368  }
   369  
   370  // SetDesiredEgressPolicyEnabled sets Endpoint's egress policy enforcement
   371  // configuration to the specified value. The endpoint's mutex must not be held.
   372  func (e *Endpoint) SetDesiredEgressPolicyEnabled(egress bool) {
   373  	e.UnconditionalLock()
   374  	e.desiredPolicy.EgressPolicyEnabled = egress
   375  	e.Unlock()
   376  }
   377  
   378  // SetDesiredIngressPolicyEnabledLocked sets Endpoint's ingress policy enforcement
   379  // configuration to the specified value. The endpoint's mutex must be held.
   380  func (e *Endpoint) SetDesiredIngressPolicyEnabledLocked(ingress bool) {
   381  	e.desiredPolicy.IngressPolicyEnabled = ingress
   382  }
   383  
   384  // SetDesiredEgressPolicyEnabledLocked sets Endpoint's egress policy enforcement
   385  // configuration to the specified value. The endpoint's mutex must be held.
   386  func (e *Endpoint) SetDesiredEgressPolicyEnabledLocked(egress bool) {
   387  	e.desiredPolicy.EgressPolicyEnabled = egress
   388  }
   389  
   390  // WaitForProxyCompletions blocks until all proxy changes have been completed.
   391  // Called with BuildMutex held.
   392  func (e *Endpoint) WaitForProxyCompletions(proxyWaitGroup *completion.WaitGroup) error {
   393  	if proxyWaitGroup == nil {
   394  		return nil
   395  	}
   396  
   397  	err := proxyWaitGroup.Context().Err()
   398  	if err != nil {
   399  		return fmt.Errorf("context cancelled before waiting for proxy updates: %s", err)
   400  	}
   401  
   402  	start := time.Now()
   403  
   404  	e.getLogger().Debug("Waiting for proxy updates to complete...")
   405  	err = proxyWaitGroup.Wait()
   406  	if err != nil {
   407  		return fmt.Errorf("proxy state changes failed: %s", err)
   408  	}
   409  	e.getLogger().Debug("Wait time for proxy updates: ", time.Since(start))
   410  
   411  	return nil
   412  }
   413  
   414  // NewEndpointWithState creates a new endpoint useful for testing purposes
   415  func NewEndpointWithState(owner regeneration.Owner, ID uint16, state string) *Endpoint {
   416  	ep := &Endpoint{
   417  		owner:           owner,
   418  		ID:              ID,
   419  		OpLabels:        pkgLabels.NewOpLabels(),
   420  		Status:          NewEndpointStatus(),
   421  		DNSHistory:      fqdn.NewDNSCacheWithLimit(option.Config.ToFQDNsMinTTL, option.Config.ToFQDNsMaxIPsPerHost),
   422  		state:           state,
   423  		hasBPFProgram:   make(chan struct{}, 0),
   424  		controllers:     controller.NewManager(),
   425  		EventQueue:      eventqueue.NewEventQueueBuffered(fmt.Sprintf("endpoint-%d", ID), option.Config.EndpointQueueSize),
   426  		desiredPolicy:   policy.NewEndpointPolicy(owner.GetPolicyRepository()),
   427  		regenFailedChan: make(chan struct{}, 1),
   428  	}
   429  
   430  	ep.realizedPolicy = ep.desiredPolicy
   431  
   432  	ep.SetDefaultOpts(option.Config.Opts)
   433  	ep.UpdateLogger(nil)
   434  
   435  	ep.EventQueue.Run()
   436  
   437  	return ep
   438  }
   439  
   440  // NewEndpointFromChangeModel creates a new endpoint from a request
   441  func NewEndpointFromChangeModel(owner regeneration.Owner, base *models.EndpointChangeRequest) (*Endpoint, error) {
   442  	if base == nil {
   443  		return nil, nil
   444  	}
   445  
   446  	ep := &Endpoint{
   447  		owner:            owner,
   448  		ID:               uint16(base.ID),
   449  		ContainerName:    base.ContainerName,
   450  		ContainerID:      base.ContainerID,
   451  		DockerNetworkID:  base.DockerNetworkID,
   452  		DockerEndpointID: base.DockerEndpointID,
   453  		IfName:           base.InterfaceName,
   454  		K8sPodName:       base.K8sPodName,
   455  		K8sNamespace:     base.K8sNamespace,
   456  		DatapathMapID:    int(base.DatapathMapID),
   457  		IfIndex:          int(base.InterfaceIndex),
   458  		OpLabels:         pkgLabels.NewOpLabels(),
   459  		DNSHistory:       fqdn.NewDNSCacheWithLimit(option.Config.ToFQDNsMinTTL, option.Config.ToFQDNsMaxIPsPerHost),
   460  		state:            "",
   461  		Status:           NewEndpointStatus(),
   462  		hasBPFProgram:    make(chan struct{}, 0),
   463  		desiredPolicy:    policy.NewEndpointPolicy(owner.GetPolicyRepository()),
   464  		controllers:      controller.NewManager(),
   465  		regenFailedChan:  make(chan struct{}, 1),
   466  	}
   467  
   468  	ep.realizedPolicy = ep.desiredPolicy
   469  
   470  	if base.Mac != "" {
   471  		m, err := mac.ParseMAC(base.Mac)
   472  		if err != nil {
   473  			return nil, err
   474  		}
   475  		ep.LXCMAC = m
   476  	}
   477  
   478  	if base.HostMac != "" {
   479  		m, err := mac.ParseMAC(base.HostMac)
   480  		if err != nil {
   481  			return nil, err
   482  		}
   483  		ep.NodeMAC = m
   484  	}
   485  
   486  	if base.Addressing != nil {
   487  		if ip := base.Addressing.IPV6; ip != "" {
   488  			ip6, err := addressing.NewCiliumIPv6(ip)
   489  			if err != nil {
   490  				return nil, err
   491  			}
   492  			ep.IPv6 = ip6
   493  		}
   494  
   495  		if ip := base.Addressing.IPV4; ip != "" {
   496  			ip4, err := addressing.NewCiliumIPv4(ip)
   497  			if err != nil {
   498  				return nil, err
   499  			}
   500  			ep.IPv4 = ip4
   501  		}
   502  	}
   503  
   504  	if base.DatapathConfiguration != nil {
   505  		ep.DatapathConfiguration = *base.DatapathConfiguration
   506  	}
   507  
   508  	ep.SetDefaultOpts(option.Config.Opts)
   509  
   510  	ep.UpdateLogger(nil)
   511  	ep.SetStateLocked(string(base.State), "Endpoint creation")
   512  
   513  	return ep, nil
   514  }
   515  
   516  // GetModelRLocked returns the API model of endpoint e.
   517  // e.mutex must be RLocked.
   518  func (e *Endpoint) GetModelRLocked() *models.Endpoint {
   519  	if e == nil {
   520  		return nil
   521  	}
   522  
   523  	currentState := models.EndpointState(e.state)
   524  	if currentState == models.EndpointStateReady && e.Status.CurrentStatus() != OK {
   525  		currentState = models.EndpointStateNotReady
   526  	}
   527  
   528  	// This returns the most recent log entry for this endpoint. It is backwards
   529  	// compatible with the json from before we added `cilium endpoint log` but it
   530  	// only returns 1 entry.
   531  	statusLog := e.Status.GetModel()
   532  	if len(statusLog) > 0 {
   533  		statusLog = statusLog[:1]
   534  	}
   535  
   536  	lblMdl := model.NewModel(&e.OpLabels)
   537  
   538  	// Sort these slices since they come out in random orders. This allows
   539  	// reflect.DeepEqual to succeed.
   540  	sort.StringSlice(lblMdl.Realized.User).Sort()
   541  	sort.StringSlice(lblMdl.Disabled).Sort()
   542  	sort.StringSlice(lblMdl.SecurityRelevant).Sort()
   543  	sort.StringSlice(lblMdl.Derived).Sort()
   544  
   545  	controllerMdl := e.controllers.GetStatusModel()
   546  	sort.Slice(controllerMdl, func(i, j int) bool { return controllerMdl[i].Name < controllerMdl[j].Name })
   547  
   548  	spec := &models.EndpointConfigurationSpec{
   549  		LabelConfiguration: lblMdl.Realized,
   550  	}
   551  
   552  	if e.Options != nil {
   553  		spec.Options = *e.Options.GetMutableModel()
   554  	}
   555  
   556  	mdl := &models.Endpoint{
   557  		ID:   int64(e.ID),
   558  		Spec: spec,
   559  		Status: &models.EndpointStatus{
   560  			// FIXME GH-3280 When we begin implementing revision numbers this will
   561  			// diverge from models.Endpoint.Spec to reflect the in-datapath config
   562  			Realized: spec,
   563  			Identity: e.SecurityIdentity.GetModel(),
   564  			Labels:   lblMdl,
   565  			Networking: &models.EndpointNetworking{
   566  				Addressing: []*models.AddressPair{{
   567  					IPV4: e.IPv4.String(),
   568  					IPV6: e.IPv6.String(),
   569  				}},
   570  				InterfaceIndex: int64(e.IfIndex),
   571  				InterfaceName:  e.IfName,
   572  				Mac:            e.LXCMAC.String(),
   573  				HostMac:        e.NodeMAC.String(),
   574  			},
   575  			ExternalIdentifiers: &models.EndpointIdentifiers{
   576  				ContainerID:      e.ContainerID,
   577  				ContainerName:    e.ContainerName,
   578  				DockerEndpointID: e.DockerEndpointID,
   579  				DockerNetworkID:  e.DockerNetworkID,
   580  				PodName:          e.GetK8sNamespaceAndPodNameLocked(),
   581  			},
   582  			// FIXME GH-3280 When we begin returning endpoint revisions this should
   583  			// change to return the configured and in-datapath policies.
   584  			Policy:      e.GetPolicyModel(),
   585  			Log:         statusLog,
   586  			Controllers: controllerMdl,
   587  			State:       currentState, // TODO: Validate
   588  			Health:      e.getHealthModel(),
   589  		},
   590  	}
   591  
   592  	return mdl
   593  }
   594  
   595  // GetHealthModel returns the endpoint's health object.
   596  //
   597  // Must be called with e.Mutex locked.
   598  func (e *Endpoint) getHealthModel() *models.EndpointHealth {
   599  	// Duplicated from GetModelRLocked.
   600  	currentState := models.EndpointState(e.state)
   601  	if currentState == models.EndpointStateReady && e.Status.CurrentStatus() != OK {
   602  		currentState = models.EndpointStateNotReady
   603  	}
   604  
   605  	h := models.EndpointHealth{
   606  		Bpf:           models.EndpointHealthStatusDisabled,
   607  		Policy:        models.EndpointHealthStatusDisabled,
   608  		Connected:     false,
   609  		OverallHealth: models.EndpointHealthStatusDisabled,
   610  	}
   611  	switch currentState {
   612  	case models.EndpointStateRegenerating, models.EndpointStateWaitingToRegenerate, models.EndpointStateDisconnecting:
   613  		h = models.EndpointHealth{
   614  			Bpf:           models.EndpointHealthStatusPending,
   615  			Policy:        models.EndpointHealthStatusPending,
   616  			Connected:     true,
   617  			OverallHealth: models.EndpointHealthStatusPending,
   618  		}
   619  	case models.EndpointStateCreating:
   620  		h = models.EndpointHealth{
   621  			Bpf:           models.EndpointHealthStatusBootstrap,
   622  			Policy:        models.EndpointHealthStatusDisabled,
   623  			Connected:     true,
   624  			OverallHealth: models.EndpointHealthStatusDisabled,
   625  		}
   626  	case models.EndpointStateWaitingForIdentity:
   627  		h = models.EndpointHealth{
   628  			Bpf:           models.EndpointHealthStatusDisabled,
   629  			Policy:        models.EndpointHealthStatusBootstrap,
   630  			Connected:     true,
   631  			OverallHealth: models.EndpointHealthStatusDisabled,
   632  		}
   633  	case models.EndpointStateNotReady:
   634  		h = models.EndpointHealth{
   635  			Bpf:           models.EndpointHealthStatusWarning,
   636  			Policy:        models.EndpointHealthStatusWarning,
   637  			Connected:     true,
   638  			OverallHealth: models.EndpointHealthStatusWarning,
   639  		}
   640  	case models.EndpointStateDisconnected:
   641  		h = models.EndpointHealth{
   642  			Bpf:           models.EndpointHealthStatusDisabled,
   643  			Policy:        models.EndpointHealthStatusDisabled,
   644  			Connected:     false,
   645  			OverallHealth: models.EndpointHealthStatusDisabled,
   646  		}
   647  	case models.EndpointStateReady:
   648  		h = models.EndpointHealth{
   649  			Bpf:           models.EndpointHealthStatusOK,
   650  			Policy:        models.EndpointHealthStatusOK,
   651  			Connected:     true,
   652  			OverallHealth: models.EndpointHealthStatusOK,
   653  		}
   654  	}
   655  
   656  	return &h
   657  }
   658  
   659  // GetHealthModel returns the endpoint's health object.
   660  func (e *Endpoint) GetHealthModel() *models.EndpointHealth {
   661  	// NOTE: Using rlock on mutex directly because getHealthModel handles removed endpoint properly
   662  	e.mutex.RLock()
   663  	defer e.mutex.RUnlock()
   664  	return e.getHealthModel()
   665  }
   666  
   667  // GetModel returns the API model of endpoint e.
   668  func (e *Endpoint) GetModel() *models.Endpoint {
   669  	if e == nil {
   670  		return nil
   671  	}
   672  	// NOTE: Using rlock on mutex directly because GetModelRLocked handles removed endpoint properly
   673  	e.mutex.RLock()
   674  	defer e.mutex.RUnlock()
   675  
   676  	return e.GetModelRLocked()
   677  }
   678  
   679  // GetPolicyModel returns the endpoint's policy as an API model.
   680  //
   681  // Must be called with e.Mutex locked.
   682  func (e *Endpoint) GetPolicyModel() *models.EndpointPolicyStatus {
   683  	if e == nil {
   684  		return nil
   685  	}
   686  
   687  	if e.SecurityIdentity == nil {
   688  		return nil
   689  	}
   690  
   691  	realizedIngressIdentities := make([]int64, 0)
   692  	realizedEgressIdentities := make([]int64, 0)
   693  
   694  	for policyMapKey := range e.realizedPolicy.PolicyMapState {
   695  		if policyMapKey.DestPort != 0 {
   696  			// If the port is non-zero, then the Key no longer only applies
   697  			// at L3. AllowedIngressIdentities and AllowedEgressIdentities
   698  			// contain sets of which identities (i.e., label-based L3 only)
   699  			// are allowed, so anything which contains L4-related policy should
   700  			// not be added to these sets.
   701  			continue
   702  		}
   703  		switch trafficdirection.TrafficDirection(policyMapKey.TrafficDirection) {
   704  		case trafficdirection.Ingress:
   705  			realizedIngressIdentities = append(realizedIngressIdentities, int64(policyMapKey.Identity))
   706  		case trafficdirection.Egress:
   707  			realizedEgressIdentities = append(realizedEgressIdentities, int64(policyMapKey.Identity))
   708  		default:
   709  			log.WithField(logfields.TrafficDirection, trafficdirection.TrafficDirection(policyMapKey.TrafficDirection)).Error("Unexpected traffic direction present in realized PolicyMap state for endpoint")
   710  		}
   711  	}
   712  
   713  	desiredIngressIdentities := make([]int64, 0)
   714  	desiredEgressIdentities := make([]int64, 0)
   715  
   716  	for policyMapKey := range e.desiredPolicy.PolicyMapState {
   717  		if policyMapKey.DestPort != 0 {
   718  			// If the port is non-zero, then the Key no longer only applies
   719  			// at L3. AllowedIngressIdentities and AllowedEgressIdentities
   720  			// contain sets of which identities (i.e., label-based L3 only)
   721  			// are allowed, so anything which contains L4-related policy should
   722  			// not be added to these sets.
   723  			continue
   724  		}
   725  		switch trafficdirection.TrafficDirection(policyMapKey.TrafficDirection) {
   726  		case trafficdirection.Ingress:
   727  			desiredIngressIdentities = append(desiredIngressIdentities, int64(policyMapKey.Identity))
   728  		case trafficdirection.Egress:
   729  			desiredEgressIdentities = append(desiredEgressIdentities, int64(policyMapKey.Identity))
   730  		default:
   731  			log.WithField(logfields.TrafficDirection, trafficdirection.TrafficDirection(policyMapKey.TrafficDirection)).Error("Unexpected traffic direction present in desired PolicyMap state for endpoint")
   732  		}
   733  	}
   734  
   735  	policyEnabled := e.policyStatus()
   736  
   737  	e.proxyStatisticsMutex.RLock()
   738  	proxyStats := make([]*models.ProxyStatistics, 0, len(e.proxyStatistics))
   739  	for _, stats := range e.proxyStatistics {
   740  		proxyStats = append(proxyStats, stats.DeepCopy())
   741  	}
   742  	e.proxyStatisticsMutex.RUnlock()
   743  	sortProxyStats(proxyStats)
   744  
   745  	var (
   746  		realizedCIDRPolicy *policy.CIDRPolicy
   747  		realizedL4Policy   *policy.L4Policy
   748  	)
   749  	if e.realizedPolicy != nil {
   750  		realizedL4Policy = e.realizedPolicy.L4Policy
   751  		realizedCIDRPolicy = e.realizedPolicy.CIDRPolicy
   752  	}
   753  
   754  	mdl := &models.EndpointPolicy{
   755  		ID: int64(e.SecurityIdentity.ID),
   756  		// This field should be removed.
   757  		Build:                    int64(e.policyRevision),
   758  		PolicyRevision:           int64(e.policyRevision),
   759  		AllowedIngressIdentities: realizedIngressIdentities,
   760  		AllowedEgressIdentities:  realizedEgressIdentities,
   761  		CidrPolicy:               realizedCIDRPolicy.GetModel(),
   762  		L4:                       realizedL4Policy.GetModel(),
   763  		PolicyEnabled:            policyEnabled,
   764  	}
   765  
   766  	var (
   767  		desiredCIDRPolicy *policy.CIDRPolicy
   768  		desiredL4Policy   *policy.L4Policy
   769  	)
   770  	if e.desiredPolicy != nil {
   771  		desiredCIDRPolicy = e.desiredPolicy.CIDRPolicy
   772  		desiredL4Policy = e.desiredPolicy.L4Policy
   773  	}
   774  
   775  	desiredMdl := &models.EndpointPolicy{
   776  		ID: int64(e.SecurityIdentity.ID),
   777  		// This field should be removed.
   778  		Build:                    int64(e.nextPolicyRevision),
   779  		PolicyRevision:           int64(e.nextPolicyRevision),
   780  		AllowedIngressIdentities: desiredIngressIdentities,
   781  		AllowedEgressIdentities:  desiredEgressIdentities,
   782  		CidrPolicy:               desiredCIDRPolicy.GetModel(),
   783  		L4:                       desiredL4Policy.GetModel(),
   784  		PolicyEnabled:            policyEnabled,
   785  	}
   786  	// FIXME GH-3280 Once we start returning revisions Realized should be the
   787  	// policy implemented in the data path
   788  	return &models.EndpointPolicyStatus{
   789  		Spec:                desiredMdl,
   790  		Realized:            mdl,
   791  		ProxyPolicyRevision: int64(e.proxyPolicyRevision),
   792  		ProxyStatistics:     proxyStats,
   793  	}
   794  }
   795  
   796  // policyStatus returns the endpoint's policy status
   797  //
   798  // Must be called with e.Mutex locked.
   799  func (e *Endpoint) policyStatus() models.EndpointPolicyEnabled {
   800  	policyEnabled := models.EndpointPolicyEnabledNone
   801  	switch {
   802  	case e.realizedPolicy.IngressPolicyEnabled && e.realizedPolicy.EgressPolicyEnabled:
   803  		policyEnabled = models.EndpointPolicyEnabledBoth
   804  	case e.realizedPolicy.IngressPolicyEnabled:
   805  		policyEnabled = models.EndpointPolicyEnabledIngress
   806  	case e.realizedPolicy.EgressPolicyEnabled:
   807  		policyEnabled = models.EndpointPolicyEnabledEgress
   808  	}
   809  	return policyEnabled
   810  }
   811  
   812  // GetID returns the endpoint's ID as a 64-bit unsigned integer.
   813  func (e *Endpoint) GetID() uint64 {
   814  	return uint64(e.ID)
   815  }
   816  
   817  // GetLabels returns the labels as slice
   818  func (e *Endpoint) GetLabels() []string {
   819  	if e.SecurityIdentity == nil {
   820  		return []string{}
   821  	}
   822  
   823  	return e.SecurityIdentity.Labels.GetModel()
   824  }
   825  
   826  // GetSecurityIdentity returns the security identity of the endpoint. It assumes
   827  // the endpoint's mutex is held.
   828  func (e *Endpoint) GetSecurityIdentity() *identityPkg.Identity {
   829  	return e.SecurityIdentity
   830  }
   831  
   832  // GetID16 returns the endpoint's ID as a 16-bit unsigned integer.
   833  func (e *Endpoint) GetID16() uint16 {
   834  	return e.ID
   835  }
   836  
   837  // GetK8sPodLabels returns all labels that exist in the endpoint and were
   838  // derived from k8s pod.
   839  func (e *Endpoint) GetK8sPodLabels() pkgLabels.Labels {
   840  	e.UnconditionalRLock()
   841  	defer e.RUnlock()
   842  	allLabels := e.OpLabels.AllLabels()
   843  	if allLabels == nil {
   844  		return nil
   845  	}
   846  
   847  	allLabelsFromK8s := allLabels.GetFromSource(pkgLabels.LabelSourceK8s)
   848  
   849  	k8sEPPodLabels := pkgLabels.Labels{}
   850  	for k, v := range allLabelsFromK8s {
   851  		if !strings.HasPrefix(v.Key, ciliumio.PodNamespaceMetaLabels) &&
   852  			!strings.HasPrefix(v.Key, ciliumio.PolicyLabelServiceAccount) &&
   853  			!strings.HasPrefix(v.Key, ciliumio.PodNamespaceLabel) {
   854  			k8sEPPodLabels[k] = v
   855  		}
   856  	}
   857  	return k8sEPPodLabels
   858  }
   859  
   860  // GetLabelsSHA returns the SHA of labels
   861  func (e *Endpoint) GetLabelsSHA() string {
   862  	if e.SecurityIdentity == nil {
   863  		return ""
   864  	}
   865  
   866  	return e.SecurityIdentity.GetLabelsSHA256()
   867  }
   868  
   869  // GetOpLabels returns the labels as slice
   870  func (e *Endpoint) GetOpLabels() []string {
   871  	e.UnconditionalRLock()
   872  	defer e.RUnlock()
   873  	return e.OpLabels.IdentityLabels().GetModel()
   874  }
   875  
   876  // GetOptions returns the datapath configuration options of the endpoint.
   877  func (e *Endpoint) GetOptions() *option.IntOptions {
   878  	return e.Options
   879  }
   880  
   881  // GetIPv4Address returns the IPv4 address of the endpoint as a string
   882  func (e *Endpoint) GetIPv4Address() string {
   883  	return e.IPv4.String()
   884  }
   885  
   886  // GetIPv6Address returns the IPv6 address of the endpoint as a string
   887  func (e *Endpoint) GetIPv6Address() string {
   888  	return e.IPv6.String()
   889  }
   890  
   891  // IPv4Address returns the IPv4 address of the endpoint
   892  func (e *Endpoint) IPv4Address() addressing.CiliumIPv4 {
   893  	return e.IPv4
   894  }
   895  
   896  // IPv6Address returns the IPv6 address of the endpoint
   897  func (e *Endpoint) IPv6Address() addressing.CiliumIPv6 {
   898  	return e.IPv6
   899  }
   900  
   901  // GetNodeMAC returns the MAC address of the node from this endpoint's perspective.
   902  func (e *Endpoint) GetNodeMAC() mac.MAC {
   903  	return e.NodeMAC
   904  }
   905  
   906  // SetNodeMACLocked updates the node MAC inside the endpoint.
   907  func (e *Endpoint) SetNodeMACLocked(m mac.MAC) {
   908  	e.NodeMAC = m
   909  }
   910  
   911  func (e *Endpoint) HasSidecarProxy() bool {
   912  	return e.hasSidecarProxy
   913  }
   914  
   915  // ConntrackName returns the name suffix for the endpoint-specific bpf
   916  // conntrack map, which is a 5-digit endpoint ID, or "global" when the
   917  // global map should be used.
   918  // Must be called with the endpoint locked.
   919  func (e *Endpoint) ConntrackName() string {
   920  	if e.ConntrackLocalLocked() {
   921  		return fmt.Sprintf("%05d", int(e.ID))
   922  	}
   923  	return "global"
   924  }
   925  
   926  // StringID returns the endpoint's ID in a string.
   927  func (e *Endpoint) StringID() string {
   928  	return strconv.Itoa(int(e.ID))
   929  }
   930  
   931  func (e *Endpoint) GetIdentity() identityPkg.NumericIdentity {
   932  	if e.SecurityIdentity != nil {
   933  		return e.SecurityIdentity.ID
   934  	}
   935  
   936  	return identityPkg.InvalidIdentity
   937  }
   938  
   939  // Allows is only used for unit testing
   940  func (e *Endpoint) Allows(id identityPkg.NumericIdentity) bool {
   941  	e.UnconditionalRLock()
   942  	defer e.RUnlock()
   943  
   944  	keyToLookup := policy.Key{
   945  		Identity:         uint32(id),
   946  		TrafficDirection: trafficdirection.Ingress.Uint8(),
   947  	}
   948  
   949  	_, ok := e.desiredPolicy.PolicyMapState[keyToLookup]
   950  	return ok
   951  }
   952  
   953  // String returns endpoint on a JSON format.
   954  func (e *Endpoint) String() string {
   955  	e.UnconditionalRLock()
   956  	defer e.RUnlock()
   957  	b, err := json.MarshalIndent(e, "", "  ")
   958  	if err != nil {
   959  		return err.Error()
   960  	}
   961  	return string(b)
   962  }
   963  
   964  // optionChanged is a callback used with pkg/option to apply the options to an
   965  // endpoint.  Not used for anything at the moment.
   966  func optionChanged(key string, value option.OptionSetting, data interface{}) {
   967  }
   968  
   969  // applyOptsLocked applies the given options to the endpoint's options and
   970  // returns true if there were any options changed.
   971  func (e *Endpoint) applyOptsLocked(opts option.OptionMap) bool {
   972  	changed := e.Options.ApplyValidated(opts, optionChanged, e) > 0
   973  	_, exists := opts[option.Debug]
   974  	if exists && changed {
   975  		e.UpdateLogger(nil)
   976  	}
   977  	return changed
   978  }
   979  
   980  // ForcePolicyCompute marks the endpoint for forced bpf regeneration.
   981  func (e *Endpoint) ForcePolicyCompute() {
   982  	e.forcePolicyCompute = true
   983  }
   984  
   985  // SetDefaultOpts initializes the endpoint Options and configures the specified
   986  // options.
   987  func (e *Endpoint) SetDefaultOpts(opts *option.IntOptions) {
   988  	if e.Options == nil {
   989  		e.Options = option.NewIntOptions(&EndpointMutableOptionLibrary)
   990  	}
   991  	if e.Options.Library == nil {
   992  		e.Options.Library = &EndpointMutableOptionLibrary
   993  	}
   994  	if e.Options.Opts == nil {
   995  		e.Options.Opts = option.OptionMap{}
   996  	}
   997  
   998  	if opts != nil {
   999  		epOptLib := option.GetEndpointMutableOptionLibrary()
  1000  		for k := range epOptLib {
  1001  			e.Options.SetValidated(k, opts.GetValue(k))
  1002  		}
  1003  	}
  1004  	e.UpdateLogger(nil)
  1005  }
  1006  
  1007  // ConntrackLocal determines whether this endpoint is currently using a local
  1008  // table to handle connection tracking (true), or the global table (false).
  1009  func (e *Endpoint) ConntrackLocal() bool {
  1010  	e.UnconditionalRLock()
  1011  	defer e.RUnlock()
  1012  
  1013  	return e.ConntrackLocalLocked()
  1014  }
  1015  
  1016  // ConntrackLocalLocked is the same as ConntrackLocal, but assumes that the
  1017  // endpoint is already locked for reading.
  1018  func (e *Endpoint) ConntrackLocalLocked() bool {
  1019  	if e.SecurityIdentity == nil || e.Options == nil ||
  1020  		!e.Options.IsEnabled(option.ConntrackLocal) {
  1021  		return false
  1022  	}
  1023  
  1024  	return true
  1025  }
  1026  
  1027  // base64 returns the endpoint in a base64 format.
  1028  func (e *Endpoint) base64() (string, error) {
  1029  	var (
  1030  		jsonBytes []byte
  1031  		err       error
  1032  	)
  1033  
  1034  	jsonBytes, err = json.Marshal(e)
  1035  	if err != nil {
  1036  		return "", err
  1037  	}
  1038  	return base64.StdEncoding.EncodeToString(jsonBytes), nil
  1039  }
  1040  
  1041  // parseBase64ToEndpoint parses the endpoint stored in the given base64 string.
  1042  func parseBase64ToEndpoint(str string, ep *Endpoint) error {
  1043  	jsonBytes, err := base64.StdEncoding.DecodeString(str)
  1044  	if err != nil {
  1045  		return err
  1046  	}
  1047  	return json.Unmarshal(jsonBytes, ep)
  1048  }
  1049  
  1050  // FilterEPDir returns a list of directories' names that possible belong to an endpoint.
  1051  func FilterEPDir(dirFiles []os.FileInfo) []string {
  1052  	eptsID := []string{}
  1053  	for _, file := range dirFiles {
  1054  		if file.IsDir() {
  1055  			_, err := strconv.ParseUint(file.Name(), 10, 16)
  1056  			if err == nil || strings.HasSuffix(file.Name(), nextDirectorySuffix) || strings.HasSuffix(file.Name(), nextFailedDirectorySuffix) {
  1057  				eptsID = append(eptsID, file.Name())
  1058  			}
  1059  		}
  1060  	}
  1061  	return eptsID
  1062  }
  1063  
  1064  // ParseEndpoint parses the given strEp which is in the form of:
  1065  // common.CiliumCHeaderPrefix + common.Version + ":" + endpointBase64
  1066  // Note that the parse'd endpoint's identity is only partially restored. The
  1067  // caller must call `SetIdentity()` to make the returned endpoint's identity useful.
  1068  func ParseEndpoint(owner regeneration.Owner, strEp string) (*Endpoint, error) {
  1069  	// TODO: Provide a better mechanism to update from old version once we bump
  1070  	// TODO: cilium version.
  1071  	strEpSlice := strings.Split(strEp, ":")
  1072  	if len(strEpSlice) != 2 {
  1073  		return nil, fmt.Errorf("invalid format %q. Should contain a single ':'", strEp)
  1074  	}
  1075  	ep := Endpoint{
  1076  		owner:      owner,
  1077  		OpLabels:   pkgLabels.NewOpLabels(),
  1078  		DNSHistory: fqdn.NewDNSCacheWithLimit(option.Config.ToFQDNsMinTTL, option.Config.ToFQDNsMaxIPsPerHost),
  1079  	}
  1080  	if err := parseBase64ToEndpoint(strEpSlice[1], &ep); err != nil {
  1081  		return nil, fmt.Errorf("failed to parse base64toendpoint: %s", err)
  1082  	}
  1083  
  1084  	// Validate the options that were parsed
  1085  	ep.SetDefaultOpts(ep.Options)
  1086  
  1087  	// Initialize fields to values which are non-nil that are not serialized.
  1088  	ep.hasBPFProgram = make(chan struct{}, 0)
  1089  	ep.desiredPolicy = policy.NewEndpointPolicy(owner.GetPolicyRepository())
  1090  	ep.realizedPolicy = ep.desiredPolicy
  1091  	ep.controllers = controller.NewManager()
  1092  	ep.regenFailedChan = make(chan struct{}, 1)
  1093  
  1094  	// We need to check for nil in Status, CurrentStatuses and Log, since in
  1095  	// some use cases, status will be not nil and Cilium will eventually
  1096  	// error/panic if CurrentStatus or Log are not initialized correctly.
  1097  	// Reference issue GH-2477
  1098  	if ep.Status == nil || ep.Status.CurrentStatuses == nil || ep.Status.Log == nil {
  1099  		ep.Status = NewEndpointStatus()
  1100  	}
  1101  
  1102  	// Make sure the endpoint has an identity, using the 'init' identity if none.
  1103  	if ep.SecurityIdentity == nil {
  1104  		ep.SecurityIdentity = identityPkg.LookupReservedIdentity(identityPkg.ReservedIdentityInit)
  1105  	}
  1106  	ep.SecurityIdentity.Sanitize()
  1107  
  1108  	ep.UpdateLogger(nil)
  1109  
  1110  	ep.SetStateLocked(StateRestoring, "Endpoint restoring")
  1111  
  1112  	return &ep, nil
  1113  }
  1114  
  1115  func (e *Endpoint) LogStatus(typ StatusType, code StatusCode, msg string) {
  1116  	e.UnconditionalLock()
  1117  	defer e.Unlock()
  1118  	// FIXME GH2323 instead of a mutex we could use a channel to send the status
  1119  	// log message to a single writer?
  1120  	e.logStatusLocked(typ, code, msg)
  1121  }
  1122  
  1123  func (e *Endpoint) LogStatusOK(typ StatusType, msg string) {
  1124  	e.LogStatus(typ, OK, msg)
  1125  }
  1126  
  1127  // LogStatusOKLocked will log an OK message of the given status type with the
  1128  // given msg string.
  1129  // must be called with endpoint.Mutex held
  1130  func (e *Endpoint) LogStatusOKLocked(typ StatusType, msg string) {
  1131  	e.logStatusLocked(typ, OK, msg)
  1132  }
  1133  
  1134  // logStatusLocked logs a status message
  1135  // must be called with endpoint.Mutex held
  1136  func (e *Endpoint) logStatusLocked(typ StatusType, code StatusCode, msg string) {
  1137  	e.Status.indexMU.Lock()
  1138  	defer e.Status.indexMU.Unlock()
  1139  	sts := &statusLogMsg{
  1140  		Status: Status{
  1141  			Code:  code,
  1142  			Msg:   msg,
  1143  			Type:  typ,
  1144  			State: e.state,
  1145  		},
  1146  		Timestamp: time.Now().UTC(),
  1147  	}
  1148  	e.Status.addStatusLog(sts)
  1149  	e.getLogger().WithFields(logrus.Fields{
  1150  		"code":                   sts.Status.Code,
  1151  		"type":                   sts.Status.Type,
  1152  		logfields.EndpointState:  sts.Status.State,
  1153  		logfields.PolicyRevision: e.policyRevision,
  1154  	}).Debug(msg)
  1155  }
  1156  
  1157  type UpdateValidationError struct {
  1158  	msg string
  1159  }
  1160  
  1161  func (e UpdateValidationError) Error() string { return e.msg }
  1162  
  1163  type UpdateCompilationError struct {
  1164  	msg string
  1165  }
  1166  
  1167  func (e UpdateCompilationError) Error() string { return e.msg }
  1168  
  1169  // UpdateStateChangeError is an error that indicates that updating the state
  1170  // of an endpoint was unsuccessful.
  1171  // Implements error interface.
  1172  type UpdateStateChangeError struct {
  1173  	msg string
  1174  }
  1175  
  1176  func (e UpdateStateChangeError) Error() string { return e.msg }
  1177  
  1178  // Update modifies the endpoint options and *always* tries to regenerate the
  1179  // endpoint's program. Returns an error if the provided options are not valid,
  1180  // if there was an issue triggering policy updates for the given endpoint,
  1181  // or if endpoint regeneration was unable to be triggered. Note that the
  1182  // LabelConfiguration in the EndpointConfigurationSpec is *not* consumed here.
  1183  func (e *Endpoint) Update(cfg *models.EndpointConfigurationSpec) error {
  1184  	om, err := EndpointMutableOptionLibrary.ValidateConfigurationMap(cfg.Options)
  1185  	if err != nil {
  1186  		return UpdateValidationError{err.Error()}
  1187  	}
  1188  
  1189  	if err := e.LockAlive(); err != nil {
  1190  		return err
  1191  	}
  1192  
  1193  	e.getLogger().WithField("configuration-options", cfg).Debug("updating endpoint configuration options")
  1194  
  1195  	// CurrentStatus will be not OK when we have an uncleared error in BPF,
  1196  	// policy or Other. We should keep trying to regenerate in the hopes of
  1197  	// succeeding.
  1198  	// Note: This "retry" behaviour is better suited to a controller, and can be
  1199  	// moved there once we have an endpoint regeneration controller.
  1200  	regenCtx := &regeneration.ExternalRegenerationMetadata{
  1201  		Reason: "endpoint was updated via API",
  1202  	}
  1203  
  1204  	// If configuration options are provided, we only regenerate if necessary.
  1205  	// Otherwise always regenerate.
  1206  	if cfg.Options == nil {
  1207  		regenCtx.RegenerationLevel = regeneration.RegenerateWithDatapathRebuild
  1208  		regenCtx.Reason = "endpoint was manually regenerated via API"
  1209  	} else if e.updateAndOverrideEndpointOptions(om) || e.Status.CurrentStatus() != OK {
  1210  		regenCtx.RegenerationLevel = regeneration.RegenerateWithDatapathRewrite
  1211  	}
  1212  
  1213  	if regenCtx.RegenerationLevel > regeneration.RegenerateWithoutDatapath {
  1214  		e.getLogger().Debug("need to regenerate endpoint; checking state before" +
  1215  			" attempting to regenerate")
  1216  
  1217  		// TODO / FIXME: GH-3281: need ways to queue up regenerations per-endpoint.
  1218  
  1219  		// Default timeout for PATCH /endpoint/{id}/config is 60 seconds, so put
  1220  		// timeout in this function a bit below that timeout. If the timeout
  1221  		// for clients in API is below this value, they will get a message containing
  1222  		// "context deadline exceeded".
  1223  		timeout := time.After(EndpointGenerationTimeout)
  1224  
  1225  		// Check for endpoint state every second.
  1226  		ticker := time.NewTicker(1 * time.Second)
  1227  		defer ticker.Stop()
  1228  
  1229  		e.Unlock()
  1230  		for {
  1231  			select {
  1232  			case <-ticker.C:
  1233  				if err := e.LockAlive(); err != nil {
  1234  					return err
  1235  				}
  1236  				// Check endpoint state before attempting configuration update because
  1237  				// configuration updates can only be applied when the endpoint is in
  1238  				// specific states. See GH-3058.
  1239  				stateTransitionSucceeded := e.SetStateLocked(StateWaitingToRegenerate, regenCtx.Reason)
  1240  				if stateTransitionSucceeded {
  1241  					e.Unlock()
  1242  					e.Regenerate(regenCtx)
  1243  					return nil
  1244  				}
  1245  				e.Unlock()
  1246  			case <-timeout:
  1247  				e.getLogger().Warning("timed out waiting for endpoint state to change")
  1248  				return UpdateStateChangeError{fmt.Sprintf("unable to regenerate endpoint program because state transition to %s was unsuccessful; check `cilium endpoint log %d` for more information", StateWaitingToRegenerate, e.ID)}
  1249  			}
  1250  		}
  1251  
  1252  	}
  1253  
  1254  	e.Unlock()
  1255  	return nil
  1256  }
  1257  
  1258  // HasLabels returns whether endpoint e contains all labels l. Will return 'false'
  1259  // if any label in l is not in the endpoint's labels.
  1260  func (e *Endpoint) HasLabels(l pkgLabels.Labels) bool {
  1261  	e.UnconditionalRLock()
  1262  	defer e.RUnlock()
  1263  
  1264  	return e.hasLabelsRLocked(l)
  1265  }
  1266  
  1267  // hasLabelsRLocked returns whether endpoint e contains all labels l. Will
  1268  // return 'false' if any label in l is not in the endpoint's labels.
  1269  // e.Mutex must be RLocked
  1270  func (e *Endpoint) hasLabelsRLocked(l pkgLabels.Labels) bool {
  1271  	allEpLabels := e.OpLabels.AllLabels()
  1272  
  1273  	for _, v := range l {
  1274  		found := false
  1275  		for _, j := range allEpLabels {
  1276  			if j.Equals(&v) {
  1277  				found = true
  1278  				break
  1279  			}
  1280  		}
  1281  		if !found {
  1282  			return false
  1283  		}
  1284  	}
  1285  
  1286  	return true
  1287  }
  1288  
  1289  // replaceInformationLabels replaces the information labels of the endpoint.
  1290  // Passing a nil set of labels will not perform any action.
  1291  // Must be called with e.Mutex.Lock().
  1292  func (e *Endpoint) replaceInformationLabels(l pkgLabels.Labels) {
  1293  	if l == nil {
  1294  		return
  1295  	}
  1296  	e.OpLabels.ReplaceInformationLabels(l, e.getLogger())
  1297  }
  1298  
  1299  // replaceIdentityLabels replaces the identity labels of the endpoint. If a net
  1300  // changed occurred, the identityRevision is bumped and returned, otherwise 0 is
  1301  // returned.
  1302  // Passing a nil set of labels will not perform any action and will return the
  1303  // current endpoint's identityRevision.
  1304  // Must be called with e.Mutex.Lock().
  1305  func (e *Endpoint) replaceIdentityLabels(l pkgLabels.Labels) int {
  1306  	if l == nil {
  1307  		return e.identityRevision
  1308  	}
  1309  
  1310  	changed := e.OpLabels.ReplaceIdentityLabels(l, e.getLogger())
  1311  	rev := 0
  1312  	if changed {
  1313  		e.identityRevision++
  1314  		rev = e.identityRevision
  1315  	}
  1316  
  1317  	return rev
  1318  }
  1319  
  1320  // DeleteConfig is the endpoint deletion configuration
  1321  type DeleteConfig struct {
  1322  	NoIPRelease       bool
  1323  	NoIdentityRelease bool
  1324  }
  1325  
  1326  // LeaveLocked removes the endpoint's directory from the system. Must be called
  1327  // with Endpoint's mutex AND BuildMutex locked.
  1328  //
  1329  // Note: LeaveLocked() is called indirectly from endpoint restore logic for
  1330  // endpoints which failed to be restored. Any cleanup routine of LeaveLocked()
  1331  // which depends on kvstore connectivity must be protected by a flag in
  1332  // DeleteConfig and the restore logic must opt-out of it.
  1333  func (e *Endpoint) LeaveLocked(proxyWaitGroup *completion.WaitGroup, conf DeleteConfig) []error {
  1334  	errors := []error{}
  1335  
  1336  	if !option.Config.DryMode {
  1337  		loader.Unload(e.createEpInfoCache(""))
  1338  	}
  1339  
  1340  	e.owner.RemoveFromEndpointQueue(uint64(e.ID))
  1341  	if e.SecurityIdentity != nil && len(e.realizedRedirects) > 0 {
  1342  		// Passing a new map of nil will purge all redirects
  1343  		finalize, _ := e.removeOldRedirects(nil, proxyWaitGroup)
  1344  		if finalize != nil {
  1345  			finalize()
  1346  		}
  1347  	}
  1348  
  1349  	if e.PolicyMap != nil {
  1350  		if err := e.PolicyMap.Close(); err != nil {
  1351  			errors = append(errors, fmt.Errorf("unable to close policymap %s: %s", e.PolicyMap.String(), err))
  1352  		}
  1353  	}
  1354  
  1355  	if e.bpfConfigMap != nil {
  1356  		if err := e.bpfConfigMap.Close(); err != nil {
  1357  			errors = append(errors, fmt.Errorf("unable to close configmap %s: %s", e.BPFConfigMapPath(), err))
  1358  		}
  1359  	}
  1360  
  1361  	if !conf.NoIdentityRelease && e.SecurityIdentity != nil {
  1362  		identitymanager.Remove(e.SecurityIdentity)
  1363  
  1364  		releaseCtx, cancel := context.WithTimeout(context.Background(), option.Config.KVstoreConnectivityTimeout)
  1365  		defer cancel()
  1366  
  1367  		_, err := cache.Release(releaseCtx, e.owner, e.SecurityIdentity)
  1368  		if err != nil {
  1369  			errors = append(errors, fmt.Errorf("unable to release identity: %s", err))
  1370  		}
  1371  		e.owner.RemoveNetworkPolicy(e)
  1372  		e.SecurityIdentity = nil
  1373  	}
  1374  
  1375  	e.removeDirectories()
  1376  	e.controllers.RemoveAll()
  1377  	e.cleanPolicySignals()
  1378  
  1379  	if e.dnsHistoryTrigger != nil {
  1380  		e.dnsHistoryTrigger.Shutdown()
  1381  	}
  1382  
  1383  	if e.ConntrackLocalLocked() {
  1384  		ctmap.CloseLocalMaps(e.ConntrackName())
  1385  	} else if !option.Config.DryMode {
  1386  		e.scrubIPsInConntrackTableLocked()
  1387  	}
  1388  
  1389  	e.SetStateLocked(StateDisconnected, "Endpoint removed")
  1390  
  1391  	endpointPolicyStatus.Remove(e.ID)
  1392  	e.getLogger().Info("Removed endpoint")
  1393  
  1394  	return errors
  1395  }
  1396  
  1397  // RegenerateWait should only be called when endpoint's state has successfully
  1398  // been changed to "waiting-to-regenerate"
  1399  func (e *Endpoint) RegenerateWait(reason string) error {
  1400  	if !<-e.Regenerate(&regeneration.ExternalRegenerationMetadata{Reason: reason}) {
  1401  		return fmt.Errorf("error while regenerating endpoint."+
  1402  			" For more info run: 'cilium endpoint get %d'", e.ID)
  1403  	}
  1404  	return nil
  1405  }
  1406  
  1407  // SetContainerName modifies the endpoint's container name
  1408  func (e *Endpoint) SetContainerName(name string) {
  1409  	e.UnconditionalLock()
  1410  	e.ContainerName = name
  1411  	e.Unlock()
  1412  }
  1413  
  1414  // GetK8sNamespace returns the name of the pod if the endpoint represents a
  1415  // Kubernetes pod
  1416  func (e *Endpoint) GetK8sNamespace() string {
  1417  	e.UnconditionalRLock()
  1418  	ns := e.K8sNamespace
  1419  	e.RUnlock()
  1420  	return ns
  1421  }
  1422  
  1423  // SetK8sNamespace modifies the endpoint's pod name
  1424  func (e *Endpoint) SetK8sNamespace(name string) {
  1425  	e.UnconditionalLock()
  1426  	e.K8sNamespace = name
  1427  	e.UpdateLogger(map[string]interface{}{
  1428  		logfields.K8sPodName: e.GetK8sNamespaceAndPodNameLocked(),
  1429  	})
  1430  	e.Unlock()
  1431  }
  1432  
  1433  // K8sNamespaceAndPodNameIsSet returns true if the pod name is set
  1434  func (e *Endpoint) K8sNamespaceAndPodNameIsSet() bool {
  1435  	e.UnconditionalLock()
  1436  	podName := e.GetK8sNamespaceAndPodNameLocked()
  1437  	e.Unlock()
  1438  	return podName != "" && podName != "/"
  1439  }
  1440  
  1441  // GetK8sPodName returns the name of the pod if the endpoint represents a
  1442  // Kubernetes pod
  1443  func (e *Endpoint) GetK8sPodName() string {
  1444  	e.UnconditionalRLock()
  1445  	k8sPodName := e.K8sPodName
  1446  	e.RUnlock()
  1447  
  1448  	return k8sPodName
  1449  }
  1450  
  1451  // HumanStringLocked returns the endpoint's most human readable identifier as string
  1452  func (e *Endpoint) HumanStringLocked() string {
  1453  	if pod := e.GetK8sNamespaceAndPodNameLocked(); pod != "" {
  1454  		return pod
  1455  	}
  1456  
  1457  	return e.StringID()
  1458  }
  1459  
  1460  // GetK8sNamespaceAndPodNameLocked returns the namespace and pod name.  This
  1461  // function requires e.Mutex to be held.
  1462  func (e *Endpoint) GetK8sNamespaceAndPodNameLocked() string {
  1463  	return e.K8sNamespace + "/" + e.K8sPodName
  1464  }
  1465  
  1466  // SetK8sPodName modifies the endpoint's pod name
  1467  func (e *Endpoint) SetK8sPodName(name string) {
  1468  	e.UnconditionalLock()
  1469  	e.K8sPodName = name
  1470  	e.UpdateLogger(map[string]interface{}{
  1471  		logfields.K8sPodName: e.GetK8sNamespaceAndPodNameLocked(),
  1472  	})
  1473  	e.Unlock()
  1474  }
  1475  
  1476  // SetContainerID modifies the endpoint's container ID
  1477  func (e *Endpoint) SetContainerID(id string) {
  1478  	e.UnconditionalLock()
  1479  	e.ContainerID = id
  1480  	e.UpdateLogger(map[string]interface{}{
  1481  		logfields.ContainerID: e.getShortContainerID(),
  1482  	})
  1483  	e.Unlock()
  1484  }
  1485  
  1486  // GetContainerID returns the endpoint's container ID
  1487  func (e *Endpoint) GetContainerID() string {
  1488  	e.UnconditionalRLock()
  1489  	cID := e.ContainerID
  1490  	e.RUnlock()
  1491  	return cID
  1492  }
  1493  
  1494  // GetShortContainerID returns the endpoint's shortened container ID
  1495  func (e *Endpoint) GetShortContainerID() string {
  1496  	e.UnconditionalRLock()
  1497  	defer e.RUnlock()
  1498  
  1499  	return e.getShortContainerID()
  1500  }
  1501  
  1502  func (e *Endpoint) getShortContainerID() string {
  1503  	if e == nil {
  1504  		return ""
  1505  	}
  1506  
  1507  	caplen := 10
  1508  	if len(e.ContainerID) <= caplen {
  1509  		return e.ContainerID
  1510  	}
  1511  
  1512  	return e.ContainerID[:caplen]
  1513  
  1514  }
  1515  
  1516  // SetDockerEndpointID modifies the endpoint's Docker Endpoint ID
  1517  func (e *Endpoint) SetDockerEndpointID(id string) {
  1518  	e.UnconditionalLock()
  1519  	e.DockerEndpointID = id
  1520  	e.Unlock()
  1521  }
  1522  
  1523  // SetDockerNetworkID modifies the endpoint's Docker Endpoint ID
  1524  func (e *Endpoint) SetDockerNetworkID(id string) {
  1525  	e.UnconditionalLock()
  1526  	e.DockerNetworkID = id
  1527  	e.Unlock()
  1528  }
  1529  
  1530  // GetDockerNetworkID returns the endpoint's Docker Endpoint ID
  1531  func (e *Endpoint) GetDockerNetworkID() string {
  1532  	e.UnconditionalRLock()
  1533  	defer e.RUnlock()
  1534  
  1535  	return e.DockerNetworkID
  1536  }
  1537  
  1538  // SetDatapathMapIDAndPinMapLocked modifies the endpoint's datapath map ID
  1539  func (e *Endpoint) SetDatapathMapIDAndPinMapLocked(id int) error {
  1540  	e.DatapathMapID = id
  1541  	return e.PinDatapathMap()
  1542  }
  1543  
  1544  // IsDatapathMapPinnedLocked returns whether the endpoint's datapath map has been pinned
  1545  func (e *Endpoint) IsDatapathMapPinnedLocked() bool {
  1546  	return e.isDatapathMapPinned
  1547  }
  1548  
  1549  // GetState returns the endpoint's state
  1550  // endpoint.Mutex may only be.RLockAlive()ed
  1551  func (e *Endpoint) GetStateLocked() string {
  1552  	return e.state
  1553  }
  1554  
  1555  // GetState returns the endpoint's state
  1556  // endpoint.Mutex may only be.RLockAlive()ed
  1557  func (e *Endpoint) GetState() string {
  1558  	e.UnconditionalRLock()
  1559  	defer e.RUnlock()
  1560  	return e.GetStateLocked()
  1561  }
  1562  
  1563  // SetState modifies the endpoint's state
  1564  // Returns true only if endpoints state was changed as requested
  1565  func (e *Endpoint) SetState(toState, reason string) bool {
  1566  	e.UnconditionalLock()
  1567  	defer e.Unlock()
  1568  	return e.SetStateLocked(toState, reason)
  1569  }
  1570  
  1571  // SetStateLocked modifies the endpoint's state
  1572  // endpoint.Mutex must be held
  1573  // Returns true only if endpoints state was changed as requested
  1574  func (e *Endpoint) SetStateLocked(toState, reason string) bool {
  1575  	// Validate the state transition.
  1576  	fromState := e.state
  1577  
  1578  	switch fromState { // From state
  1579  	case "": // Special case for capturing initial state transitions like
  1580  		// nil --> StateWaitingForIdentity, StateRestoring
  1581  		switch toState {
  1582  		case StateWaitingForIdentity, StateRestoring:
  1583  			goto OKState
  1584  		}
  1585  	case StateCreating:
  1586  		switch toState {
  1587  		case StateDisconnecting, StateWaitingForIdentity, StateRestoring:
  1588  			goto OKState
  1589  		}
  1590  	case StateWaitingForIdentity:
  1591  		switch toState {
  1592  		case StateReady, StateDisconnecting, StateInvalid:
  1593  			goto OKState
  1594  		}
  1595  	case StateReady:
  1596  		switch toState {
  1597  		case StateWaitingForIdentity, StateDisconnecting, StateWaitingToRegenerate, StateRestoring:
  1598  			goto OKState
  1599  		}
  1600  	case StateDisconnecting:
  1601  		switch toState {
  1602  		case StateDisconnected:
  1603  			goto OKState
  1604  		}
  1605  	case StateDisconnected, StateInvalid:
  1606  		// No valid transitions, as disconnected and invalid are terminal
  1607  		// states for the endpoint.
  1608  	case StateWaitingToRegenerate:
  1609  		switch toState {
  1610  		// Note that transitions to StateWaitingToRegenerate are not allowed,
  1611  		// as callers of this function enqueue regenerations if 'true' is
  1612  		// returned. We don't want to return 'true' for the case of
  1613  		// transitioning to StateWaitingToRegenerate, as this means that a
  1614  		// regeneration is already queued up. Callers would then queue up
  1615  		// another unneeded regeneration, which is undesired.
  1616  		case StateWaitingForIdentity, StateDisconnecting, StateRestoring:
  1617  			goto OKState
  1618  		// Don't log this state transition being invalid below so that we don't
  1619  		// put warnings in the logs for a case which does not result in incorrect
  1620  		// behavior.
  1621  		case StateWaitingToRegenerate:
  1622  			return false
  1623  		}
  1624  	case StateRegenerating:
  1625  		switch toState {
  1626  		// Even while the endpoint is regenerating it is
  1627  		// possible that further changes require a new
  1628  		// build. In this case the endpoint is transitioned
  1629  		// from the regenerating state to
  1630  		// waiting-for-identity or waiting-to-regenerate state.
  1631  		case StateWaitingForIdentity, StateDisconnecting, StateWaitingToRegenerate, StateRestoring:
  1632  			goto OKState
  1633  		}
  1634  	case StateRestoring:
  1635  		switch toState {
  1636  		case StateDisconnecting, StateRestoring:
  1637  			goto OKState
  1638  		}
  1639  	}
  1640  	if toState != fromState {
  1641  		_, fileName, fileLine, _ := runtime.Caller(1)
  1642  		e.getLogger().WithFields(logrus.Fields{
  1643  			logfields.EndpointState + ".from": fromState,
  1644  			logfields.EndpointState + ".to":   toState,
  1645  			"file":                            fileName,
  1646  			"line":                            fileLine,
  1647  		}).Info("Invalid state transition skipped")
  1648  	}
  1649  	e.logStatusLocked(Other, Warning, fmt.Sprintf("Skipped invalid state transition to %s due to: %s", toState, reason))
  1650  	return false
  1651  
  1652  OKState:
  1653  	e.state = toState
  1654  	e.logStatusLocked(Other, OK, reason)
  1655  
  1656  	if fromState != "" {
  1657  		metrics.EndpointStateCount.
  1658  			WithLabelValues(fromState).Dec()
  1659  	}
  1660  
  1661  	// Since StateDisconnected and StateInvalid are final states, after which
  1662  	// the endpoint is gone or doesn't exist, we should not increment metrics
  1663  	// for these states.
  1664  	if toState != "" && toState != StateDisconnected && toState != StateInvalid {
  1665  		metrics.EndpointStateCount.
  1666  			WithLabelValues(toState).Inc()
  1667  	}
  1668  	return true
  1669  }
  1670  
  1671  // BuilderSetStateLocked modifies the endpoint's state
  1672  // endpoint.Mutex must be held
  1673  // endpoint BuildMutex must be held!
  1674  func (e *Endpoint) BuilderSetStateLocked(toState, reason string) bool {
  1675  	// Validate the state transition.
  1676  	fromState := e.state
  1677  	switch fromState { // From state
  1678  	case StateCreating, StateWaitingForIdentity, StateReady, StateDisconnecting, StateDisconnected, StateInvalid:
  1679  		// No valid transitions for the builder
  1680  	case StateWaitingToRegenerate, StateRestoring:
  1681  		switch toState {
  1682  		// Builder transitions the endpoint from
  1683  		// waiting-to-regenerate state to regenerating state
  1684  		// right after acquiring the endpoint lock, and while
  1685  		// endpoint's build mutex is held. All changes to
  1686  		// cilium and endpoint configuration, policy as well
  1687  		// as the existing set of security identities will be
  1688  		// reconsidered after this point, i.e., even if some
  1689  		// of them are changed regeneration need not be queued
  1690  		// if the endpoint is already in waiting-to-regenerate
  1691  		// state.
  1692  		case StateRegenerating:
  1693  			goto OKState
  1694  		// Transition to ReadyState is not supported, but is
  1695  		// attempted when a regeneration is competed, and another
  1696  		// regeneration has been queued in the meanwhile. So this
  1697  		// is expected and will not be logged as an error or warning.
  1698  		case StateReady:
  1699  			return false
  1700  		}
  1701  	case StateRegenerating:
  1702  		switch toState {
  1703  		// While still holding the build mutex, the builder
  1704  		// tries to transition the endpoint to ready
  1705  		// state. But since the endpoint mutex was released
  1706  		// for the duration of the bpf generation, it is
  1707  		// possible that another build request has been
  1708  		// queued. In this case the endpoint has been
  1709  		// transitioned to waiting-to-regenerate state
  1710  		// already, and the transition to ready state is
  1711  		// skipped (but not worth logging for, as this is
  1712  		// normal, see above).
  1713  		case StateReady:
  1714  			goto OKState
  1715  		}
  1716  	}
  1717  	e.logStatusLocked(Other, Warning, fmt.Sprintf("Skipped invalid state transition to %s due to: %s", toState, reason))
  1718  	return false
  1719  
  1720  OKState:
  1721  	e.state = toState
  1722  	e.logStatusLocked(Other, OK, reason)
  1723  
  1724  	if fromState != "" {
  1725  		metrics.EndpointStateCount.
  1726  			WithLabelValues(fromState).Dec()
  1727  	}
  1728  
  1729  	// Since StateDisconnected and StateInvalid are final states, after which
  1730  	// the endpoint is gone or doesn't exist, we should not increment metrics
  1731  	// for these states.
  1732  	if toState != "" && toState != StateDisconnected && toState != StateInvalid {
  1733  		metrics.EndpointStateCount.
  1734  			WithLabelValues(toState).Inc()
  1735  	}
  1736  	return true
  1737  }
  1738  
  1739  // OnProxyPolicyUpdate is a callback used to update the Endpoint's
  1740  // proxyPolicyRevision when the specified revision has been applied in the
  1741  // proxy.
  1742  func (e *Endpoint) OnProxyPolicyUpdate(revision uint64) {
  1743  	// NOTE: UnconditionalLock is used here because this callback has no way of reporting an error
  1744  	e.UnconditionalLock()
  1745  	if revision > e.proxyPolicyRevision {
  1746  		e.proxyPolicyRevision = revision
  1747  	}
  1748  	e.Unlock()
  1749  }
  1750  
  1751  // getProxyStatisticsLocked gets the ProxyStatistics for the flows with the
  1752  // given characteristics, or adds a new one and returns it.
  1753  // Must be called with e.proxyStatisticsMutex held.
  1754  func (e *Endpoint) getProxyStatisticsLocked(key string, l7Protocol string, port uint16, ingress bool) *models.ProxyStatistics {
  1755  	if e.proxyStatistics == nil {
  1756  		e.proxyStatistics = make(map[string]*models.ProxyStatistics)
  1757  	}
  1758  
  1759  	proxyStats, ok := e.proxyStatistics[key]
  1760  	if !ok {
  1761  		var location string
  1762  		if ingress {
  1763  			location = models.ProxyStatisticsLocationIngress
  1764  		} else {
  1765  			location = models.ProxyStatisticsLocationEgress
  1766  		}
  1767  		proxyStats = &models.ProxyStatistics{
  1768  			Location: location,
  1769  			Port:     int64(port),
  1770  			Protocol: l7Protocol,
  1771  			Statistics: &models.RequestResponseStatistics{
  1772  				Requests:  &models.MessageForwardingStatistics{},
  1773  				Responses: &models.MessageForwardingStatistics{},
  1774  			},
  1775  		}
  1776  
  1777  		e.proxyStatistics[key] = proxyStats
  1778  	}
  1779  
  1780  	return proxyStats
  1781  }
  1782  
  1783  // UpdateProxyStatistics updates the Endpoint's proxy  statistics to account
  1784  // for a new observed flow with the given characteristics.
  1785  func (e *Endpoint) UpdateProxyStatistics(l4Protocol string, port uint16, ingress, request bool, verdict accesslog.FlowVerdict) {
  1786  	e.proxyStatisticsMutex.Lock()
  1787  	defer e.proxyStatisticsMutex.Unlock()
  1788  
  1789  	key := policy.ProxyID(e.ID, ingress, l4Protocol, port)
  1790  	proxyStats, ok := e.proxyStatistics[key]
  1791  	if !ok {
  1792  		e.getLogger().WithField(logfields.L4PolicyID, key).Warn("Proxy stats not found when updating")
  1793  		return
  1794  	}
  1795  
  1796  	var stats *models.MessageForwardingStatistics
  1797  	if request {
  1798  		stats = proxyStats.Statistics.Requests
  1799  	} else {
  1800  		stats = proxyStats.Statistics.Responses
  1801  	}
  1802  
  1803  	stats.Received++
  1804  	metrics.ProxyReceived.Inc()
  1805  	metrics.ProxyPolicyL7Total.WithLabelValues("received").Inc()
  1806  
  1807  	switch verdict {
  1808  	case accesslog.VerdictForwarded:
  1809  		stats.Forwarded++
  1810  		metrics.ProxyForwarded.Inc()
  1811  		metrics.ProxyPolicyL7Total.WithLabelValues("forwarded").Inc()
  1812  	case accesslog.VerdictDenied:
  1813  		stats.Denied++
  1814  		metrics.ProxyDenied.Inc()
  1815  		metrics.ProxyPolicyL7Total.WithLabelValues("denied").Inc()
  1816  	case accesslog.VerdictError:
  1817  		stats.Error++
  1818  		metrics.ProxyParseErrors.Inc()
  1819  		metrics.ProxyPolicyL7Total.WithLabelValues("parse_errors").Inc()
  1820  	}
  1821  }
  1822  
  1823  // APICanModify determines whether API requests from a user are allowed to
  1824  // modify this endpoint.
  1825  func APICanModify(e *Endpoint) error {
  1826  	if e.IsInit() {
  1827  		return nil
  1828  	}
  1829  	if e.OpLabels.OrchestrationIdentity.IsReserved() {
  1830  		return fmt.Errorf("endpoint may not be associated reserved labels")
  1831  	}
  1832  	return nil
  1833  }
  1834  
  1835  func (e *Endpoint) getIDandLabels() string {
  1836  	e.UnconditionalRLock()
  1837  	defer e.RUnlock()
  1838  
  1839  	labels := ""
  1840  	if e.SecurityIdentity != nil {
  1841  		labels = e.SecurityIdentity.Labels.String()
  1842  	}
  1843  
  1844  	return fmt.Sprintf("%d (%s)", e.ID, labels)
  1845  }
  1846  
  1847  // MetadataResolverCB provides an implementation for resolving the endpoint
  1848  // metadata for an endpoint such as the associated labels and annotations.
  1849  type MetadataResolverCB func(*Endpoint) (identityLabels labels.Labels, infoLabels labels.Labels, err error)
  1850  
  1851  // RunMetadataResolver starts a controller associated with the received
  1852  // endpoint which will periodically attempt to resolve the metadata for the
  1853  // endpoint and update the endpoint with the related. It stops resolving after
  1854  // either the first successful metadata resolution or when the endpoint is
  1855  // removed.
  1856  //
  1857  // This assumes that after the initial successful resolution, other mechanisms
  1858  // will handle updates (such as pkg/k8s/watchers informers).
  1859  func (e *Endpoint) RunMetadataResolver(resolveMetadata MetadataResolverCB) {
  1860  	done := make(chan struct{})
  1861  	controllerName := fmt.Sprintf("resolve-labels-%s/%s", e.GetK8sNamespace(), e.GetK8sPodName())
  1862  	go func() {
  1863  		<-done
  1864  		e.controllers.RemoveController(controllerName)
  1865  	}()
  1866  
  1867  	e.controllers.UpdateController(controllerName,
  1868  		controller.ControllerParams{
  1869  			DoFunc: func(ctx context.Context) error {
  1870  				identityLabels, info, err := resolveMetadata(e)
  1871  				if err != nil {
  1872  					e.Logger(controllerName).WithError(err).Warning("Unable to fetch kubernetes labels")
  1873  					return err
  1874  				}
  1875  				e.UpdateLabels(ctx, identityLabels, info, true)
  1876  				close(done)
  1877  				return nil
  1878  			},
  1879  			RunInterval: 30 * time.Second,
  1880  		},
  1881  	)
  1882  }
  1883  
  1884  // ModifyIdentityLabels changes the custom and orchestration identity labels of an endpoint.
  1885  // Labels can be added or deleted. If a label change is performed, the
  1886  // endpoint will receive a new identity and will be regenerated. Both of these
  1887  // operations will happen in the background.
  1888  func (e *Endpoint) ModifyIdentityLabels(addLabels, delLabels pkgLabels.Labels) error {
  1889  	if err := e.LockAlive(); err != nil {
  1890  		return err
  1891  	}
  1892  
  1893  	changed, err := e.OpLabels.ModifyIdentityLabels(addLabels, delLabels)
  1894  	if err != nil {
  1895  		e.Unlock()
  1896  		return err
  1897  	}
  1898  
  1899  	var rev int
  1900  	if changed {
  1901  		// Mark with StateWaitingForIdentity, it will be set to
  1902  		// StateWaitingToRegenerate after the identity resolution has been
  1903  		// completed
  1904  		e.SetStateLocked(StateWaitingForIdentity, "Triggering identity resolution due to updated identity labels")
  1905  
  1906  		e.identityRevision++
  1907  		rev = e.identityRevision
  1908  	}
  1909  	e.Unlock()
  1910  
  1911  	if changed {
  1912  		e.runIdentityResolver(context.Background(), rev, false)
  1913  	}
  1914  	return nil
  1915  }
  1916  
  1917  // IsInit returns true if the endpoint still hasn't received identity labels,
  1918  // i.e. has the special identity with label reserved:init.
  1919  func (e *Endpoint) IsInit() bool {
  1920  	init, found := e.OpLabels.GetIdentityLabel(pkgLabels.IDNameInit)
  1921  	return found && init.Source == pkgLabels.LabelSourceReserved
  1922  }
  1923  
  1924  // UpdateLabels is called to update the labels of an endpoint. Calls to this
  1925  // function do not necessarily mean that the labels actually changed. The
  1926  // container runtime layer will periodically synchronize labels.
  1927  //
  1928  // If a net label changed was performed, the endpoint will receive a new
  1929  // identity and will be regenerated. Both of these operations will happen in
  1930  // the background.
  1931  func (e *Endpoint) UpdateLabels(ctx context.Context, identityLabels, infoLabels pkgLabels.Labels, blocking bool) {
  1932  	log.WithFields(logrus.Fields{
  1933  		logfields.ContainerID:    e.GetShortContainerID(),
  1934  		logfields.EndpointID:     e.StringID(),
  1935  		logfields.IdentityLabels: identityLabels.String(),
  1936  		logfields.InfoLabels:     infoLabels.String(),
  1937  	}).Debug("Refreshing labels of endpoint")
  1938  
  1939  	if err := e.LockAlive(); err != nil {
  1940  		e.LogDisconnectedMutexAction(err, "when trying to refresh endpoint labels")
  1941  		return
  1942  	}
  1943  
  1944  	e.replaceInformationLabels(infoLabels)
  1945  	// replace identity labels and update the identity if labels have changed
  1946  	rev := e.replaceIdentityLabels(identityLabels)
  1947  	e.Unlock()
  1948  	if rev != 0 {
  1949  		e.runIdentityResolver(ctx, rev, blocking)
  1950  	}
  1951  }
  1952  
  1953  func (e *Endpoint) identityResolutionIsObsolete(myChangeRev int) bool {
  1954  	// Check if the endpoint has since received a new identity revision, if
  1955  	// so, abort as a new resolution routine will have been started.
  1956  	if myChangeRev != e.identityRevision {
  1957  		return true
  1958  	}
  1959  
  1960  	return false
  1961  }
  1962  
  1963  // runIdentityResolver resolves the numeric identity for the set of labels that
  1964  // are currently configured on the endpoint.
  1965  //
  1966  // Must be called with e.Mutex NOT held.
  1967  func (e *Endpoint) runIdentityResolver(ctx context.Context, myChangeRev int, blocking bool) {
  1968  	if err := e.RLockAlive(); err != nil {
  1969  		// If a labels update and an endpoint delete API request arrive
  1970  		// in quick succession, this could occur; in that case, there's
  1971  		// no point updating the controller.
  1972  		e.getLogger().WithError(err).Info("Cannot run labels resolver")
  1973  		return
  1974  	}
  1975  	newLabels := e.OpLabels.IdentityLabels()
  1976  	e.RUnlock()
  1977  	scopedLog := e.getLogger().WithField(logfields.IdentityLabels, newLabels)
  1978  
  1979  	// If we are certain we can resolve the identity without accessing the KV
  1980  	// store, do it first synchronously right now. This can reduce the number
  1981  	// of regenerations for the endpoint during its initialization.
  1982  	if blocking || cache.IdentityAllocationIsLocal(newLabels) {
  1983  		scopedLog.Info("Resolving identity labels (blocking)")
  1984  
  1985  		err := e.identityLabelsChanged(ctx, myChangeRev)
  1986  		switch err {
  1987  		case ErrNotAlive:
  1988  			scopedLog.Debug("not changing endpoint identity because endpoint is in process of being removed")
  1989  			return
  1990  		default:
  1991  			if err != nil {
  1992  				scopedLog.WithError(err).Warn("Error changing endpoint identity")
  1993  			}
  1994  		}
  1995  	} else {
  1996  		scopedLog.Info("Resolving identity labels (non-blocking)")
  1997  	}
  1998  
  1999  	ctrlName := fmt.Sprintf("resolve-identity-%d", e.ID)
  2000  	e.controllers.UpdateController(ctrlName,
  2001  		controller.ControllerParams{
  2002  			DoFunc: func(ctx context.Context) error {
  2003  				err := e.identityLabelsChanged(ctx, myChangeRev)
  2004  				switch err {
  2005  				case ErrNotAlive:
  2006  					e.getLogger().Debug("not changing endpoint identity because endpoint is in process of being removed")
  2007  					return controller.NewExitReason("Endpoint disappeared")
  2008  				default:
  2009  					return err
  2010  				}
  2011  			},
  2012  			RunInterval: 5 * time.Minute,
  2013  		},
  2014  	)
  2015  }
  2016  
  2017  func (e *Endpoint) identityLabelsChanged(ctx context.Context, myChangeRev int) error {
  2018  	if err := e.RLockAlive(); err != nil {
  2019  		return ErrNotAlive
  2020  	}
  2021  	newLabels := e.OpLabels.IdentityLabels()
  2022  	elog := e.getLogger().WithFields(logrus.Fields{
  2023  		logfields.EndpointID:     e.ID,
  2024  		logfields.IdentityLabels: newLabels,
  2025  	})
  2026  
  2027  	// Since we unlocked the endpoint and re-locked, the label update may already be obsolete
  2028  	if e.identityResolutionIsObsolete(myChangeRev) {
  2029  		e.RUnlock()
  2030  		elog.Debug("Endpoint identity has changed, aborting resolution routine in favour of new one")
  2031  		return nil
  2032  	}
  2033  
  2034  	if e.SecurityIdentity != nil && e.SecurityIdentity.Labels.Equals(newLabels) {
  2035  		// Sets endpoint state to ready if was waiting for identity
  2036  		if e.GetStateLocked() == StateWaitingForIdentity {
  2037  			e.SetStateLocked(StateReady, "Set identity for this endpoint")
  2038  		}
  2039  		e.RUnlock()
  2040  		elog.Debug("Endpoint labels unchanged, skipping resolution of identity")
  2041  		return nil
  2042  	}
  2043  
  2044  	// Unlock the endpoint mutex for the possibly long lasting kvstore operation
  2045  	e.RUnlock()
  2046  	elog.Debug("Resolving identity for labels")
  2047  
  2048  	allocateCtx, cancel := context.WithTimeout(context.Background(), option.Config.KVstoreConnectivityTimeout)
  2049  	defer cancel()
  2050  
  2051  	identity, _, err := cache.AllocateIdentity(allocateCtx, e.owner, newLabels)
  2052  	if err != nil {
  2053  		err = fmt.Errorf("unable to resolve identity: %s", err)
  2054  		e.LogStatus(Other, Warning, fmt.Sprintf("%s (will retry)", err.Error()))
  2055  		return err
  2056  	}
  2057  
  2058  	// When releasing identities after allocation due to either failure of
  2059  	// allocation or due a no longer used identity we want to operation to
  2060  	// continue even if the parent has given up. Enforce a timeout of two
  2061  	// minutes to avoid blocking forever but give plenty of time to release
  2062  	// the identity.
  2063  	releaseCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
  2064  	defer cancel()
  2065  
  2066  	releaseNewlyAllocatedIdentity := func() {
  2067  		_, err := cache.Release(releaseCtx, e.owner, identity)
  2068  		if err != nil {
  2069  			// non fatal error as keys will expire after lease expires but log it
  2070  			elog.WithFields(logrus.Fields{logfields.Identity: identity.ID}).
  2071  				WithError(err).Warn("Unable to release newly allocated identity again")
  2072  		}
  2073  	}
  2074  
  2075  	if err := e.LockAlive(); err != nil {
  2076  		releaseNewlyAllocatedIdentity()
  2077  		return err
  2078  	}
  2079  
  2080  	// Since we unlocked the endpoint and re-locked, the label update may already be obsolete
  2081  	if e.identityResolutionIsObsolete(myChangeRev) {
  2082  		e.Unlock()
  2083  
  2084  		releaseNewlyAllocatedIdentity()
  2085  
  2086  		return nil
  2087  	}
  2088  
  2089  	// If endpoint has an old identity, defer release of it to the end of
  2090  	// the function after the endpoint structured has been unlocked again
  2091  	oldIdentity := e.SecurityIdentity
  2092  	if oldIdentity != nil {
  2093  		// The identity of the endpoint is changing, delay the use of
  2094  		// the identity by a grace period to give all other cluster
  2095  		// nodes a chance to adjust their policies first. This requires
  2096  		// to unlock the endpoit and then lock it again.
  2097  		//
  2098  		// If the identity change is from init -> *, don't delay the
  2099  		// use of the identity as we want the init duration to be as
  2100  		// short as possible.
  2101  		if identity.ID != oldIdentity.ID && oldIdentity.ID != identityPkg.ReservedIdentityInit {
  2102  			e.Unlock()
  2103  
  2104  			elog.Debugf("Applying grace period before regeneration due to identity change")
  2105  			time.Sleep(option.Config.IdentityChangeGracePeriod)
  2106  
  2107  			if err := e.LockAlive(); err != nil {
  2108  				releaseNewlyAllocatedIdentity()
  2109  				return err
  2110  			}
  2111  
  2112  			// Since we unlocked the endpoint and re-locked, the label update may already be obsolete
  2113  			if e.identityResolutionIsObsolete(myChangeRev) {
  2114  				e.Unlock()
  2115  				releaseNewlyAllocatedIdentity()
  2116  				return nil
  2117  			}
  2118  		}
  2119  	}
  2120  
  2121  	elog.WithFields(logrus.Fields{logfields.Identity: identity.StringID()}).
  2122  		Debug("Assigned new identity to endpoint")
  2123  
  2124  	e.SetIdentity(identity, false)
  2125  
  2126  	if oldIdentity != nil {
  2127  		_, err := cache.Release(releaseCtx, e.owner, oldIdentity)
  2128  		if err != nil {
  2129  			elog.WithFields(logrus.Fields{logfields.Identity: oldIdentity.ID}).
  2130  				WithError(err).Warn("Unable to release old endpoint identity")
  2131  		}
  2132  	}
  2133  
  2134  	readyToRegenerate := false
  2135  
  2136  	// Regeneration is only triggered once the endpoint ID has been
  2137  	// assigned. This ensures that on the initial creation, the endpoint is
  2138  	// not generated until the endpoint ID has been assigned. If the
  2139  	// identity is resolved before the endpoint ID is assigned, the
  2140  	// regeneration is deferred into endpointmanager.AddEndpoint(). If the
  2141  	// identity is not allocated yet when endpointmanager.AddEndpoint() is
  2142  	// called, the controller calling identityLabelsChanged() will trigger
  2143  	// the regeneration as soon as the identity is known.
  2144  	if e.ID != 0 {
  2145  		readyToRegenerate = e.SetStateLocked(StateWaitingToRegenerate, "Triggering regeneration due to new identity")
  2146  	}
  2147  
  2148  	// Unconditionally force policy recomputation after a new identity has been
  2149  	// assigned.
  2150  	e.ForcePolicyCompute()
  2151  
  2152  	e.Unlock()
  2153  
  2154  	if readyToRegenerate {
  2155  		e.Regenerate(&regeneration.ExternalRegenerationMetadata{Reason: "updated security labels"})
  2156  	}
  2157  
  2158  	return nil
  2159  }
  2160  
  2161  // SetPolicyRevision sets the endpoint's policy revision with the given
  2162  // revision.
  2163  func (e *Endpoint) SetPolicyRevision(rev uint64) {
  2164  	if err := e.LockAlive(); err != nil {
  2165  		return
  2166  	}
  2167  	e.setPolicyRevision(rev)
  2168  	e.Unlock()
  2169  }
  2170  
  2171  // setPolicyRevision sets the endpoint's policy revision with the given
  2172  // revision.
  2173  func (e *Endpoint) setPolicyRevision(rev uint64) {
  2174  	if rev <= e.policyRevision {
  2175  		return
  2176  	}
  2177  
  2178  	now := time.Now()
  2179  	e.policyRevision = rev
  2180  	e.UpdateLogger(map[string]interface{}{
  2181  		logfields.DatapathPolicyRevision: e.policyRevision,
  2182  	})
  2183  	for ps := range e.policyRevisionSignals {
  2184  		select {
  2185  		case <-ps.ctx.Done():
  2186  			close(ps.ch)
  2187  			ps.done(now)
  2188  			delete(e.policyRevisionSignals, ps)
  2189  		default:
  2190  			if rev >= ps.wantedRev {
  2191  				close(ps.ch)
  2192  				ps.done(now)
  2193  				delete(e.policyRevisionSignals, ps)
  2194  			}
  2195  		}
  2196  	}
  2197  }
  2198  
  2199  // cleanPolicySignals closes and removes all policy revision signals.
  2200  func (e *Endpoint) cleanPolicySignals() {
  2201  	now := time.Now()
  2202  	for w := range e.policyRevisionSignals {
  2203  		w.done(now)
  2204  		close(w.ch)
  2205  	}
  2206  	e.policyRevisionSignals = map[*policySignal]bool{}
  2207  }
  2208  
  2209  // policySignal is used to mark when a wanted policy wantedRev is reached
  2210  type policySignal struct {
  2211  	// wantedRev specifies which policy revision the signal wants.
  2212  	wantedRev uint64
  2213  	// ch is the channel that signalizes once the policy revision wanted is reached.
  2214  	ch chan struct{}
  2215  	// ctx is the context for the policy signal request.
  2216  	ctx context.Context
  2217  	// done is a callback to call for this policySignal. It is in addition to the
  2218  	// ch above.
  2219  	done func(ts time.Time)
  2220  }
  2221  
  2222  // WaitForPolicyRevision returns a channel that is closed when one or more of
  2223  // the following conditions have met:
  2224  //  - the endpoint is disconnected state
  2225  //  - the endpoint's policy revision reaches the wanted revision
  2226  // When the done callback is non-nil it will be called just before the channel is closed.
  2227  func (e *Endpoint) WaitForPolicyRevision(ctx context.Context, rev uint64, done func(ts time.Time)) <-chan struct{} {
  2228  	// NOTE: UnconditionalLock is used here because this method handles endpoint in disconnected state on its own
  2229  	e.UnconditionalLock()
  2230  	defer e.Unlock()
  2231  
  2232  	if done == nil {
  2233  		done = func(time.Time) {}
  2234  	}
  2235  
  2236  	ch := make(chan struct{})
  2237  	if e.policyRevision >= rev || e.state == StateDisconnected {
  2238  		close(ch)
  2239  		done(time.Now())
  2240  		return ch
  2241  	}
  2242  	ps := &policySignal{
  2243  		wantedRev: rev,
  2244  		ctx:       ctx,
  2245  		ch:        ch,
  2246  		done:      done,
  2247  	}
  2248  	if e.policyRevisionSignals == nil {
  2249  		e.policyRevisionSignals = map[*policySignal]bool{}
  2250  	}
  2251  	e.policyRevisionSignals[ps] = true
  2252  	return ch
  2253  }
  2254  
  2255  // IPs returns the slice of valid IPs for this endpoint.
  2256  func (e *Endpoint) IPs() []net.IP {
  2257  	ips := []net.IP{}
  2258  	if e.IPv4.IsSet() {
  2259  		ips = append(ips, e.IPv4.IP())
  2260  	}
  2261  	if e.IPv6.IsSet() {
  2262  		ips = append(ips, e.IPv6.IP())
  2263  	}
  2264  	return ips
  2265  }
  2266  
  2267  // InsertEvent is called when the endpoint is inserted into the endpoint
  2268  // manager.
  2269  func (e *Endpoint) InsertEvent() {
  2270  	e.getLogger().Info("New endpoint")
  2271  }
  2272  
  2273  // IsDisconnecting returns true if the endpoint is being disconnected or
  2274  // already disconnected
  2275  //
  2276  // This function must be called after re-acquiring the endpoint mutex to verify
  2277  // that the endpoint has not been removed in the meantime.
  2278  //
  2279  // endpoint.mutex must be held in read mode at least
  2280  func (e *Endpoint) IsDisconnecting() bool {
  2281  	return e.state == StateDisconnected || e.state == StateDisconnecting
  2282  }
  2283  
  2284  // PinDatapathMap retrieves a file descriptor from the map ID from the API call
  2285  // and pins the corresponding map into the BPF file system.
  2286  func (e *Endpoint) PinDatapathMap() error {
  2287  	if e.DatapathMapID == 0 {
  2288  		return nil
  2289  	}
  2290  
  2291  	mapFd, err := bpf.MapFdFromID(e.DatapathMapID)
  2292  	if err != nil {
  2293  		return err
  2294  	}
  2295  	defer unix.Close(mapFd)
  2296  
  2297  	err = bpf.ObjPin(mapFd, e.BPFIpvlanMapPath())
  2298  
  2299  	if err == nil {
  2300  		e.isDatapathMapPinned = true
  2301  	}
  2302  
  2303  	return err
  2304  }
  2305  
  2306  func (e *Endpoint) syncEndpointHeaderFile(reasons []string) {
  2307  	e.BuildMutex.Lock()
  2308  	defer e.BuildMutex.Unlock()
  2309  
  2310  	if err := e.LockAlive(); err != nil {
  2311  		// endpoint was removed in the meanwhile, return
  2312  		return
  2313  	}
  2314  	defer e.Unlock()
  2315  
  2316  	if err := e.writeHeaderfile(e.StateDirectoryPath()); err != nil {
  2317  		e.getLogger().WithFields(logrus.Fields{
  2318  			logfields.Reason: reasons,
  2319  		}).WithError(err).Warning("could not sync header file")
  2320  	}
  2321  }
  2322  
  2323  // SyncEndpointHeaderFile it bumps the current DNS History information for the
  2324  // endpoint in the lxc_config.h file.
  2325  func (e *Endpoint) SyncEndpointHeaderFile() error {
  2326  	if err := e.LockAlive(); err != nil {
  2327  		// endpoint was removed in the meanwhile, return
  2328  		return nil
  2329  	}
  2330  	defer e.Unlock()
  2331  
  2332  	if e.dnsHistoryTrigger == nil {
  2333  		t, err := trigger.NewTrigger(trigger.Parameters{
  2334  			Name:        "sync_endpoint_header_file",
  2335  			MinInterval: 5 * time.Second,
  2336  			TriggerFunc: func(reasons []string) { e.syncEndpointHeaderFile(reasons) },
  2337  		})
  2338  		if err != nil {
  2339  			return fmt.Errorf(
  2340  				"Sync Endpoint header file trigger for endpoint cannot be activated: %s",
  2341  				err)
  2342  		}
  2343  		e.dnsHistoryTrigger = t
  2344  	}
  2345  	e.dnsHistoryTrigger.Trigger()
  2346  	return nil
  2347  }