github.com/fafucoder/cilium@v1.6.11/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 := ®eneration.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(®eneration.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(®eneration.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 }