github.com/noironetworks/cilium-net@v1.6.12/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  // GetIdentityLocked is identical to GetIdentity() but assumes that a.mutex is
   932  // already held. This function is obsolete and should no longer be used.
   933  func (e *Endpoint) GetIdentityLocked() identityPkg.NumericIdentity {
   934  	return e.getIdentity()
   935  }
   936  
   937  // GetIdentity returns the numeric security identity of the endpoint
   938  func (e *Endpoint) GetIdentity() identityPkg.NumericIdentity {
   939  	e.UnconditionalRLock()
   940  	defer e.RUnlock()
   941  
   942  	return e.getIdentity()
   943  }
   944  
   945  func (e *Endpoint) getIdentity() identityPkg.NumericIdentity {
   946  	if e.SecurityIdentity != nil {
   947  		return e.SecurityIdentity.ID
   948  	}
   949  
   950  	return identityPkg.InvalidIdentity
   951  }
   952  
   953  // Allows is only used for unit testing
   954  func (e *Endpoint) Allows(id identityPkg.NumericIdentity) bool {
   955  	e.UnconditionalRLock()
   956  	defer e.RUnlock()
   957  
   958  	keyToLookup := policy.Key{
   959  		Identity:         uint32(id),
   960  		TrafficDirection: trafficdirection.Ingress.Uint8(),
   961  	}
   962  
   963  	_, ok := e.desiredPolicy.PolicyMapState[keyToLookup]
   964  	return ok
   965  }
   966  
   967  // String returns endpoint on a JSON format.
   968  func (e *Endpoint) String() string {
   969  	e.UnconditionalRLock()
   970  	defer e.RUnlock()
   971  	b, err := json.MarshalIndent(e, "", "  ")
   972  	if err != nil {
   973  		return err.Error()
   974  	}
   975  	return string(b)
   976  }
   977  
   978  // optionChanged is a callback used with pkg/option to apply the options to an
   979  // endpoint.  Not used for anything at the moment.
   980  func optionChanged(key string, value option.OptionSetting, data interface{}) {
   981  }
   982  
   983  // applyOptsLocked applies the given options to the endpoint's options and
   984  // returns true if there were any options changed.
   985  func (e *Endpoint) applyOptsLocked(opts option.OptionMap) bool {
   986  	changed := e.Options.ApplyValidated(opts, optionChanged, e) > 0
   987  	_, exists := opts[option.Debug]
   988  	if exists && changed {
   989  		e.UpdateLogger(nil)
   990  	}
   991  	return changed
   992  }
   993  
   994  // ForcePolicyCompute marks the endpoint for forced bpf regeneration.
   995  func (e *Endpoint) ForcePolicyCompute() {
   996  	e.forcePolicyCompute = true
   997  }
   998  
   999  // SetDefaultOpts initializes the endpoint Options and configures the specified
  1000  // options.
  1001  func (e *Endpoint) SetDefaultOpts(opts *option.IntOptions) {
  1002  	if e.Options == nil {
  1003  		e.Options = option.NewIntOptions(&EndpointMutableOptionLibrary)
  1004  	}
  1005  	if e.Options.Library == nil {
  1006  		e.Options.Library = &EndpointMutableOptionLibrary
  1007  	}
  1008  	if e.Options.Opts == nil {
  1009  		e.Options.Opts = option.OptionMap{}
  1010  	}
  1011  
  1012  	if opts != nil {
  1013  		epOptLib := option.GetEndpointMutableOptionLibrary()
  1014  		for k := range epOptLib {
  1015  			e.Options.SetValidated(k, opts.GetValue(k))
  1016  		}
  1017  	}
  1018  	e.UpdateLogger(nil)
  1019  }
  1020  
  1021  // ConntrackLocal determines whether this endpoint is currently using a local
  1022  // table to handle connection tracking (true), or the global table (false).
  1023  func (e *Endpoint) ConntrackLocal() bool {
  1024  	e.UnconditionalRLock()
  1025  	defer e.RUnlock()
  1026  
  1027  	return e.ConntrackLocalLocked()
  1028  }
  1029  
  1030  // ConntrackLocalLocked is the same as ConntrackLocal, but assumes that the
  1031  // endpoint is already locked for reading.
  1032  func (e *Endpoint) ConntrackLocalLocked() bool {
  1033  	if e.SecurityIdentity == nil || e.Options == nil ||
  1034  		!e.Options.IsEnabled(option.ConntrackLocal) {
  1035  		return false
  1036  	}
  1037  
  1038  	return true
  1039  }
  1040  
  1041  // base64 returns the endpoint in a base64 format.
  1042  func (e *Endpoint) base64() (string, error) {
  1043  	var (
  1044  		jsonBytes []byte
  1045  		err       error
  1046  	)
  1047  
  1048  	jsonBytes, err = json.Marshal(e)
  1049  	if err != nil {
  1050  		return "", err
  1051  	}
  1052  	return base64.StdEncoding.EncodeToString(jsonBytes), nil
  1053  }
  1054  
  1055  // parseBase64ToEndpoint parses the endpoint stored in the given base64 string.
  1056  func parseBase64ToEndpoint(str string, ep *Endpoint) error {
  1057  	jsonBytes, err := base64.StdEncoding.DecodeString(str)
  1058  	if err != nil {
  1059  		return err
  1060  	}
  1061  	return json.Unmarshal(jsonBytes, ep)
  1062  }
  1063  
  1064  // FilterEPDir returns a list of directories' names that possible belong to an endpoint.
  1065  func FilterEPDir(dirFiles []os.FileInfo) []string {
  1066  	eptsID := []string{}
  1067  	for _, file := range dirFiles {
  1068  		if file.IsDir() {
  1069  			_, err := strconv.ParseUint(file.Name(), 10, 16)
  1070  			if err == nil || strings.HasSuffix(file.Name(), nextDirectorySuffix) || strings.HasSuffix(file.Name(), nextFailedDirectorySuffix) {
  1071  				eptsID = append(eptsID, file.Name())
  1072  			}
  1073  		}
  1074  	}
  1075  	return eptsID
  1076  }
  1077  
  1078  // ParseEndpoint parses the given strEp which is in the form of:
  1079  // common.CiliumCHeaderPrefix + common.Version + ":" + endpointBase64
  1080  // Note that the parse'd endpoint's identity is only partially restored. The
  1081  // caller must call `SetIdentity()` to make the returned endpoint's identity useful.
  1082  func ParseEndpoint(owner regeneration.Owner, strEp string) (*Endpoint, error) {
  1083  	// TODO: Provide a better mechanism to update from old version once we bump
  1084  	// TODO: cilium version.
  1085  	strEpSlice := strings.Split(strEp, ":")
  1086  	if len(strEpSlice) != 2 {
  1087  		return nil, fmt.Errorf("invalid format %q. Should contain a single ':'", strEp)
  1088  	}
  1089  	ep := Endpoint{
  1090  		owner:      owner,
  1091  		OpLabels:   pkgLabels.NewOpLabels(),
  1092  		DNSHistory: fqdn.NewDNSCacheWithLimit(option.Config.ToFQDNsMinTTL, option.Config.ToFQDNsMaxIPsPerHost),
  1093  	}
  1094  	if err := parseBase64ToEndpoint(strEpSlice[1], &ep); err != nil {
  1095  		return nil, fmt.Errorf("failed to parse base64toendpoint: %s", err)
  1096  	}
  1097  
  1098  	// Validate the options that were parsed
  1099  	ep.SetDefaultOpts(ep.Options)
  1100  
  1101  	// Initialize fields to values which are non-nil that are not serialized.
  1102  	ep.hasBPFProgram = make(chan struct{}, 0)
  1103  	ep.desiredPolicy = policy.NewEndpointPolicy(owner.GetPolicyRepository())
  1104  	ep.realizedPolicy = ep.desiredPolicy
  1105  	ep.controllers = controller.NewManager()
  1106  	ep.regenFailedChan = make(chan struct{}, 1)
  1107  
  1108  	// We need to check for nil in Status, CurrentStatuses and Log, since in
  1109  	// some use cases, status will be not nil and Cilium will eventually
  1110  	// error/panic if CurrentStatus or Log are not initialized correctly.
  1111  	// Reference issue GH-2477
  1112  	if ep.Status == nil || ep.Status.CurrentStatuses == nil || ep.Status.Log == nil {
  1113  		ep.Status = NewEndpointStatus()
  1114  	}
  1115  
  1116  	// Make sure the endpoint has an identity, using the 'init' identity if none.
  1117  	if ep.SecurityIdentity == nil {
  1118  		ep.SecurityIdentity = identityPkg.LookupReservedIdentity(identityPkg.ReservedIdentityInit)
  1119  	}
  1120  	ep.SecurityIdentity.Sanitize()
  1121  
  1122  	ep.UpdateLogger(nil)
  1123  
  1124  	ep.SetStateLocked(StateRestoring, "Endpoint restoring")
  1125  
  1126  	return &ep, nil
  1127  }
  1128  
  1129  func (e *Endpoint) LogStatus(typ StatusType, code StatusCode, msg string) {
  1130  	e.UnconditionalLock()
  1131  	defer e.Unlock()
  1132  	// FIXME GH2323 instead of a mutex we could use a channel to send the status
  1133  	// log message to a single writer?
  1134  	e.logStatusLocked(typ, code, msg)
  1135  }
  1136  
  1137  func (e *Endpoint) LogStatusOK(typ StatusType, msg string) {
  1138  	e.LogStatus(typ, OK, msg)
  1139  }
  1140  
  1141  // LogStatusOKLocked will log an OK message of the given status type with the
  1142  // given msg string.
  1143  // must be called with endpoint.Mutex held
  1144  func (e *Endpoint) LogStatusOKLocked(typ StatusType, msg string) {
  1145  	e.logStatusLocked(typ, OK, msg)
  1146  }
  1147  
  1148  // logStatusLocked logs a status message
  1149  // must be called with endpoint.Mutex held
  1150  func (e *Endpoint) logStatusLocked(typ StatusType, code StatusCode, msg string) {
  1151  	e.Status.indexMU.Lock()
  1152  	defer e.Status.indexMU.Unlock()
  1153  	sts := &statusLogMsg{
  1154  		Status: Status{
  1155  			Code:  code,
  1156  			Msg:   msg,
  1157  			Type:  typ,
  1158  			State: e.state,
  1159  		},
  1160  		Timestamp: time.Now().UTC(),
  1161  	}
  1162  	e.Status.addStatusLog(sts)
  1163  	e.getLogger().WithFields(logrus.Fields{
  1164  		"code":                   sts.Status.Code,
  1165  		"type":                   sts.Status.Type,
  1166  		logfields.EndpointState:  sts.Status.State,
  1167  		logfields.PolicyRevision: e.policyRevision,
  1168  	}).Debug(msg)
  1169  }
  1170  
  1171  type UpdateValidationError struct {
  1172  	msg string
  1173  }
  1174  
  1175  func (e UpdateValidationError) Error() string { return e.msg }
  1176  
  1177  type UpdateCompilationError struct {
  1178  	msg string
  1179  }
  1180  
  1181  func (e UpdateCompilationError) Error() string { return e.msg }
  1182  
  1183  // UpdateStateChangeError is an error that indicates that updating the state
  1184  // of an endpoint was unsuccessful.
  1185  // Implements error interface.
  1186  type UpdateStateChangeError struct {
  1187  	msg string
  1188  }
  1189  
  1190  func (e UpdateStateChangeError) Error() string { return e.msg }
  1191  
  1192  // Update modifies the endpoint options and *always* tries to regenerate the
  1193  // endpoint's program. Returns an error if the provided options are not valid,
  1194  // if there was an issue triggering policy updates for the given endpoint,
  1195  // or if endpoint regeneration was unable to be triggered. Note that the
  1196  // LabelConfiguration in the EndpointConfigurationSpec is *not* consumed here.
  1197  func (e *Endpoint) Update(cfg *models.EndpointConfigurationSpec) error {
  1198  	om, err := EndpointMutableOptionLibrary.ValidateConfigurationMap(cfg.Options)
  1199  	if err != nil {
  1200  		return UpdateValidationError{err.Error()}
  1201  	}
  1202  
  1203  	if err := e.LockAlive(); err != nil {
  1204  		return err
  1205  	}
  1206  
  1207  	e.getLogger().WithField("configuration-options", cfg).Debug("updating endpoint configuration options")
  1208  
  1209  	// CurrentStatus will be not OK when we have an uncleared error in BPF,
  1210  	// policy or Other. We should keep trying to regenerate in the hopes of
  1211  	// succeeding.
  1212  	// Note: This "retry" behaviour is better suited to a controller, and can be
  1213  	// moved there once we have an endpoint regeneration controller.
  1214  	regenCtx := &regeneration.ExternalRegenerationMetadata{
  1215  		Reason: "endpoint was updated via API",
  1216  	}
  1217  
  1218  	// If configuration options are provided, we only regenerate if necessary.
  1219  	// Otherwise always regenerate.
  1220  	if cfg.Options == nil {
  1221  		regenCtx.RegenerationLevel = regeneration.RegenerateWithDatapathRebuild
  1222  		regenCtx.Reason = "endpoint was manually regenerated via API"
  1223  	} else if e.updateAndOverrideEndpointOptions(om) || e.Status.CurrentStatus() != OK {
  1224  		regenCtx.RegenerationLevel = regeneration.RegenerateWithDatapathRewrite
  1225  	}
  1226  
  1227  	if regenCtx.RegenerationLevel > regeneration.RegenerateWithoutDatapath {
  1228  		e.getLogger().Debug("need to regenerate endpoint; checking state before" +
  1229  			" attempting to regenerate")
  1230  
  1231  		// TODO / FIXME: GH-3281: need ways to queue up regenerations per-endpoint.
  1232  
  1233  		// Default timeout for PATCH /endpoint/{id}/config is 60 seconds, so put
  1234  		// timeout in this function a bit below that timeout. If the timeout
  1235  		// for clients in API is below this value, they will get a message containing
  1236  		// "context deadline exceeded".
  1237  		timeout := time.After(EndpointGenerationTimeout)
  1238  
  1239  		// Check for endpoint state every second.
  1240  		ticker := time.NewTicker(1 * time.Second)
  1241  		defer ticker.Stop()
  1242  
  1243  		e.Unlock()
  1244  		for {
  1245  			select {
  1246  			case <-ticker.C:
  1247  				if err := e.LockAlive(); err != nil {
  1248  					return err
  1249  				}
  1250  				// Check endpoint state before attempting configuration update because
  1251  				// configuration updates can only be applied when the endpoint is in
  1252  				// specific states. See GH-3058.
  1253  				stateTransitionSucceeded := e.SetStateLocked(StateWaitingToRegenerate, regenCtx.Reason)
  1254  				if stateTransitionSucceeded {
  1255  					e.Unlock()
  1256  					e.Regenerate(regenCtx)
  1257  					return nil
  1258  				}
  1259  				e.Unlock()
  1260  			case <-timeout:
  1261  				e.getLogger().Warning("timed out waiting for endpoint state to change")
  1262  				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)}
  1263  			}
  1264  		}
  1265  
  1266  	}
  1267  
  1268  	e.Unlock()
  1269  	return nil
  1270  }
  1271  
  1272  // HasLabels returns whether endpoint e contains all labels l. Will return 'false'
  1273  // if any label in l is not in the endpoint's labels.
  1274  func (e *Endpoint) HasLabels(l pkgLabels.Labels) bool {
  1275  	e.UnconditionalRLock()
  1276  	defer e.RUnlock()
  1277  
  1278  	return e.hasLabelsRLocked(l)
  1279  }
  1280  
  1281  // hasLabelsRLocked returns whether endpoint e contains all labels l. Will
  1282  // return 'false' if any label in l is not in the endpoint's labels.
  1283  // e.Mutex must be RLocked
  1284  func (e *Endpoint) hasLabelsRLocked(l pkgLabels.Labels) bool {
  1285  	allEpLabels := e.OpLabels.AllLabels()
  1286  
  1287  	for _, v := range l {
  1288  		found := false
  1289  		for _, j := range allEpLabels {
  1290  			if j.Equals(&v) {
  1291  				found = true
  1292  				break
  1293  			}
  1294  		}
  1295  		if !found {
  1296  			return false
  1297  		}
  1298  	}
  1299  
  1300  	return true
  1301  }
  1302  
  1303  // replaceInformationLabels replaces the information labels of the endpoint.
  1304  // Passing a nil set of labels will not perform any action.
  1305  // Must be called with e.Mutex.Lock().
  1306  func (e *Endpoint) replaceInformationLabels(l pkgLabels.Labels) {
  1307  	if l == nil {
  1308  		return
  1309  	}
  1310  	e.OpLabels.ReplaceInformationLabels(l, e.getLogger())
  1311  }
  1312  
  1313  // replaceIdentityLabels replaces the identity labels of the endpoint. If a net
  1314  // changed occurred, the identityRevision is bumped and returned, otherwise 0 is
  1315  // returned.
  1316  // Passing a nil set of labels will not perform any action and will return the
  1317  // current endpoint's identityRevision.
  1318  // Must be called with e.Mutex.Lock().
  1319  func (e *Endpoint) replaceIdentityLabels(l pkgLabels.Labels) int {
  1320  	if l == nil {
  1321  		return e.identityRevision
  1322  	}
  1323  
  1324  	changed := e.OpLabels.ReplaceIdentityLabels(l, e.getLogger())
  1325  	rev := 0
  1326  	if changed {
  1327  		e.identityRevision++
  1328  		rev = e.identityRevision
  1329  	}
  1330  
  1331  	return rev
  1332  }
  1333  
  1334  // DeleteConfig is the endpoint deletion configuration
  1335  type DeleteConfig struct {
  1336  	NoIPRelease       bool
  1337  	NoIdentityRelease bool
  1338  }
  1339  
  1340  // LeaveLocked removes the endpoint's directory from the system. Must be called
  1341  // with Endpoint's mutex AND BuildMutex locked.
  1342  //
  1343  // Note: LeaveLocked() is called indirectly from endpoint restore logic for
  1344  // endpoints which failed to be restored. Any cleanup routine of LeaveLocked()
  1345  // which depends on kvstore connectivity must be protected by a flag in
  1346  // DeleteConfig and the restore logic must opt-out of it.
  1347  func (e *Endpoint) LeaveLocked(proxyWaitGroup *completion.WaitGroup, conf DeleteConfig) []error {
  1348  	errors := []error{}
  1349  
  1350  	if !option.Config.DryMode {
  1351  		loader.Unload(e.createEpInfoCache(""))
  1352  	}
  1353  
  1354  	e.owner.RemoveFromEndpointQueue(uint64(e.ID))
  1355  	if e.SecurityIdentity != nil && len(e.realizedRedirects) > 0 {
  1356  		// Passing a new map of nil will purge all redirects
  1357  		finalize, _ := e.removeOldRedirects(nil, proxyWaitGroup)
  1358  		if finalize != nil {
  1359  			finalize()
  1360  		}
  1361  	}
  1362  
  1363  	if e.PolicyMap != nil {
  1364  		if err := e.PolicyMap.Close(); err != nil {
  1365  			errors = append(errors, fmt.Errorf("unable to close policymap %s: %s", e.PolicyMap.String(), err))
  1366  		}
  1367  	}
  1368  
  1369  	if e.bpfConfigMap != nil {
  1370  		if err := e.bpfConfigMap.Close(); err != nil {
  1371  			errors = append(errors, fmt.Errorf("unable to close configmap %s: %s", e.BPFConfigMapPath(), err))
  1372  		}
  1373  	}
  1374  
  1375  	if !conf.NoIdentityRelease && e.SecurityIdentity != nil {
  1376  		identitymanager.Remove(e.SecurityIdentity)
  1377  
  1378  		releaseCtx, cancel := context.WithTimeout(context.Background(), option.Config.KVstoreConnectivityTimeout)
  1379  		defer cancel()
  1380  
  1381  		_, err := cache.Release(releaseCtx, e.owner, e.SecurityIdentity)
  1382  		if err != nil {
  1383  			errors = append(errors, fmt.Errorf("unable to release identity: %s", err))
  1384  		}
  1385  		e.owner.RemoveNetworkPolicy(e)
  1386  		e.SecurityIdentity = nil
  1387  	}
  1388  
  1389  	e.removeDirectories()
  1390  	e.controllers.RemoveAll()
  1391  	e.cleanPolicySignals()
  1392  
  1393  	if e.dnsHistoryTrigger != nil {
  1394  		e.dnsHistoryTrigger.Shutdown()
  1395  	}
  1396  
  1397  	if e.ConntrackLocalLocked() {
  1398  		ctmap.CloseLocalMaps(e.ConntrackName())
  1399  	} else if !option.Config.DryMode {
  1400  		e.scrubIPsInConntrackTableLocked()
  1401  	}
  1402  
  1403  	e.SetStateLocked(StateDisconnected, "Endpoint removed")
  1404  
  1405  	endpointPolicyStatus.Remove(e.ID)
  1406  	e.getLogger().Info("Removed endpoint")
  1407  
  1408  	return errors
  1409  }
  1410  
  1411  // RegenerateWait should only be called when endpoint's state has successfully
  1412  // been changed to "waiting-to-regenerate"
  1413  func (e *Endpoint) RegenerateWait(reason string) error {
  1414  	if !<-e.Regenerate(&regeneration.ExternalRegenerationMetadata{Reason: reason}) {
  1415  		return fmt.Errorf("error while regenerating endpoint."+
  1416  			" For more info run: 'cilium endpoint get %d'", e.ID)
  1417  	}
  1418  	return nil
  1419  }
  1420  
  1421  // SetContainerName modifies the endpoint's container name
  1422  func (e *Endpoint) SetContainerName(name string) {
  1423  	e.UnconditionalLock()
  1424  	e.ContainerName = name
  1425  	e.Unlock()
  1426  }
  1427  
  1428  // GetK8sNamespace returns the name of the pod if the endpoint represents a
  1429  // Kubernetes pod
  1430  func (e *Endpoint) GetK8sNamespace() string {
  1431  	e.UnconditionalRLock()
  1432  	ns := e.K8sNamespace
  1433  	e.RUnlock()
  1434  	return ns
  1435  }
  1436  
  1437  // SetK8sNamespace modifies the endpoint's pod name
  1438  func (e *Endpoint) SetK8sNamespace(name string) {
  1439  	e.UnconditionalLock()
  1440  	e.K8sNamespace = name
  1441  	e.UpdateLogger(map[string]interface{}{
  1442  		logfields.K8sPodName: e.GetK8sNamespaceAndPodNameLocked(),
  1443  	})
  1444  	e.Unlock()
  1445  }
  1446  
  1447  // K8sNamespaceAndPodNameIsSet returns true if the pod name is set
  1448  func (e *Endpoint) K8sNamespaceAndPodNameIsSet() bool {
  1449  	e.UnconditionalLock()
  1450  	podName := e.GetK8sNamespaceAndPodNameLocked()
  1451  	e.Unlock()
  1452  	return podName != "" && podName != "/"
  1453  }
  1454  
  1455  // GetK8sPodName returns the name of the pod if the endpoint represents a
  1456  // Kubernetes pod
  1457  func (e *Endpoint) GetK8sPodName() string {
  1458  	e.UnconditionalRLock()
  1459  	k8sPodName := e.K8sPodName
  1460  	e.RUnlock()
  1461  
  1462  	return k8sPodName
  1463  }
  1464  
  1465  // HumanStringLocked returns the endpoint's most human readable identifier as string
  1466  func (e *Endpoint) HumanStringLocked() string {
  1467  	if pod := e.GetK8sNamespaceAndPodNameLocked(); pod != "" {
  1468  		return pod
  1469  	}
  1470  
  1471  	return e.StringID()
  1472  }
  1473  
  1474  // GetK8sNamespaceAndPodNameLocked returns the namespace and pod name.  This
  1475  // function requires e.Mutex to be held.
  1476  func (e *Endpoint) GetK8sNamespaceAndPodNameLocked() string {
  1477  	return e.K8sNamespace + "/" + e.K8sPodName
  1478  }
  1479  
  1480  // SetK8sPodName modifies the endpoint's pod name
  1481  func (e *Endpoint) SetK8sPodName(name string) {
  1482  	e.UnconditionalLock()
  1483  	e.K8sPodName = name
  1484  	e.UpdateLogger(map[string]interface{}{
  1485  		logfields.K8sPodName: e.GetK8sNamespaceAndPodNameLocked(),
  1486  	})
  1487  	e.Unlock()
  1488  }
  1489  
  1490  // SetContainerID modifies the endpoint's container ID
  1491  func (e *Endpoint) SetContainerID(id string) {
  1492  	e.UnconditionalLock()
  1493  	e.ContainerID = id
  1494  	e.UpdateLogger(map[string]interface{}{
  1495  		logfields.ContainerID: e.getShortContainerID(),
  1496  	})
  1497  	e.Unlock()
  1498  }
  1499  
  1500  // GetContainerID returns the endpoint's container ID
  1501  func (e *Endpoint) GetContainerID() string {
  1502  	e.UnconditionalRLock()
  1503  	cID := e.ContainerID
  1504  	e.RUnlock()
  1505  	return cID
  1506  }
  1507  
  1508  // GetShortContainerID returns the endpoint's shortened container ID
  1509  func (e *Endpoint) GetShortContainerID() string {
  1510  	e.UnconditionalRLock()
  1511  	defer e.RUnlock()
  1512  
  1513  	return e.getShortContainerID()
  1514  }
  1515  
  1516  func (e *Endpoint) getShortContainerID() string {
  1517  	if e == nil {
  1518  		return ""
  1519  	}
  1520  
  1521  	caplen := 10
  1522  	if len(e.ContainerID) <= caplen {
  1523  		return e.ContainerID
  1524  	}
  1525  
  1526  	return e.ContainerID[:caplen]
  1527  
  1528  }
  1529  
  1530  // SetDockerEndpointID modifies the endpoint's Docker Endpoint ID
  1531  func (e *Endpoint) SetDockerEndpointID(id string) {
  1532  	e.UnconditionalLock()
  1533  	e.DockerEndpointID = id
  1534  	e.Unlock()
  1535  }
  1536  
  1537  // SetDockerNetworkID modifies the endpoint's Docker Endpoint ID
  1538  func (e *Endpoint) SetDockerNetworkID(id string) {
  1539  	e.UnconditionalLock()
  1540  	e.DockerNetworkID = id
  1541  	e.Unlock()
  1542  }
  1543  
  1544  // GetDockerNetworkID returns the endpoint's Docker Endpoint ID
  1545  func (e *Endpoint) GetDockerNetworkID() string {
  1546  	e.UnconditionalRLock()
  1547  	defer e.RUnlock()
  1548  
  1549  	return e.DockerNetworkID
  1550  }
  1551  
  1552  // SetDatapathMapIDAndPinMapLocked modifies the endpoint's datapath map ID
  1553  func (e *Endpoint) SetDatapathMapIDAndPinMapLocked(id int) error {
  1554  	e.DatapathMapID = id
  1555  	return e.PinDatapathMap()
  1556  }
  1557  
  1558  // IsDatapathMapPinnedLocked returns whether the endpoint's datapath map has been pinned
  1559  func (e *Endpoint) IsDatapathMapPinnedLocked() bool {
  1560  	return e.isDatapathMapPinned
  1561  }
  1562  
  1563  // GetState returns the endpoint's state
  1564  // endpoint.Mutex may only be.RLockAlive()ed
  1565  func (e *Endpoint) GetStateLocked() string {
  1566  	return e.state
  1567  }
  1568  
  1569  // GetState returns the endpoint's state
  1570  // endpoint.Mutex may only be.RLockAlive()ed
  1571  func (e *Endpoint) GetState() string {
  1572  	e.UnconditionalRLock()
  1573  	defer e.RUnlock()
  1574  	return e.GetStateLocked()
  1575  }
  1576  
  1577  // SetState modifies the endpoint's state
  1578  // Returns true only if endpoints state was changed as requested
  1579  func (e *Endpoint) SetState(toState, reason string) bool {
  1580  	e.UnconditionalLock()
  1581  	defer e.Unlock()
  1582  	return e.SetStateLocked(toState, reason)
  1583  }
  1584  
  1585  // SetStateLocked modifies the endpoint's state
  1586  // endpoint.Mutex must be held
  1587  // Returns true only if endpoints state was changed as requested
  1588  func (e *Endpoint) SetStateLocked(toState, reason string) bool {
  1589  	// Validate the state transition.
  1590  	fromState := e.state
  1591  
  1592  	switch fromState { // From state
  1593  	case "": // Special case for capturing initial state transitions like
  1594  		// nil --> StateWaitingForIdentity, StateRestoring
  1595  		switch toState {
  1596  		case StateWaitingForIdentity, StateRestoring:
  1597  			goto OKState
  1598  		}
  1599  	case StateCreating:
  1600  		switch toState {
  1601  		case StateDisconnecting, StateWaitingForIdentity, StateRestoring:
  1602  			goto OKState
  1603  		}
  1604  	case StateWaitingForIdentity:
  1605  		switch toState {
  1606  		case StateReady, StateDisconnecting, StateInvalid:
  1607  			goto OKState
  1608  		}
  1609  	case StateReady:
  1610  		switch toState {
  1611  		case StateWaitingForIdentity, StateDisconnecting, StateWaitingToRegenerate, StateRestoring:
  1612  			goto OKState
  1613  		}
  1614  	case StateDisconnecting:
  1615  		switch toState {
  1616  		case StateDisconnected:
  1617  			goto OKState
  1618  		}
  1619  	case StateDisconnected, StateInvalid:
  1620  		// No valid transitions, as disconnected and invalid are terminal
  1621  		// states for the endpoint.
  1622  	case StateWaitingToRegenerate:
  1623  		switch toState {
  1624  		// Note that transitions to StateWaitingToRegenerate are not allowed,
  1625  		// as callers of this function enqueue regenerations if 'true' is
  1626  		// returned. We don't want to return 'true' for the case of
  1627  		// transitioning to StateWaitingToRegenerate, as this means that a
  1628  		// regeneration is already queued up. Callers would then queue up
  1629  		// another unneeded regeneration, which is undesired.
  1630  		case StateWaitingForIdentity, StateDisconnecting, StateRestoring:
  1631  			goto OKState
  1632  		// Don't log this state transition being invalid below so that we don't
  1633  		// put warnings in the logs for a case which does not result in incorrect
  1634  		// behavior.
  1635  		case StateWaitingToRegenerate:
  1636  			return false
  1637  		}
  1638  	case StateRegenerating:
  1639  		switch toState {
  1640  		// Even while the endpoint is regenerating it is
  1641  		// possible that further changes require a new
  1642  		// build. In this case the endpoint is transitioned
  1643  		// from the regenerating state to
  1644  		// waiting-for-identity or waiting-to-regenerate state.
  1645  		case StateWaitingForIdentity, StateDisconnecting, StateWaitingToRegenerate, StateRestoring:
  1646  			goto OKState
  1647  		}
  1648  	case StateRestoring:
  1649  		switch toState {
  1650  		case StateDisconnecting, StateRestoring:
  1651  			goto OKState
  1652  		}
  1653  	}
  1654  	if toState != fromState {
  1655  		_, fileName, fileLine, _ := runtime.Caller(1)
  1656  		e.getLogger().WithFields(logrus.Fields{
  1657  			logfields.EndpointState + ".from": fromState,
  1658  			logfields.EndpointState + ".to":   toState,
  1659  			"file":                            fileName,
  1660  			"line":                            fileLine,
  1661  		}).Info("Invalid state transition skipped")
  1662  	}
  1663  	e.logStatusLocked(Other, Warning, fmt.Sprintf("Skipped invalid state transition to %s due to: %s", toState, reason))
  1664  	return false
  1665  
  1666  OKState:
  1667  	e.state = toState
  1668  	e.logStatusLocked(Other, OK, reason)
  1669  
  1670  	if fromState != "" {
  1671  		metrics.EndpointStateCount.
  1672  			WithLabelValues(fromState).Dec()
  1673  	}
  1674  
  1675  	// Since StateDisconnected and StateInvalid are final states, after which
  1676  	// the endpoint is gone or doesn't exist, we should not increment metrics
  1677  	// for these states.
  1678  	if toState != "" && toState != StateDisconnected && toState != StateInvalid {
  1679  		metrics.EndpointStateCount.
  1680  			WithLabelValues(toState).Inc()
  1681  	}
  1682  	return true
  1683  }
  1684  
  1685  // BuilderSetStateLocked modifies the endpoint's state
  1686  // endpoint.Mutex must be held
  1687  // endpoint BuildMutex must be held!
  1688  func (e *Endpoint) BuilderSetStateLocked(toState, reason string) bool {
  1689  	// Validate the state transition.
  1690  	fromState := e.state
  1691  	switch fromState { // From state
  1692  	case StateCreating, StateWaitingForIdentity, StateReady, StateDisconnecting, StateDisconnected, StateInvalid:
  1693  		// No valid transitions for the builder
  1694  	case StateWaitingToRegenerate, StateRestoring:
  1695  		switch toState {
  1696  		// Builder transitions the endpoint from
  1697  		// waiting-to-regenerate state to regenerating state
  1698  		// right after acquiring the endpoint lock, and while
  1699  		// endpoint's build mutex is held. All changes to
  1700  		// cilium and endpoint configuration, policy as well
  1701  		// as the existing set of security identities will be
  1702  		// reconsidered after this point, i.e., even if some
  1703  		// of them are changed regeneration need not be queued
  1704  		// if the endpoint is already in waiting-to-regenerate
  1705  		// state.
  1706  		case StateRegenerating:
  1707  			goto OKState
  1708  		// Transition to ReadyState is not supported, but is
  1709  		// attempted when a regeneration is competed, and another
  1710  		// regeneration has been queued in the meanwhile. So this
  1711  		// is expected and will not be logged as an error or warning.
  1712  		case StateReady:
  1713  			return false
  1714  		}
  1715  	case StateRegenerating:
  1716  		switch toState {
  1717  		// While still holding the build mutex, the builder
  1718  		// tries to transition the endpoint to ready
  1719  		// state. But since the endpoint mutex was released
  1720  		// for the duration of the bpf generation, it is
  1721  		// possible that another build request has been
  1722  		// queued. In this case the endpoint has been
  1723  		// transitioned to waiting-to-regenerate state
  1724  		// already, and the transition to ready state is
  1725  		// skipped (but not worth logging for, as this is
  1726  		// normal, see above).
  1727  		case StateReady:
  1728  			goto OKState
  1729  		}
  1730  	}
  1731  	e.logStatusLocked(Other, Warning, fmt.Sprintf("Skipped invalid state transition to %s due to: %s", toState, reason))
  1732  	return false
  1733  
  1734  OKState:
  1735  	e.state = toState
  1736  	e.logStatusLocked(Other, OK, reason)
  1737  
  1738  	if fromState != "" {
  1739  		metrics.EndpointStateCount.
  1740  			WithLabelValues(fromState).Dec()
  1741  	}
  1742  
  1743  	// Since StateDisconnected and StateInvalid are final states, after which
  1744  	// the endpoint is gone or doesn't exist, we should not increment metrics
  1745  	// for these states.
  1746  	if toState != "" && toState != StateDisconnected && toState != StateInvalid {
  1747  		metrics.EndpointStateCount.
  1748  			WithLabelValues(toState).Inc()
  1749  	}
  1750  	return true
  1751  }
  1752  
  1753  // OnProxyPolicyUpdate is a callback used to update the Endpoint's
  1754  // proxyPolicyRevision when the specified revision has been applied in the
  1755  // proxy.
  1756  func (e *Endpoint) OnProxyPolicyUpdate(revision uint64) {
  1757  	// NOTE: UnconditionalLock is used here because this callback has no way of reporting an error
  1758  	e.UnconditionalLock()
  1759  	if revision > e.proxyPolicyRevision {
  1760  		e.proxyPolicyRevision = revision
  1761  	}
  1762  	e.Unlock()
  1763  }
  1764  
  1765  // getProxyStatisticsLocked gets the ProxyStatistics for the flows with the
  1766  // given characteristics, or adds a new one and returns it.
  1767  // Must be called with e.proxyStatisticsMutex held.
  1768  func (e *Endpoint) getProxyStatisticsLocked(key string, l7Protocol string, port uint16, ingress bool) *models.ProxyStatistics {
  1769  	if e.proxyStatistics == nil {
  1770  		e.proxyStatistics = make(map[string]*models.ProxyStatistics)
  1771  	}
  1772  
  1773  	proxyStats, ok := e.proxyStatistics[key]
  1774  	if !ok {
  1775  		var location string
  1776  		if ingress {
  1777  			location = models.ProxyStatisticsLocationIngress
  1778  		} else {
  1779  			location = models.ProxyStatisticsLocationEgress
  1780  		}
  1781  		proxyStats = &models.ProxyStatistics{
  1782  			Location: location,
  1783  			Port:     int64(port),
  1784  			Protocol: l7Protocol,
  1785  			Statistics: &models.RequestResponseStatistics{
  1786  				Requests:  &models.MessageForwardingStatistics{},
  1787  				Responses: &models.MessageForwardingStatistics{},
  1788  			},
  1789  		}
  1790  
  1791  		e.proxyStatistics[key] = proxyStats
  1792  	}
  1793  
  1794  	return proxyStats
  1795  }
  1796  
  1797  // UpdateProxyStatistics updates the Endpoint's proxy  statistics to account
  1798  // for a new observed flow with the given characteristics.
  1799  func (e *Endpoint) UpdateProxyStatistics(l4Protocol string, port uint16, ingress, request bool, verdict accesslog.FlowVerdict) {
  1800  	e.proxyStatisticsMutex.Lock()
  1801  	defer e.proxyStatisticsMutex.Unlock()
  1802  
  1803  	key := policy.ProxyID(e.ID, ingress, l4Protocol, port)
  1804  	proxyStats, ok := e.proxyStatistics[key]
  1805  	if !ok {
  1806  		e.getLogger().WithField(logfields.L4PolicyID, key).Warn("Proxy stats not found when updating")
  1807  		return
  1808  	}
  1809  
  1810  	var stats *models.MessageForwardingStatistics
  1811  	if request {
  1812  		stats = proxyStats.Statistics.Requests
  1813  	} else {
  1814  		stats = proxyStats.Statistics.Responses
  1815  	}
  1816  
  1817  	stats.Received++
  1818  	metrics.ProxyReceived.Inc()
  1819  	metrics.ProxyPolicyL7Total.WithLabelValues("received").Inc()
  1820  
  1821  	switch verdict {
  1822  	case accesslog.VerdictForwarded:
  1823  		stats.Forwarded++
  1824  		metrics.ProxyForwarded.Inc()
  1825  		metrics.ProxyPolicyL7Total.WithLabelValues("forwarded").Inc()
  1826  	case accesslog.VerdictDenied:
  1827  		stats.Denied++
  1828  		metrics.ProxyDenied.Inc()
  1829  		metrics.ProxyPolicyL7Total.WithLabelValues("denied").Inc()
  1830  	case accesslog.VerdictError:
  1831  		stats.Error++
  1832  		metrics.ProxyParseErrors.Inc()
  1833  		metrics.ProxyPolicyL7Total.WithLabelValues("parse_errors").Inc()
  1834  	}
  1835  }
  1836  
  1837  // APICanModify determines whether API requests from a user are allowed to
  1838  // modify this endpoint.
  1839  func APICanModify(e *Endpoint) error {
  1840  	if e.IsInit() {
  1841  		return nil
  1842  	}
  1843  	if e.OpLabels.OrchestrationIdentity.IsReserved() {
  1844  		return fmt.Errorf("endpoint may not be associated reserved labels")
  1845  	}
  1846  	return nil
  1847  }
  1848  
  1849  func (e *Endpoint) getIDandLabels() string {
  1850  	e.UnconditionalRLock()
  1851  	defer e.RUnlock()
  1852  
  1853  	labels := ""
  1854  	if e.SecurityIdentity != nil {
  1855  		labels = e.SecurityIdentity.Labels.String()
  1856  	}
  1857  
  1858  	return fmt.Sprintf("%d (%s)", e.ID, labels)
  1859  }
  1860  
  1861  // MetadataResolverCB provides an implementation for resolving the endpoint
  1862  // metadata for an endpoint such as the associated labels and annotations.
  1863  type MetadataResolverCB func(*Endpoint) (identityLabels labels.Labels, infoLabels labels.Labels, err error)
  1864  
  1865  // RunMetadataResolver starts a controller associated with the received
  1866  // endpoint which will periodically attempt to resolve the metadata for the
  1867  // endpoint and update the endpoint with the related. It stops resolving after
  1868  // either the first successful metadata resolution or when the endpoint is
  1869  // removed.
  1870  //
  1871  // This assumes that after the initial successful resolution, other mechanisms
  1872  // will handle updates (such as pkg/k8s/watchers informers).
  1873  func (e *Endpoint) RunMetadataResolver(resolveMetadata MetadataResolverCB) {
  1874  	done := make(chan struct{})
  1875  	controllerName := fmt.Sprintf("resolve-labels-%s/%s", e.GetK8sNamespace(), e.GetK8sPodName())
  1876  	go func() {
  1877  		<-done
  1878  		e.controllers.RemoveController(controllerName)
  1879  	}()
  1880  
  1881  	e.controllers.UpdateController(controllerName,
  1882  		controller.ControllerParams{
  1883  			DoFunc: func(ctx context.Context) error {
  1884  				identityLabels, info, err := resolveMetadata(e)
  1885  				if err != nil {
  1886  					e.Logger(controllerName).WithError(err).Warning("Unable to fetch kubernetes labels")
  1887  					return err
  1888  				}
  1889  				e.UpdateLabels(ctx, identityLabels, info, true)
  1890  				close(done)
  1891  				return nil
  1892  			},
  1893  			RunInterval: 30 * time.Second,
  1894  		},
  1895  	)
  1896  }
  1897  
  1898  // ModifyIdentityLabels changes the custom and orchestration identity labels of an endpoint.
  1899  // Labels can be added or deleted. If a label change is performed, the
  1900  // endpoint will receive a new identity and will be regenerated. Both of these
  1901  // operations will happen in the background.
  1902  func (e *Endpoint) ModifyIdentityLabels(addLabels, delLabels pkgLabels.Labels) error {
  1903  	if err := e.LockAlive(); err != nil {
  1904  		return err
  1905  	}
  1906  
  1907  	changed, err := e.OpLabels.ModifyIdentityLabels(addLabels, delLabels)
  1908  	if err != nil {
  1909  		e.Unlock()
  1910  		return err
  1911  	}
  1912  
  1913  	var rev int
  1914  	if changed {
  1915  		// Mark with StateWaitingForIdentity, it will be set to
  1916  		// StateWaitingToRegenerate after the identity resolution has been
  1917  		// completed
  1918  		e.SetStateLocked(StateWaitingForIdentity, "Triggering identity resolution due to updated identity labels")
  1919  
  1920  		e.identityRevision++
  1921  		rev = e.identityRevision
  1922  	}
  1923  	e.Unlock()
  1924  
  1925  	if changed {
  1926  		e.runIdentityResolver(context.Background(), rev, false)
  1927  	}
  1928  	return nil
  1929  }
  1930  
  1931  // IsInit returns true if the endpoint still hasn't received identity labels,
  1932  // i.e. has the special identity with label reserved:init.
  1933  func (e *Endpoint) IsInit() bool {
  1934  	init, found := e.OpLabels.GetIdentityLabel(pkgLabels.IDNameInit)
  1935  	return found && init.Source == pkgLabels.LabelSourceReserved
  1936  }
  1937  
  1938  // UpdateLabels is called to update the labels of an endpoint. Calls to this
  1939  // function do not necessarily mean that the labels actually changed. The
  1940  // container runtime layer will periodically synchronize labels.
  1941  //
  1942  // If a net label changed was performed, the endpoint will receive a new
  1943  // identity and will be regenerated. Both of these operations will happen in
  1944  // the background.
  1945  func (e *Endpoint) UpdateLabels(ctx context.Context, identityLabels, infoLabels pkgLabels.Labels, blocking bool) {
  1946  	log.WithFields(logrus.Fields{
  1947  		logfields.ContainerID:    e.GetShortContainerID(),
  1948  		logfields.EndpointID:     e.StringID(),
  1949  		logfields.IdentityLabels: identityLabels.String(),
  1950  		logfields.InfoLabels:     infoLabels.String(),
  1951  	}).Debug("Refreshing labels of endpoint")
  1952  
  1953  	if err := e.LockAlive(); err != nil {
  1954  		e.LogDisconnectedMutexAction(err, "when trying to refresh endpoint labels")
  1955  		return
  1956  	}
  1957  
  1958  	e.replaceInformationLabels(infoLabels)
  1959  	// replace identity labels and update the identity if labels have changed
  1960  	rev := e.replaceIdentityLabels(identityLabels)
  1961  	e.Unlock()
  1962  	if rev != 0 {
  1963  		e.runIdentityResolver(ctx, rev, blocking)
  1964  	}
  1965  }
  1966  
  1967  func (e *Endpoint) identityResolutionIsObsolete(myChangeRev int) bool {
  1968  	// Check if the endpoint has since received a new identity revision, if
  1969  	// so, abort as a new resolution routine will have been started.
  1970  	if myChangeRev != e.identityRevision {
  1971  		return true
  1972  	}
  1973  
  1974  	return false
  1975  }
  1976  
  1977  // runIdentityResolver resolves the numeric identity for the set of labels that
  1978  // are currently configured on the endpoint.
  1979  //
  1980  // Must be called with e.Mutex NOT held.
  1981  func (e *Endpoint) runIdentityResolver(ctx context.Context, myChangeRev int, blocking bool) {
  1982  	if err := e.RLockAlive(); err != nil {
  1983  		// If a labels update and an endpoint delete API request arrive
  1984  		// in quick succession, this could occur; in that case, there's
  1985  		// no point updating the controller.
  1986  		e.getLogger().WithError(err).Info("Cannot run labels resolver")
  1987  		return
  1988  	}
  1989  	newLabels := e.OpLabels.IdentityLabels()
  1990  	e.RUnlock()
  1991  	scopedLog := e.getLogger().WithField(logfields.IdentityLabels, newLabels)
  1992  
  1993  	// If we are certain we can resolve the identity without accessing the KV
  1994  	// store, do it first synchronously right now. This can reduce the number
  1995  	// of regenerations for the endpoint during its initialization.
  1996  	if blocking || cache.IdentityAllocationIsLocal(newLabels) {
  1997  		scopedLog.Info("Resolving identity labels (blocking)")
  1998  
  1999  		err := e.identityLabelsChanged(ctx, myChangeRev)
  2000  		switch err {
  2001  		case ErrNotAlive:
  2002  			scopedLog.Debug("not changing endpoint identity because endpoint is in process of being removed")
  2003  			return
  2004  		default:
  2005  			if err != nil {
  2006  				scopedLog.WithError(err).Warn("Error changing endpoint identity")
  2007  			}
  2008  		}
  2009  	} else {
  2010  		scopedLog.Info("Resolving identity labels (non-blocking)")
  2011  	}
  2012  
  2013  	ctrlName := fmt.Sprintf("resolve-identity-%d", e.ID)
  2014  	e.controllers.UpdateController(ctrlName,
  2015  		controller.ControllerParams{
  2016  			DoFunc: func(ctx context.Context) error {
  2017  				err := e.identityLabelsChanged(ctx, myChangeRev)
  2018  				switch err {
  2019  				case ErrNotAlive:
  2020  					e.getLogger().Debug("not changing endpoint identity because endpoint is in process of being removed")
  2021  					return controller.NewExitReason("Endpoint disappeared")
  2022  				default:
  2023  					return err
  2024  				}
  2025  			},
  2026  			RunInterval: 5 * time.Minute,
  2027  		},
  2028  	)
  2029  }
  2030  
  2031  func (e *Endpoint) identityLabelsChanged(ctx context.Context, myChangeRev int) error {
  2032  	if err := e.RLockAlive(); err != nil {
  2033  		return ErrNotAlive
  2034  	}
  2035  	newLabels := e.OpLabels.IdentityLabels()
  2036  	elog := e.getLogger().WithFields(logrus.Fields{
  2037  		logfields.EndpointID:     e.ID,
  2038  		logfields.IdentityLabels: newLabels,
  2039  	})
  2040  
  2041  	// Since we unlocked the endpoint and re-locked, the label update may already be obsolete
  2042  	if e.identityResolutionIsObsolete(myChangeRev) {
  2043  		e.RUnlock()
  2044  		elog.Debug("Endpoint identity has changed, aborting resolution routine in favour of new one")
  2045  		return nil
  2046  	}
  2047  
  2048  	if e.SecurityIdentity != nil && e.SecurityIdentity.Labels.Equals(newLabels) {
  2049  		// Sets endpoint state to ready if was waiting for identity
  2050  		if e.GetStateLocked() == StateWaitingForIdentity {
  2051  			e.SetStateLocked(StateReady, "Set identity for this endpoint")
  2052  		}
  2053  		e.RUnlock()
  2054  		elog.Debug("Endpoint labels unchanged, skipping resolution of identity")
  2055  		return nil
  2056  	}
  2057  
  2058  	// Unlock the endpoint mutex for the possibly long lasting kvstore operation
  2059  	e.RUnlock()
  2060  	elog.Debug("Resolving identity for labels")
  2061  
  2062  	allocateCtx, cancel := context.WithTimeout(ctx, option.Config.KVstoreConnectivityTimeout)
  2063  	defer cancel()
  2064  
  2065  	identity, _, err := cache.AllocateIdentity(allocateCtx, e.owner, newLabels)
  2066  	if err != nil {
  2067  		err = fmt.Errorf("unable to resolve identity: %s", err)
  2068  		e.LogStatus(Other, Warning, fmt.Sprintf("%s (will retry)", err.Error()))
  2069  		return err
  2070  	}
  2071  
  2072  	// When releasing identities after allocation due to either failure of
  2073  	// allocation or due a no longer used identity we want to operation to
  2074  	// continue even if the parent has given up. Enforce a timeout of two
  2075  	// minutes to avoid blocking forever but give plenty of time to release
  2076  	// the identity.
  2077  	releaseCtx, cancel := context.WithTimeout(ctx, option.Config.KVstoreConnectivityTimeout)
  2078  	defer cancel()
  2079  
  2080  	releaseNewlyAllocatedIdentity := func() {
  2081  		_, err := cache.Release(releaseCtx, e.owner, identity)
  2082  		if err != nil {
  2083  			// non fatal error as keys will expire after lease expires but log it
  2084  			elog.WithFields(logrus.Fields{logfields.Identity: identity.ID}).
  2085  				WithError(err).Warn("Unable to release newly allocated identity again")
  2086  		}
  2087  	}
  2088  
  2089  	if err := e.LockAlive(); err != nil {
  2090  		releaseNewlyAllocatedIdentity()
  2091  		return err
  2092  	}
  2093  
  2094  	// Since we unlocked the endpoint and re-locked, the label update may already be obsolete
  2095  	if e.identityResolutionIsObsolete(myChangeRev) {
  2096  		e.Unlock()
  2097  
  2098  		releaseNewlyAllocatedIdentity()
  2099  
  2100  		return nil
  2101  	}
  2102  
  2103  	// If endpoint has an old identity, defer release of it to the end of
  2104  	// the function after the endpoint structured has been unlocked again
  2105  	oldIdentity := e.SecurityIdentity
  2106  	if oldIdentity != nil {
  2107  		// The identity of the endpoint is changing, delay the use of
  2108  		// the identity by a grace period to give all other cluster
  2109  		// nodes a chance to adjust their policies first. This requires
  2110  		// to unlock the endpoit and then lock it again.
  2111  		//
  2112  		// If the identity change is from init -> *, don't delay the
  2113  		// use of the identity as we want the init duration to be as
  2114  		// short as possible.
  2115  		if identity.ID != oldIdentity.ID && oldIdentity.ID != identityPkg.ReservedIdentityInit {
  2116  			e.Unlock()
  2117  
  2118  			elog.Debugf("Applying grace period before regeneration due to identity change")
  2119  			time.Sleep(option.Config.IdentityChangeGracePeriod)
  2120  
  2121  			if err := e.LockAlive(); err != nil {
  2122  				releaseNewlyAllocatedIdentity()
  2123  				return err
  2124  			}
  2125  
  2126  			// Since we unlocked the endpoint and re-locked, the label update may already be obsolete
  2127  			if e.identityResolutionIsObsolete(myChangeRev) {
  2128  				e.Unlock()
  2129  				releaseNewlyAllocatedIdentity()
  2130  				return nil
  2131  			}
  2132  		}
  2133  	}
  2134  
  2135  	elog.WithFields(logrus.Fields{logfields.Identity: identity.StringID()}).
  2136  		Debug("Assigned new identity to endpoint")
  2137  
  2138  	e.SetIdentity(identity, false)
  2139  
  2140  	if oldIdentity != nil {
  2141  		_, err := cache.Release(releaseCtx, e.owner, oldIdentity)
  2142  		if err != nil {
  2143  			elog.WithFields(logrus.Fields{logfields.Identity: oldIdentity.ID}).
  2144  				WithError(err).Warn("Unable to release old endpoint identity")
  2145  		}
  2146  	}
  2147  
  2148  	readyToRegenerate := false
  2149  
  2150  	// Regeneration is only triggered once the endpoint ID has been
  2151  	// assigned. This ensures that on the initial creation, the endpoint is
  2152  	// not generated until the endpoint ID has been assigned. If the
  2153  	// identity is resolved before the endpoint ID is assigned, the
  2154  	// regeneration is deferred into endpointmanager.AddEndpoint(). If the
  2155  	// identity is not allocated yet when endpointmanager.AddEndpoint() is
  2156  	// called, the controller calling identityLabelsChanged() will trigger
  2157  	// the regeneration as soon as the identity is known.
  2158  	if e.ID != 0 {
  2159  		readyToRegenerate = e.SetStateLocked(StateWaitingToRegenerate, "Triggering regeneration due to new identity")
  2160  	}
  2161  
  2162  	// Unconditionally force policy recomputation after a new identity has been
  2163  	// assigned.
  2164  	e.ForcePolicyCompute()
  2165  
  2166  	e.Unlock()
  2167  
  2168  	if readyToRegenerate {
  2169  		e.Regenerate(&regeneration.ExternalRegenerationMetadata{Reason: "updated security labels"})
  2170  	}
  2171  
  2172  	return nil
  2173  }
  2174  
  2175  // SetPolicyRevision sets the endpoint's policy revision with the given
  2176  // revision.
  2177  func (e *Endpoint) SetPolicyRevision(rev uint64) {
  2178  	if err := e.LockAlive(); err != nil {
  2179  		return
  2180  	}
  2181  	e.setPolicyRevision(rev)
  2182  	e.Unlock()
  2183  }
  2184  
  2185  // setPolicyRevision sets the endpoint's policy revision with the given
  2186  // revision.
  2187  func (e *Endpoint) setPolicyRevision(rev uint64) {
  2188  	if rev <= e.policyRevision {
  2189  		return
  2190  	}
  2191  
  2192  	now := time.Now()
  2193  	e.policyRevision = rev
  2194  	e.UpdateLogger(map[string]interface{}{
  2195  		logfields.DatapathPolicyRevision: e.policyRevision,
  2196  	})
  2197  	for ps := range e.policyRevisionSignals {
  2198  		select {
  2199  		case <-ps.ctx.Done():
  2200  			close(ps.ch)
  2201  			ps.done(now)
  2202  			delete(e.policyRevisionSignals, ps)
  2203  		default:
  2204  			if rev >= ps.wantedRev {
  2205  				close(ps.ch)
  2206  				ps.done(now)
  2207  				delete(e.policyRevisionSignals, ps)
  2208  			}
  2209  		}
  2210  	}
  2211  }
  2212  
  2213  // cleanPolicySignals closes and removes all policy revision signals.
  2214  func (e *Endpoint) cleanPolicySignals() {
  2215  	now := time.Now()
  2216  	for w := range e.policyRevisionSignals {
  2217  		w.done(now)
  2218  		close(w.ch)
  2219  	}
  2220  	e.policyRevisionSignals = map[*policySignal]bool{}
  2221  }
  2222  
  2223  // policySignal is used to mark when a wanted policy wantedRev is reached
  2224  type policySignal struct {
  2225  	// wantedRev specifies which policy revision the signal wants.
  2226  	wantedRev uint64
  2227  	// ch is the channel that signalizes once the policy revision wanted is reached.
  2228  	ch chan struct{}
  2229  	// ctx is the context for the policy signal request.
  2230  	ctx context.Context
  2231  	// done is a callback to call for this policySignal. It is in addition to the
  2232  	// ch above.
  2233  	done func(ts time.Time)
  2234  }
  2235  
  2236  // WaitForPolicyRevision returns a channel that is closed when one or more of
  2237  // the following conditions have met:
  2238  //  - the endpoint is disconnected state
  2239  //  - the endpoint's policy revision reaches the wanted revision
  2240  // When the done callback is non-nil it will be called just before the channel is closed.
  2241  func (e *Endpoint) WaitForPolicyRevision(ctx context.Context, rev uint64, done func(ts time.Time)) <-chan struct{} {
  2242  	// NOTE: UnconditionalLock is used here because this method handles endpoint in disconnected state on its own
  2243  	e.UnconditionalLock()
  2244  	defer e.Unlock()
  2245  
  2246  	if done == nil {
  2247  		done = func(time.Time) {}
  2248  	}
  2249  
  2250  	ch := make(chan struct{})
  2251  	if e.policyRevision >= rev || e.state == StateDisconnected {
  2252  		close(ch)
  2253  		done(time.Now())
  2254  		return ch
  2255  	}
  2256  	ps := &policySignal{
  2257  		wantedRev: rev,
  2258  		ctx:       ctx,
  2259  		ch:        ch,
  2260  		done:      done,
  2261  	}
  2262  	if e.policyRevisionSignals == nil {
  2263  		e.policyRevisionSignals = map[*policySignal]bool{}
  2264  	}
  2265  	e.policyRevisionSignals[ps] = true
  2266  	return ch
  2267  }
  2268  
  2269  // IPs returns the slice of valid IPs for this endpoint.
  2270  func (e *Endpoint) IPs() []net.IP {
  2271  	ips := []net.IP{}
  2272  	if e.IPv4.IsSet() {
  2273  		ips = append(ips, e.IPv4.IP())
  2274  	}
  2275  	if e.IPv6.IsSet() {
  2276  		ips = append(ips, e.IPv6.IP())
  2277  	}
  2278  	return ips
  2279  }
  2280  
  2281  // InsertEvent is called when the endpoint is inserted into the endpoint
  2282  // manager.
  2283  func (e *Endpoint) InsertEvent() {
  2284  	e.getLogger().Info("New endpoint")
  2285  }
  2286  
  2287  // IsDisconnecting returns true if the endpoint is being disconnected or
  2288  // already disconnected
  2289  //
  2290  // This function must be called after re-acquiring the endpoint mutex to verify
  2291  // that the endpoint has not been removed in the meantime.
  2292  //
  2293  // endpoint.mutex must be held in read mode at least
  2294  func (e *Endpoint) IsDisconnecting() bool {
  2295  	return e.state == StateDisconnected || e.state == StateDisconnecting
  2296  }
  2297  
  2298  // PinDatapathMap retrieves a file descriptor from the map ID from the API call
  2299  // and pins the corresponding map into the BPF file system.
  2300  func (e *Endpoint) PinDatapathMap() error {
  2301  	if e.DatapathMapID == 0 {
  2302  		return nil
  2303  	}
  2304  
  2305  	mapFd, err := bpf.MapFdFromID(e.DatapathMapID)
  2306  	if err != nil {
  2307  		return err
  2308  	}
  2309  	defer unix.Close(mapFd)
  2310  
  2311  	err = bpf.ObjPin(mapFd, e.BPFIpvlanMapPath())
  2312  
  2313  	if err == nil {
  2314  		e.isDatapathMapPinned = true
  2315  	}
  2316  
  2317  	return err
  2318  }
  2319  
  2320  func (e *Endpoint) syncEndpointHeaderFile(reasons []string) {
  2321  	e.BuildMutex.Lock()
  2322  	defer e.BuildMutex.Unlock()
  2323  
  2324  	if err := e.LockAlive(); err != nil {
  2325  		// endpoint was removed in the meanwhile, return
  2326  		return
  2327  	}
  2328  	defer e.Unlock()
  2329  
  2330  	if err := e.writeHeaderfile(e.StateDirectoryPath()); err != nil {
  2331  		e.getLogger().WithFields(logrus.Fields{
  2332  			logfields.Reason: reasons,
  2333  		}).WithError(err).Warning("could not sync header file")
  2334  	}
  2335  }
  2336  
  2337  // SyncEndpointHeaderFile it bumps the current DNS History information for the
  2338  // endpoint in the lxc_config.h file.
  2339  func (e *Endpoint) SyncEndpointHeaderFile() error {
  2340  	if err := e.LockAlive(); err != nil {
  2341  		// endpoint was removed in the meanwhile, return
  2342  		return nil
  2343  	}
  2344  	defer e.Unlock()
  2345  
  2346  	if e.dnsHistoryTrigger == nil {
  2347  		t, err := trigger.NewTrigger(trigger.Parameters{
  2348  			Name:        "sync_endpoint_header_file",
  2349  			MinInterval: 5 * time.Second,
  2350  			TriggerFunc: func(reasons []string) { e.syncEndpointHeaderFile(reasons) },
  2351  		})
  2352  		if err != nil {
  2353  			return fmt.Errorf(
  2354  				"Sync Endpoint header file trigger for endpoint cannot be activated: %s",
  2355  				err)
  2356  		}
  2357  		e.dnsHistoryTrigger = t
  2358  	}
  2359  	e.dnsHistoryTrigger.Trigger()
  2360  	return nil
  2361  }