github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/tcpconnect/tracer/tracer.go (about) 1 // Copyright 2022-2023 The Inspektor Gadget authors 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 //go:build !withoutebpf 16 17 package tracer 18 19 import ( 20 "errors" 21 "fmt" 22 "os" 23 "time" 24 "unsafe" 25 26 "github.com/cilium/ebpf" 27 "github.com/cilium/ebpf/link" 28 "github.com/cilium/ebpf/perf" 29 30 gadgetcontext "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-context" 31 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets" 32 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/tcpconnect/types" 33 eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 34 ) 35 36 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags ${CFLAGS} -type event tcpconnect ./bpf/tcpconnect.bpf.c -- -I./bpf/ 37 38 type Config struct { 39 MountnsMap *ebpf.Map 40 CalculateLatency bool 41 MinLatency time.Duration 42 } 43 44 type Tracer struct { 45 config *Config 46 enricher gadgets.DataEnricherByMntNs 47 eventCallback func(*types.Event) 48 49 objs tcpconnectObjects 50 v4EnterLink link.Link 51 v4ExitLink link.Link 52 v6EnterLink link.Link 53 v6ExitLink link.Link 54 tcpDestroySockLink link.Link 55 tcpRvcStateProcessLink link.Link 56 reader *perf.Reader 57 } 58 59 func NewTracer(config *Config, enricher gadgets.DataEnricherByMntNs, 60 eventCallback func(*types.Event), 61 ) (*Tracer, error) { 62 t := &Tracer{ 63 config: config, 64 enricher: enricher, 65 eventCallback: eventCallback, 66 } 67 68 if err := t.install(); err != nil { 69 t.close() 70 return nil, err 71 } 72 73 go t.run() 74 75 return t, nil 76 } 77 78 // Stop stops the tracer 79 // TODO: Remove after refactoring 80 func (t *Tracer) Stop() { 81 t.close() 82 } 83 84 func (t *Tracer) close() { 85 t.v4EnterLink = gadgets.CloseLink(t.v4EnterLink) 86 t.v4ExitLink = gadgets.CloseLink(t.v4ExitLink) 87 t.v6EnterLink = gadgets.CloseLink(t.v6EnterLink) 88 t.v6ExitLink = gadgets.CloseLink(t.v6ExitLink) 89 t.tcpDestroySockLink = gadgets.CloseLink(t.tcpDestroySockLink) 90 t.tcpRvcStateProcessLink = gadgets.CloseLink(t.tcpRvcStateProcessLink) 91 92 t.objs.Close() 93 } 94 95 func (t *Tracer) install() error { 96 var err error 97 spec, err := loadTcpconnect() 98 if err != nil { 99 return fmt.Errorf("loading ebpf program: %w", err) 100 } 101 102 consts := map[string]interface{}{ 103 "targ_min_latency_ns": t.config.MinLatency, 104 "calculate_latency": t.config.CalculateLatency, 105 } 106 107 if err := gadgets.LoadeBPFSpec(t.config.MountnsMap, spec, consts, &t.objs); err != nil { 108 return fmt.Errorf("loading ebpf spec: %w", err) 109 } 110 111 t.v4EnterLink, err = link.Kprobe("tcp_v4_connect", t.objs.IgTcpcV4CoE, nil) 112 if err != nil { 113 return fmt.Errorf("attaching kprobe: %w", err) 114 } 115 116 t.v6EnterLink, err = link.Kprobe("tcp_v6_connect", t.objs.IgTcpcV6CoE, nil) 117 if err != nil { 118 return fmt.Errorf("attaching kprobe: %w", err) 119 } 120 121 if !t.config.CalculateLatency { 122 t.v4ExitLink, err = link.Kretprobe("tcp_v4_connect", t.objs.IgTcpcV4CoX, nil) 123 if err != nil { 124 return fmt.Errorf("attaching kretprobe: %w", err) 125 } 126 127 t.v6ExitLink, err = link.Kretprobe("tcp_v6_connect", t.objs.IgTcpcV6CoX, nil) 128 if err != nil { 129 return fmt.Errorf("attaching kretprobe: %w", err) 130 } 131 } else { 132 t.tcpDestroySockLink, err = link.Tracepoint("tcp", "tcp_destroy_sock", t.objs.IgTcpDestroy, nil) 133 if err != nil { 134 return fmt.Errorf("attaching tracepoint: %w", err) 135 } 136 137 t.tcpRvcStateProcessLink, err = link.Kprobe("tcp_rcv_state_process", t.objs.IgTcpRsp, nil) 138 if err != nil { 139 return fmt.Errorf("attaching kprobe: %w", err) 140 } 141 } 142 143 reader, err := perf.NewReader(t.objs.tcpconnectMaps.Events, gadgets.PerfBufferPages*os.Getpagesize()) 144 if err != nil { 145 return fmt.Errorf("creating perf ring buffer: %w", err) 146 } 147 t.reader = reader 148 149 return nil 150 } 151 152 func (t *Tracer) run() { 153 for { 154 record, err := t.reader.Read() 155 if err != nil { 156 if errors.Is(err, perf.ErrClosed) { 157 // nothing to do, we're done 158 return 159 } 160 161 msg := fmt.Sprintf("Error reading perf ring buffer: %s", err) 162 t.eventCallback(types.Base(eventtypes.Err(msg))) 163 return 164 } 165 166 if record.LostSamples > 0 { 167 msg := fmt.Sprintf("lost %d samples", record.LostSamples) 168 t.eventCallback(types.Base(eventtypes.Warn(msg))) 169 continue 170 } 171 172 bpfEvent := (*tcpconnectEvent)(unsafe.Pointer(&record.RawSample[0])) 173 174 ipversion := gadgets.IPVerFromAF(bpfEvent.Af) 175 176 event := types.Event{ 177 Event: eventtypes.Event{ 178 Type: eventtypes.NORMAL, 179 Timestamp: gadgets.WallTimeFromBootTime(bpfEvent.Timestamp), 180 }, 181 WithMountNsID: eventtypes.WithMountNsID{MountNsID: bpfEvent.MntnsId}, 182 Pid: bpfEvent.Pid, 183 Uid: bpfEvent.Uid, 184 Gid: bpfEvent.Gid, 185 Comm: gadgets.FromCString(bpfEvent.Task[:]), 186 SrcEndpoint: eventtypes.L4Endpoint{ 187 L3Endpoint: eventtypes.L3Endpoint{ 188 Addr: gadgets.IPStringFromBytes(bpfEvent.SaddrV6, ipversion), 189 Version: uint8(ipversion), 190 }, 191 Port: gadgets.Htons(bpfEvent.Sport), 192 }, 193 DstEndpoint: eventtypes.L4Endpoint{ 194 L3Endpoint: eventtypes.L3Endpoint{ 195 Addr: gadgets.IPStringFromBytes(bpfEvent.DaddrV6, ipversion), 196 Version: uint8(ipversion), 197 }, 198 Port: gadgets.Htons(bpfEvent.Dport), 199 }, 200 IPVersion: ipversion, 201 Latency: time.Duration(int64(bpfEvent.Latency)), 202 } 203 204 if t.enricher != nil { 205 t.enricher.EnrichByMntNs(&event.CommonData, event.MountNsID) 206 } 207 208 t.eventCallback(&event) 209 } 210 } 211 212 // --- Registry changes 213 214 func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error { 215 params := gadgetCtx.GadgetParams() 216 t.config.CalculateLatency = params.Get(ParamLatency).AsBool() 217 t.config.MinLatency = params.Get(ParamMin).AsDuration() 218 219 defer t.close() 220 if err := t.install(); err != nil { 221 return fmt.Errorf("installing tracer: %w", err) 222 } 223 224 go t.run() 225 gadgetcontext.WaitForTimeoutOrDone(gadgetCtx) 226 227 return nil 228 } 229 230 func (t *Tracer) SetMountNsMap(mountnsMap *ebpf.Map) { 231 t.config.MountnsMap = mountnsMap 232 } 233 234 func (t *Tracer) SetEventHandler(handler any) { 235 nh, ok := handler.(func(ev *types.Event)) 236 if !ok { 237 panic("event handler invalid") 238 } 239 t.eventCallback = nh 240 } 241 242 func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) { 243 tracer := &Tracer{ 244 config: &Config{}, 245 } 246 return tracer, nil 247 }