github.com/fafucoder/cilium@v1.6.11/pkg/endpoint/endpoint_status.go (about) 1 // Copyright 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 "sort" 19 "strings" 20 "time" 21 22 "github.com/cilium/cilium/api/v1/models" 23 "github.com/cilium/cilium/pkg/identity" 24 identitycache "github.com/cilium/cilium/pkg/identity/cache" 25 cilium_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 26 "github.com/cilium/cilium/pkg/labels" 27 "github.com/cilium/cilium/pkg/node" 28 "github.com/cilium/cilium/pkg/option" 29 "github.com/cilium/cilium/pkg/policy" 30 "github.com/cilium/cilium/pkg/policy/trafficdirection" 31 ) 32 33 func getEndpointStatusControllers(status *models.EndpointStatus) (controllers cilium_v2.ControllerList) { 34 for _, c := range status.Controllers { 35 if c.Status == nil { 36 continue 37 } 38 39 if c.Status.ConsecutiveFailureCount > 0 { 40 s := cilium_v2.ControllerStatus{ 41 Configuration: c.Configuration, 42 Name: c.Name, 43 UUID: string(c.UUID), 44 Status: cilium_v2.ControllerStatusStatus{ 45 ConsecutiveFailureCount: c.Status.ConsecutiveFailureCount, 46 FailureCount: c.Status.FailureCount, 47 LastFailureMsg: c.Status.LastFailureMsg, 48 LastFailureTimestamp: c.Status.LastFailureTimestamp.String(), 49 LastSuccessTimestamp: c.Status.LastSuccessTimestamp.String(), 50 SuccessCount: c.Status.SuccessCount, 51 }, 52 } 53 if controllers == nil { 54 controllers = cilium_v2.ControllerList{s} 55 } else { 56 controllers = append(controllers, s) 57 } 58 } 59 } 60 61 if controllers != nil { 62 controllers.Sort() 63 } 64 65 return 66 } 67 68 func (e *Endpoint) getEndpointStatusLog() (log []*models.EndpointStatusChange) { 69 added := 0 70 71 if s := e.Status; s != nil { 72 s.indexMU.RLock() 73 defer s.indexMU.RUnlock() 74 75 for i := s.lastIndex(); ; i-- { 76 if i < 0 { 77 i = maxLogs - 1 78 } 79 if i < len(s.Log) && s.Log[i] != nil { 80 l := &models.EndpointStatusChange{ 81 Timestamp: s.Log[i].Timestamp.Format(time.RFC3339), 82 Code: s.Log[i].Status.Code.String(), 83 Message: s.Log[i].Status.Msg, 84 State: models.EndpointState(s.Log[i].Status.State), 85 } 86 87 if strings.ToLower(l.Code) != models.EndpointStatusChangeCodeOk { 88 if log == nil { 89 log = []*models.EndpointStatusChange{l} 90 } else { 91 log = append(log, l) 92 } 93 94 // Limit the number of endpoint log 95 // entries to keep the size of the 96 // EndpointStatus low. 97 added++ 98 if added >= cilium_v2.EndpointStatusLogEntries { 99 break 100 } 101 } 102 } 103 if i == s.Index { 104 break 105 } 106 } 107 } 108 return 109 } 110 111 func getEndpointIdentity(status *models.EndpointStatus) (identity *cilium_v2.EndpointIdentity) { 112 if status.Identity != nil { 113 identity = &cilium_v2.EndpointIdentity{ 114 ID: status.Identity.ID, 115 } 116 117 identity.Labels = make([]string, len(status.Identity.Labels)) 118 copy(identity.Labels, status.Identity.Labels) 119 sort.Strings(identity.Labels) 120 } 121 return 122 } 123 124 func getEndpointNetworking(status *models.EndpointStatus) (networking *cilium_v2.EndpointNetworking) { 125 if status.Networking != nil { 126 networking = &cilium_v2.EndpointNetworking{ 127 Addressing: make(cilium_v2.AddressPairList, len(status.Networking.Addressing)), 128 } 129 130 if option.Config.EnableIPv4 { 131 networking.NodeIP = node.GetExternalIPv4().String() 132 } else { 133 networking.NodeIP = node.GetIPv6().String() 134 } 135 136 i := 0 137 for _, pair := range status.Networking.Addressing { 138 networking.Addressing[i] = &cilium_v2.AddressPair{ 139 IPV4: pair.IPV4, 140 IPV6: pair.IPV6, 141 } 142 i++ 143 } 144 145 networking.Addressing.Sort() 146 } 147 return 148 } 149 150 // updateLabels inserts the labels correnspoding to the specified identity into 151 // the AllowedIdentityTuple. 152 func updateLabels(allowedIdentityTuple *cilium_v2.AllowedIdentityTuple, secID identity.NumericIdentity) { 153 // IdentityUnknown denotes that this is an L4-only BPF 154 // allow, so it applies to all identities. In this case 155 // we should skip resolving the labels, because the 156 // value 0 does not denote an allow for the "unknown" 157 // identity, but instead an allow of all identities for 158 // that port. 159 if secID != identity.IdentityUnknown { 160 identity := identitycache.LookupIdentityByID(secID) 161 if identity != nil { 162 var l labels.Labels 163 if identity.CIDRLabel != nil { 164 l = identity.CIDRLabel 165 } else { 166 l = identity.Labels 167 } 168 169 allowedIdentityTuple.IdentityLabels = l.StringMap() 170 } 171 } 172 } 173 174 // populateResponseWithPolicyKey inserts an AllowedIdentityTuple element into 'policy' 175 // which corresponds to the specified 'desiredPolicy'. 176 func populateResponseWithPolicyKey(policy *cilium_v2.EndpointPolicy, policyKey *policy.Key) { 177 allowedIdentityTuple := cilium_v2.AllowedIdentityTuple{ 178 DestPort: policyKey.DestPort, 179 Protocol: policyKey.Nexthdr, 180 Identity: uint64(policyKey.Identity), 181 } 182 183 secID := identity.NumericIdentity(policyKey.Identity) 184 updateLabels(&allowedIdentityTuple, secID) 185 186 switch { 187 case policyKey.IsIngress(): 188 if policy.Ingress.Allowed == nil { 189 policy.Ingress.Allowed = cilium_v2.AllowedIdentityList{allowedIdentityTuple} 190 } else { 191 policy.Ingress.Allowed = append(policy.Ingress.Allowed, allowedIdentityTuple) 192 } 193 case policyKey.IsEgress(): 194 if policy.Egress.Allowed == nil { 195 policy.Egress.Allowed = cilium_v2.AllowedIdentityList{allowedIdentityTuple} 196 } else { 197 policy.Egress.Allowed = append(policy.Egress.Allowed, allowedIdentityTuple) 198 } 199 } 200 } 201 202 // desiredPolicyAllowsIdentity returns whether the specified policy allows 203 // ingress and egress traffic for the specified numeric security identity. 204 // If the 'secID' is zero, it will check if all traffic is allowed. 205 // 206 // Returing true for either return value indicates all traffic is allowed. 207 func desiredPolicyAllowsIdentity(desired *policy.EndpointPolicy, identity identity.NumericIdentity) (ingress, egress bool) { 208 key := policy.Key{ 209 Identity: uint32(identity), 210 } 211 212 key.TrafficDirection = trafficdirection.Ingress.Uint8() 213 if _, ok := desired.PolicyMapState[key]; ok || !desired.IngressPolicyEnabled { 214 ingress = true 215 } 216 key.TrafficDirection = trafficdirection.Egress.Uint8() 217 if _, ok := desired.PolicyMapState[key]; ok || !desired.EgressPolicyEnabled { 218 egress = true 219 } 220 221 return ingress, egress 222 } 223 224 // getEndpointPolicy returns an API representation of the policy that the 225 // received Endpoint intends to apply. 226 func (e *Endpoint) getEndpointPolicy() (policy *cilium_v2.EndpointPolicy) { 227 if e.desiredPolicy != nil { 228 policy = &cilium_v2.EndpointPolicy{ 229 Ingress: &cilium_v2.EndpointPolicyDirection{ 230 Enforcing: e.desiredPolicy.IngressPolicyEnabled, 231 }, 232 Egress: &cilium_v2.EndpointPolicyDirection{ 233 Enforcing: e.desiredPolicy.EgressPolicyEnabled, 234 }, 235 } 236 237 // Handle allow-all cases 238 allowsAllIngress, allowsAllEgress := desiredPolicyAllowsIdentity(e.desiredPolicy, identity.IdentityUnknown) 239 if allowsAllIngress { 240 policy.Ingress.Allowed = cilium_v2.AllowedIdentityList{{}} 241 } 242 if allowsAllEgress { 243 policy.Egress.Allowed = cilium_v2.AllowedIdentityList{{}} 244 } 245 246 // If either ingress or egress policy is enabled, go through 247 // the desired policy to populate the values. 248 if !allowsAllIngress || !allowsAllEgress { 249 allowsWorldIngress, allowsWorldEgress := desiredPolicyAllowsIdentity(e.desiredPolicy, identity.ReservedIdentityWorld) 250 251 for policyKey := range e.desiredPolicy.PolicyMapState { 252 // Skip listing identities if enforcement is disabled in direction, 253 // or if the identity corresponds to a CIDR identity and the world is allowed. 254 id := identity.NumericIdentity(policyKey.Identity) 255 switch { 256 case policyKey.IsIngress(): 257 if allowsAllIngress || (id.HasLocalScope() && allowsWorldIngress) { 258 continue 259 } 260 case policyKey.IsEgress(): 261 if allowsAllEgress || (id.HasLocalScope() && allowsWorldEgress) { 262 continue 263 } 264 } 265 266 populateResponseWithPolicyKey(policy, &policyKey) 267 } 268 } 269 270 if policy.Ingress.Allowed != nil { 271 policy.Ingress.Allowed.Sort() 272 } 273 if policy.Egress.Allowed != nil { 274 policy.Egress.Allowed.Sort() 275 } 276 } 277 278 return 279 } 280 281 // GetCiliumEndpointStatus creates a cilium_v2.EndpointStatus of an endpoint. 282 // See cilium_v2.EndpointStatus for a detailed explanation of each field. 283 func (e *Endpoint) GetCiliumEndpointStatus() *cilium_v2.EndpointStatus { 284 e.mutex.RLock() 285 defer e.mutex.RUnlock() 286 287 model := e.GetModelRLocked() 288 modelStatus := model.Status 289 290 controllers := getEndpointStatusControllers(modelStatus) 291 identity := getEndpointIdentity(modelStatus) 292 log := e.getEndpointStatusLog() 293 networking := getEndpointNetworking(modelStatus) 294 295 return &cilium_v2.EndpointStatus{ 296 ID: int64(e.ID), 297 ExternalIdentifiers: modelStatus.ExternalIdentifiers, 298 Controllers: controllers, 299 Identity: identity, 300 Log: log, 301 Networking: networking, 302 Health: modelStatus.Health, 303 State: string(modelStatus.State), 304 Policy: e.getEndpointPolicy(), 305 Encryption: cilium_v2.EncryptionSpec{Key: int(node.GetIPsecKeyIdentity())}, 306 307 // Scheduled for deprecation in 1.5 308 // 309 // Status is deprecated but we have some users depending on 310 // these fields so they continue to be populated until version 311 // 1.5 312 Status: &cilium_v2.DeprecatedEndpointStatus{ 313 Controllers: controllers, 314 Identity: identity, 315 Log: log, 316 Networking: networking, 317 }, 318 } 319 }