github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadget-collection/gadgets/trace/network/gadget.go (about)

     1  // Copyright 2019-2022 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 networkgraph
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"sigs.k8s.io/controller-runtime/pkg/client"
    21  
    22  	gadgetv1alpha1 "github.com/inspektor-gadget/inspektor-gadget/pkg/apis/gadget/v1alpha1"
    23  	"github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection/networktracer"
    24  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-collection/gadgets"
    25  	netTracer "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/network/tracer"
    26  	netTypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/network/types"
    27  	"github.com/inspektor-gadget/inspektor-gadget/pkg/operators"
    28  	"github.com/inspektor-gadget/inspektor-gadget/pkg/operators/kubeipresolver"
    29  	"github.com/inspektor-gadget/inspektor-gadget/pkg/operators/kubenameresolver"
    30  	"github.com/inspektor-gadget/inspektor-gadget/pkg/operators/socketenricher"
    31  	eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
    32  )
    33  
    34  type Trace struct {
    35  	helpers gadgets.GadgetHelpers
    36  	client  client.Client
    37  
    38  	started bool
    39  
    40  	tracer *netTracer.Tracer
    41  	conn   *networktracer.ConnectionToContainerCollection
    42  
    43  	kubeIPInst         operators.OperatorInstance
    44  	kubeNameInst       operators.OperatorInstance
    45  	socketEnricherInst operators.OperatorInstance
    46  }
    47  
    48  type TraceFactory struct {
    49  	gadgets.BaseFactory
    50  }
    51  
    52  func NewFactory() gadgets.TraceFactory {
    53  	return &TraceFactory{
    54  		BaseFactory: gadgets.BaseFactory{DeleteTrace: deleteTrace},
    55  	}
    56  }
    57  
    58  func (f *TraceFactory) Description() string {
    59  	return `The network-graph gadget monitors the network activity in the specified pods and records the list of TCP connections and UDP streams.`
    60  }
    61  
    62  func (f *TraceFactory) OutputModesSupported() map[gadgetv1alpha1.TraceOutputMode]struct{} {
    63  	return map[gadgetv1alpha1.TraceOutputMode]struct{}{
    64  		gadgetv1alpha1.TraceOutputModeStream: {},
    65  	}
    66  }
    67  
    68  func deleteTrace(name string, t interface{}) {
    69  	trace := t.(*Trace)
    70  	if trace.started {
    71  		trace.stop()
    72  	}
    73  }
    74  
    75  func (f *TraceFactory) Operations() map[gadgetv1alpha1.Operation]gadgets.TraceOperation {
    76  	n := func() interface{} {
    77  		return &Trace{
    78  			client:  f.Client,
    79  			helpers: f.Helpers,
    80  		}
    81  	}
    82  
    83  	return map[gadgetv1alpha1.Operation]gadgets.TraceOperation{
    84  		gadgetv1alpha1.OperationStart: {
    85  			Doc: "Start network-graph",
    86  			Operation: func(name string, trace *gadgetv1alpha1.Trace) {
    87  				f.LookupOrCreate(name, n).(*Trace).Start(trace)
    88  			},
    89  		},
    90  		gadgetv1alpha1.OperationStop: {
    91  			Doc: "Stop network-graph",
    92  			Operation: func(name string, trace *gadgetv1alpha1.Trace) {
    93  				f.LookupOrCreate(name, n).(*Trace).Stop(trace)
    94  			},
    95  		},
    96  	}
    97  }
    98  
    99  func (t *Trace) publishEvent(
   100  	trace *gadgetv1alpha1.Trace,
   101  	event *netTypes.Event,
   102  ) {
   103  	traceName := gadgets.TraceName(trace.ObjectMeta.Namespace, trace.ObjectMeta.Name)
   104  	t.helpers.PublishEvent(
   105  		traceName,
   106  		eventtypes.EventString(event),
   107  	)
   108  }
   109  
   110  func (t *Trace) Start(trace *gadgetv1alpha1.Trace) {
   111  	if t.started {
   112  		trace.Status.State = gadgetv1alpha1.TraceStateStarted
   113  		return
   114  	}
   115  
   116  	var err error
   117  	t.tracer, err = netTracer.NewTracer()
   118  	if err != nil {
   119  		trace.Status.OperationError = fmt.Sprintf("Failed to start network-graph tracer: %s", err)
   120  		return
   121  	}
   122  
   123  	// TODO: Don't access the operators directly
   124  	// - update cmd/kubectl-gadget/advise/network-policy.go to use the gRPC interface instead of the CR one
   125  	// - delete this file pkg/gadget-collection/gadgets/trace/network/gadget.go
   126  	kubeIPOp := operators.GetRaw(kubeipresolver.OperatorName).(*kubeipresolver.KubeIPResolver)
   127  	kubeIPOp.Init(nil)
   128  	t.kubeIPInst, err = kubeIPOp.Instantiate(nil, nil, nil)
   129  	if err == nil {
   130  		t.kubeIPInst.PreGadgetRun()
   131  	}
   132  
   133  	kubeNameOp := operators.GetRaw(kubenameresolver.OperatorName).(*kubenameresolver.KubeNameResolver)
   134  	kubeNameOp.Init(nil)
   135  	t.kubeNameInst, err = kubeNameOp.Instantiate(nil, nil, nil)
   136  	if err == nil {
   137  		t.kubeNameInst.PreGadgetRun()
   138  	}
   139  
   140  	socketEnricherOp := operators.GetRaw(socketenricher.OperatorName).(*socketenricher.SocketEnricher)
   141  	socketEnricherOp.Init(nil)
   142  	t.socketEnricherInst, err = socketEnricherOp.Instantiate(nil, t.tracer, nil)
   143  	if err == nil {
   144  		t.socketEnricherInst.PreGadgetRun()
   145  	}
   146  
   147  	eventCallback := func(event *netTypes.Event) {
   148  		// Enrich event but only with the fields required for the advise network-policy gadget.
   149  		event.K8s.Node = trace.Spec.Node
   150  		if t.helpers != nil {
   151  			t.helpers.EnrichByNetNs(&event.CommonData, event.WithNetNsID.NetNsID)
   152  		}
   153  
   154  		// Use KubeIPResolver and KubeNameResolver to enrich event based on Namespace/Pod and IP.
   155  		if t.kubeIPInst != nil {
   156  			t.kubeIPInst.EnrichEvent(event)
   157  		}
   158  		if t.kubeNameInst != nil {
   159  			t.kubeNameInst.EnrichEvent(event)
   160  		}
   161  
   162  		t.publishEvent(trace, event)
   163  	}
   164  	t.tracer.SetEventHandler(eventCallback)
   165  
   166  	config := &networktracer.ConnectToContainerCollectionConfig[netTypes.Event]{
   167  		Tracer:   t.tracer,
   168  		Resolver: t.helpers,
   169  		Selector: *gadgets.ContainerSelectorFromContainerFilter(trace.Spec.Filter),
   170  		Base:     netTypes.Base,
   171  	}
   172  	t.conn, err = networktracer.ConnectToContainerCollection(config)
   173  	if err != nil {
   174  		trace.Status.OperationError = fmt.Sprintf("Failed to start network-graph tracer: %s", err)
   175  		return
   176  	}
   177  
   178  	if err := t.tracer.RunWorkaround(); err != nil {
   179  		trace.Status.OperationError = fmt.Sprintf("Failed to start network-graph tracer: %s", err)
   180  		return
   181  	}
   182  
   183  	t.started = true
   184  	trace.Status.State = gadgetv1alpha1.TraceStateStarted
   185  }
   186  
   187  func (t *Trace) Stop(trace *gadgetv1alpha1.Trace) {
   188  	if !t.started {
   189  		trace.Status.OperationError = "Not started"
   190  		return
   191  	}
   192  
   193  	t.stop()
   194  	trace.Status.State = gadgetv1alpha1.TraceStateStopped
   195  }
   196  
   197  func (t *Trace) stop() {
   198  	if t.conn != nil {
   199  		t.conn.Close()
   200  	}
   201  	if t.kubeIPInst != nil {
   202  		t.kubeIPInst.PostGadgetRun()
   203  		t.kubeIPInst = nil
   204  	}
   205  	if t.kubeNameInst != nil {
   206  		t.kubeNameInst.PostGadgetRun()
   207  		t.kubeNameInst = nil
   208  	}
   209  	if t.socketEnricherInst != nil {
   210  		t.socketEnricherInst.PostGadgetRun()
   211  		t.socketEnricherInst = nil
   212  	}
   213  
   214  	t.tracer.Close()
   215  	t.tracer = nil
   216  	t.started = false
   217  }