github.com/cilium/cilium@v1.16.2/pkg/hubble/metrics/flows-to-world/handler.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package flows_to_world 5 6 import ( 7 "context" 8 "strconv" 9 "strings" 10 11 "github.com/prometheus/client_golang/prometheus" 12 13 flowpb "github.com/cilium/cilium/api/v1/flow" 14 v1 "github.com/cilium/cilium/pkg/hubble/api/v1" 15 "github.com/cilium/cilium/pkg/hubble/metrics/api" 16 pkglabels "github.com/cilium/cilium/pkg/labels" 17 ) 18 19 const ( 20 reservedWorldLbl = pkglabels.LabelSourceReserved + ":" + pkglabels.IDNameWorld 21 reservedWorldIPv4Lbl = pkglabels.LabelSourceReserved + ":" + pkglabels.IDNameWorldIPv4 22 reservedWorldIPv6Lbl = pkglabels.LabelSourceReserved + ":" + pkglabels.IDNameWorldIPv6 23 ) 24 25 type flowsToWorldHandler struct { 26 flowsToWorld *prometheus.CounterVec 27 context *api.ContextOptions 28 anyDrop bool 29 port bool 30 synOnly bool 31 } 32 33 func (h *flowsToWorldHandler) Init(registry *prometheus.Registry, options api.Options) error { 34 c, err := api.ParseContextOptions(options) 35 if err != nil { 36 return err 37 } 38 h.context = c 39 for key := range options { 40 switch strings.ToLower(key) { 41 case "any-drop": 42 h.anyDrop = true 43 case "port": 44 h.port = true 45 case "syn-only": 46 h.synOnly = true 47 } 48 } 49 labels := []string{"protocol", "verdict"} 50 if h.port { 51 labels = append(labels, "port") 52 } 53 labels = append(labels, h.context.GetLabelNames()...) 54 55 h.flowsToWorld = prometheus.NewCounterVec(prometheus.CounterOpts{ 56 Namespace: api.DefaultPrometheusNamespace, 57 Name: "flows_to_world_total", 58 Help: "Total number of flows to reserved:world", 59 }, labels) 60 registry.MustRegister(h.flowsToWorld) 61 return nil 62 } 63 64 func (h *flowsToWorldHandler) Status() string { 65 var status []string 66 if h.anyDrop { 67 status = append(status, "any-drop") 68 } 69 if h.port { 70 status = append(status, "port") 71 } 72 if h.synOnly { 73 status = append(status, "syn-only") 74 } 75 return strings.Join(append(status, h.context.Status()), ",") 76 } 77 78 func (h *flowsToWorldHandler) Context() *api.ContextOptions { 79 return h.context 80 } 81 82 func (h *flowsToWorldHandler) ListMetricVec() []*prometheus.MetricVec { 83 return []*prometheus.MetricVec{h.flowsToWorld.MetricVec} 84 } 85 86 func (h *flowsToWorldHandler) isReservedWorld(endpoint *flowpb.Endpoint) bool { 87 for _, label := range endpoint.Labels { 88 switch label { 89 case reservedWorldLbl, reservedWorldIPv4Lbl, reservedWorldIPv6Lbl: 90 return true 91 } 92 } 93 return false 94 } 95 96 func (h *flowsToWorldHandler) ProcessFlow(_ context.Context, flow *flowpb.Flow) error { 97 l4 := flow.GetL4() 98 if flow.GetDestination() == nil || 99 !h.isReservedWorld(flow.GetDestination()) || 100 flow.GetEventType() == nil || 101 l4 == nil { 102 return nil 103 } 104 // if "any-drop" option is not set, non-policy drops are ignored. 105 if flow.GetVerdict() == flowpb.Verdict_DROPPED && !h.anyDrop && flow.GetDropReasonDesc() != flowpb.DropReason_POLICY_DENIED { 106 return nil 107 } 108 // if this is potentially a forwarded reply packet, ignore it to avoid collecting statistics about ephemeral ports 109 isReply := flow.GetIsReply() != nil && flow.GetIsReply().GetValue() 110 if flow.GetVerdict() != flowpb.Verdict_DROPPED && isReply { 111 return nil 112 } 113 114 // if "syn-only" option is set, only count non-reply SYN packets for TCP. 115 if h.synOnly && (!l4.GetTCP().GetFlags().GetSYN() || isReply) { 116 return nil 117 } 118 119 labelValues, err := h.context.GetLabelValues(flow) 120 if err != nil { 121 return err 122 } 123 124 labels := []string{v1.FlowProtocol(flow), flow.GetVerdict().String()} 125 126 // if "port" option is set, add port to the label. 127 if h.port { 128 port := "" 129 if tcp := l4.GetTCP(); tcp != nil { 130 port = strconv.Itoa(int(tcp.GetDestinationPort())) 131 } else if udp := l4.GetUDP(); udp != nil { 132 port = strconv.Itoa(int(udp.GetDestinationPort())) 133 } else if sctp := l4.GetSCTP(); sctp != nil { 134 port = strconv.Itoa(int(sctp.GetDestinationPort())) 135 } 136 labels = append(labels, port) 137 } 138 labels = append(labels, labelValues...) 139 h.flowsToWorld.WithLabelValues(labels...).Inc() 140 return nil 141 }