github.com/cilium/cilium@v1.16.2/pkg/hubble/dropeventemitter/dropeventemitter.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package dropeventemitter 5 6 import ( 7 "context" 8 "slices" 9 "strconv" 10 "strings" 11 12 v1 "k8s.io/api/core/v1" 13 typedv1 "k8s.io/client-go/kubernetes/typed/core/v1" 14 "k8s.io/client-go/tools/record" 15 16 flowpb "github.com/cilium/cilium/api/v1/flow" 17 "github.com/cilium/cilium/pkg/identity" 18 client "github.com/cilium/cilium/pkg/k8s/client" 19 slimv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" 20 metaslimv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 21 slimscheme "github.com/cilium/cilium/pkg/k8s/slim/k8s/client/clientset/versioned/scheme" 22 "github.com/cilium/cilium/pkg/k8s/watchers" 23 "github.com/cilium/cilium/pkg/time" 24 ) 25 26 type DropEventEmitter struct { 27 reasons []string 28 recorder record.EventRecorder 29 k8sWatcher watchers.CacheAccessK8SWatcher 30 } 31 32 func NewDropEventEmitter(interval time.Duration, reasons []string, k8s client.Clientset, watcher watchers.CacheAccessK8SWatcher) *DropEventEmitter { 33 broadcaster := record.NewBroadcasterWithCorrelatorOptions(record.CorrelatorOptions{ 34 BurstSize: 1, 35 QPS: 1 / float32(interval.Seconds()), 36 MaxEvents: 1, 37 MaxIntervalInSeconds: int(interval.Seconds()), 38 MessageFunc: func(event *v1.Event) string { return event.Message }, 39 }) 40 broadcaster.StartRecordingToSink(&typedv1.EventSinkImpl{Interface: k8s.CoreV1().Events("")}) 41 42 return &DropEventEmitter{ 43 reasons: reasons, 44 recorder: broadcaster.NewRecorder(slimscheme.Scheme, v1.EventSource{Component: "cilium"}), 45 k8sWatcher: watcher, 46 } 47 } 48 49 func (e *DropEventEmitter) ProcessFlow(ctx context.Context, flow *flowpb.Flow) error { 50 reason := strings.ToLower(flow.DropReasonDesc.String()) 51 52 // Only handle packet drops due to policy related to a Pod 53 if flow.Verdict != flowpb.Verdict_DROPPED || 54 !slices.Contains(e.reasons, reason) || 55 (flow.TrafficDirection == flowpb.TrafficDirection_INGRESS && 56 flow.Destination.PodName == "") || 57 (flow.TrafficDirection == flowpb.TrafficDirection_EGRESS && 58 flow.Source.PodName == "") { 59 return nil 60 } 61 62 if flow.TrafficDirection == flowpb.TrafficDirection_INGRESS { 63 message := "Incoming packet dropped (" + reason + ") from " + 64 e.endpointToString(flow.IP.Source, flow.Source) + " " + 65 e.l4protocolToString(flow.L4) 66 e.recorder.Event(&slimv1.Pod{ 67 TypeMeta: metaslimv1.TypeMeta{ 68 Kind: "Pod", 69 APIVersion: "v1", 70 }, 71 ObjectMeta: metaslimv1.ObjectMeta{ 72 Name: flow.Destination.PodName, 73 Namespace: flow.Destination.Namespace, 74 }, 75 }, v1.EventTypeWarning, "PacketDrop", message) 76 } else { 77 message := "Outgoing packet dropped (" + reason + ") to " + 78 e.endpointToString(flow.IP.Destination, flow.Destination) + " " + 79 e.l4protocolToString(flow.L4) 80 81 objMeta := metaslimv1.ObjectMeta{ 82 Name: flow.Source.PodName, 83 Namespace: flow.Source.Namespace, 84 } 85 if e.k8sWatcher != nil { 86 pod, err := e.k8sWatcher.GetCachedPod(flow.Source.Namespace, flow.Source.PodName) 87 if err == nil { 88 objMeta.UID = pod.UID 89 } 90 } 91 podObj := slimv1.Pod{ 92 TypeMeta: metaslimv1.TypeMeta{ 93 Kind: "Pod", 94 APIVersion: "v1", 95 }, 96 ObjectMeta: objMeta, 97 } 98 e.recorder.Event(&podObj, v1.EventTypeWarning, "PacketDrop", message) 99 } 100 101 return nil 102 } 103 104 func (e *DropEventEmitter) endpointToString(ip string, endpoint *flowpb.Endpoint) string { 105 if endpoint.PodName != "" { 106 return endpoint.Namespace + "/" + endpoint.PodName + " (" + ip + ")" 107 } else if identity.NumericIdentity(endpoint.Identity).IsReservedIdentity() { 108 return identity.NumericIdentity(endpoint.Identity).String() + " (" + ip + ")" 109 } else { 110 return ip 111 } 112 } 113 114 func (e *DropEventEmitter) l4protocolToString(l4 *flowpb.Layer4) string { 115 switch l4.Protocol.(type) { 116 case *flowpb.Layer4_TCP: 117 return "TCP/" + strconv.Itoa(int(l4.GetTCP().DestinationPort)) 118 case *flowpb.Layer4_UDP: 119 return "UDP/" + strconv.Itoa(int(l4.GetUDP().DestinationPort)) 120 case *flowpb.Layer4_ICMPv4: 121 return "ICMPv4" 122 case *flowpb.Layer4_ICMPv6: 123 return "ICMPv6" 124 case *flowpb.Layer4_SCTP: 125 return "SCTP" 126 } 127 return "" 128 }