github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadget-collection/gadgets/top/tcp/gadget.go (about) 1 // Copyright 2019-2021 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 package tcptop 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "strconv" 21 "strings" 22 "time" 23 24 log "github.com/sirupsen/logrus" 25 26 gadgetv1alpha1 "github.com/inspektor-gadget/inspektor-gadget/pkg/apis/gadget/v1alpha1" 27 "github.com/inspektor-gadget/inspektor-gadget/pkg/columns/sort" 28 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-collection/gadgets" 29 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/top" 30 tcptoptracer "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/top/tcp/tracer" 31 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/top/tcp/types" 32 ) 33 34 type Trace struct { 35 helpers gadgets.GadgetHelpers 36 37 started bool 38 tracer *tcptoptracer.Tracer 39 } 40 41 type TraceFactory struct { 42 gadgets.BaseFactory 43 } 44 45 func NewFactory() gadgets.TraceFactory { 46 return &TraceFactory{ 47 BaseFactory: gadgets.BaseFactory{DeleteTrace: deleteTrace}, 48 } 49 } 50 51 func (f *TraceFactory) Description() string { 52 cols := types.GetColumns() 53 validCols, _ := sort.FilterSortableColumns(cols.ColumnMap, cols.GetColumnNames()) 54 55 t := `tcptop shows command generating TCP connections, with container details. 56 57 The following parameters are supported: 58 - %s: Output interval, in seconds. (default %d) 59 - %s: Maximum rows to print. (default %d) 60 - %s: The field to sort the results by (%s). (default %s) 61 - %s: Only get events for this PID (default to all). 62 - %s: Only get events for this IP version. (either 4 or 6, default to all)` 63 return fmt.Sprintf(t, top.IntervalParam, top.IntervalDefault, 64 top.MaxRowsParam, top.MaxRowsDefault, 65 top.SortByParam, strings.Join(validCols, ","), strings.Join(types.SortByDefault, ","), 66 types.PidParam, types.FamilyParam) 67 } 68 69 func (f *TraceFactory) OutputModesSupported() map[gadgetv1alpha1.TraceOutputMode]struct{} { 70 return map[gadgetv1alpha1.TraceOutputMode]struct{}{ 71 gadgetv1alpha1.TraceOutputModeStream: {}, 72 } 73 } 74 75 func deleteTrace(name string, t interface{}) { 76 trace := t.(*Trace) 77 if trace.tracer != nil { 78 trace.tracer.Stop() 79 } 80 } 81 82 func (f *TraceFactory) Operations() map[gadgetv1alpha1.Operation]gadgets.TraceOperation { 83 n := func() interface{} { 84 return &Trace{ 85 helpers: f.Helpers, 86 } 87 } 88 89 return map[gadgetv1alpha1.Operation]gadgets.TraceOperation{ 90 gadgetv1alpha1.OperationStart: { 91 Doc: "Start tcptop gadget", 92 Operation: func(name string, trace *gadgetv1alpha1.Trace) { 93 f.LookupOrCreate(name, n).(*Trace).Start(trace) 94 }, 95 }, 96 gadgetv1alpha1.OperationStop: { 97 Doc: "Stop tcptop gadget", 98 Operation: func(name string, trace *gadgetv1alpha1.Trace) { 99 f.LookupOrCreate(name, n).(*Trace).Stop(trace) 100 }, 101 }, 102 } 103 } 104 105 func (t *Trace) Start(trace *gadgetv1alpha1.Trace) { 106 if t.started { 107 trace.Status.State = gadgetv1alpha1.TraceStateStarted 108 return 109 } 110 111 traceName := gadgets.TraceName(trace.ObjectMeta.Namespace, trace.ObjectMeta.Name) 112 113 maxRows := top.MaxRowsDefault 114 intervalSeconds := top.IntervalDefault 115 sortBy := types.SortByDefault 116 targetPid := int32(0) 117 targetFamily := int32(-1) 118 119 if trace.Spec.Parameters != nil { 120 params := trace.Spec.Parameters 121 var err error 122 123 if val, ok := params[top.MaxRowsParam]; ok { 124 maxRows, err = strconv.Atoi(val) 125 if err != nil { 126 trace.Status.OperationError = fmt.Sprintf("%q is not valid for %q", val, top.MaxRowsParam) 127 return 128 } 129 } 130 131 if val, ok := params[top.IntervalParam]; ok { 132 intervalSeconds, err = strconv.Atoi(val) 133 if err != nil { 134 trace.Status.OperationError = fmt.Sprintf("%q is not valid for %q", val, top.IntervalParam) 135 return 136 } 137 } 138 139 if val, ok := params[top.SortByParam]; ok { 140 sortByColumns := strings.Split(val, ",") 141 142 _, invalidCols := sort.FilterSortableColumns(types.GetColumns().ColumnMap, sortByColumns) 143 if len(invalidCols) > 0 { 144 trace.Status.OperationError = fmt.Sprintf("%q are not valid for %q", strings.Join(invalidCols, ","), top.SortByParam) 145 return 146 } 147 148 sortBy = sortByColumns 149 } 150 151 if val, ok := params[types.PidParam]; ok { 152 pid, err := strconv.ParseInt(val, 10, 32) 153 if err != nil { 154 trace.Status.OperationError = fmt.Sprintf("%q is not valid for %q", val, types.PidParam) 155 return 156 } 157 158 targetPid = int32(pid) 159 } 160 161 if val, ok := params[types.FamilyParam]; ok { 162 targetFamily, err = types.ParseFilterByFamily(val) 163 if err != nil { 164 trace.Status.OperationError = fmt.Sprintf("%q is not valid for %q", val, types.FamilyParam) 165 return 166 } 167 } 168 } 169 170 mountNsMap, err := t.helpers.TracerMountNsMap(traceName) 171 if err != nil { 172 trace.Status.OperationError = fmt.Sprintf("failed to find tracer's mount ns map: %s", err) 173 return 174 } 175 config := &tcptoptracer.Config{ 176 MaxRows: maxRows, 177 Interval: time.Second * time.Duration(intervalSeconds), 178 SortBy: sortBy, 179 MountnsMap: mountNsMap, 180 TargetPid: targetPid, 181 TargetFamily: targetFamily, 182 } 183 184 eventCallback := func(ev *top.Event[types.Stats]) { 185 r, err := json.Marshal(ev) 186 if err != nil { 187 log.Warnf("Gadget %s: Failed to marshall event: %s", trace.Spec.Gadget, err) 188 return 189 } 190 t.helpers.PublishEvent(traceName, string(r)) 191 } 192 193 tracer, err := tcptoptracer.NewTracer(config, t.helpers, eventCallback) 194 if err != nil { 195 trace.Status.OperationError = fmt.Sprintf("failed to create tracer: %s", err) 196 return 197 } 198 199 t.tracer = tracer 200 t.started = true 201 202 trace.Status.State = gadgetv1alpha1.TraceStateStarted 203 } 204 205 func (t *Trace) Stop(trace *gadgetv1alpha1.Trace) { 206 if !t.started { 207 trace.Status.OperationError = "Not started" 208 return 209 } 210 211 t.tracer.Stop() 212 t.tracer = nil 213 t.started = false 214 215 trace.Status.State = gadgetv1alpha1.TraceStateStopped 216 }