You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: interface.go
    path of file: ./repos/portmaster/firewall/interception/ebpf/bandwidth
    
    the code of the file until where you have to start completion: package ebpf

import (
	"context"
	"encoding/binary"
	"fmt"
	"net"
	"path/filepath"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/cilium/ebpf"
	"github.com/cilium/ebpf/link"
	"github.com/cilium/ebpf/rlimit"
	"golang.org/x/sys/unix"

	"github.com/safing/portbase/log"
	"github.com/safing/portmaster/network/packet"
)

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -cflags "-O2 -g -Wall -Werror" bpf ../programs/bandwidth.c

var ebpfLoadingFailed atomic.Uint32

// BandwidthStatsWorker monitors connection bandwidth using ebpf.
func BandwidthStatsWorker(ctx context.Context, collectInterval time.Duration, bandwidthUpdates chan *packet.BandwidthUpdate) error {
	// Allow the current process to lock memory for eBPF resources.
	err := rlimit.RemoveMemlock()
	if err != nil {
		if ebpfLoadingFailed.Add(1) >= 5 {
			log.Warningf("ebpf: failed to remove memlock 5 times, giving up with error %s", err)
			return nil
		}
		return fmt.Errorf("ebpf: failed to remove memlock: %w", err)
	}

	// Load pre-compiled programs and maps into the kernel.
	objs := bpfObjects{}
	if err := loadBpfObjects(&objs, nil); err != nil {
		if ebpfLoadingFailed.Add(1) >= 5 {
			log.Warningf("ebpf: failed to load ebpf object 5 times, giving up with error %s", err)
			return nil
		}
		return fmt.Errorf("ebpf: failed to load ebpf object: %w", err)
	}
	defer objs.Close() //nolint:errcheck

	// Find the cgroup path
	path, err := findCgroupPath()
	if err != nil {
		return fmt.Errorf("ebpf: failed to find cgroup paths: %w", err)
	}

	// Attach socket options for monitoring connections
	sockOptionsLink, err := link.AttachCgroup(link.CgroupOptions{
		Path:    path,
		Program: objs.bpfPrograms.SocketOperations,
		Attach:  ebpf.AttachCGroupSockOps,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open module sockops: %w", err)
	}
	defer sockOptionsLink.Close() //nolint:errcheck

	// Attach Udp Ipv4 recive message tracing
	udpv4RMLink, err := link.AttachTracing(link.TracingOptions{
		Program: objs.bpfPrograms.UdpRecvmsg,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open trace Udp IPv4 recvmsg: %w", err)
	}
	defer udpv4RMLink.Close() //no
    
func BandwidthStatsWorker(ctx context.Context, collectInterval time.Duration, bandwidthUpdates chan *packet.BandwidthUpdate) error {
	// Allow the current process to lock memory for eBPF resources.
	err := rlimit.RemoveMemlock()
	if err != nil {
		if ebpfLoadingFailed.Add(1) >= 5 {
			log.Warningf("ebpf: failed to remove memlock 5 times, giving up with error %s", err)
			return nil
		}
		return fmt.Errorf("ebpf: failed to remove memlock: %w", err)
	}

	// Load pre-compiled programs and maps into the kernel.
	objs := bpfObjects{}
	if err := loadBpfObjects(&objs, nil); err != nil {
		if ebpfLoadingFailed.Add(1) >= 5 {
			log.Warningf("ebpf: failed to load ebpf object 5 times, giving up with error %s", err)
			return nil
		}
		return fmt.Errorf("ebpf: failed to load ebpf object: %w", err)
	}
	defer objs.Close() //nolint:errcheck

	// Find the cgroup path
	path, err := findCgroupPath()
	if err != nil {
		return fmt.Errorf("ebpf: failed to find cgroup paths: %w", err)
	}

	// Attach socket options for monitoring connections
	sockOptionsLink, err := link.AttachCgroup(link.CgroupOptions{
		Path:    path,
		Program: objs.bpfPrograms.SocketOperations,
		Attach:  ebpf.AttachCGroupSockOps,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open module sockops: %w", err)
	}
	defer sockOptionsLink.Close() //nolint:errcheck

	// Attach Udp Ipv4 recive message tracing
	udpv4RMLink, err := link.AttachTracing(link.TracingOptions{
		Program: objs.bpfPrograms.UdpRecvmsg,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open trace Udp IPv4 recvmsg: %w", err)
	}
	defer udpv4RMLink.Close() //nolint:errcheck

	// Attach UDP IPv4 send message tracing
	udpv4SMLink, err := link.AttachTracing(link.TracingOptions{
		Program: objs.bpfPrograms.UdpSendmsg,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open trace Udp IPv4 sendmsg: %w", err)
	}
	defer udpv4SMLink.Close() //nolint:errcheck

	// Attach UDP IPv6 receive message tracing
	udpv6RMLink, err := link.AttachTracing(link.TracingOptions{
		Program: objs.bpfPrograms.Udpv6Recvmsg,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open trace Udp IPv6 recvmsg: %w", err)
	}
	defer udpv6RMLink.Close() //nolint:errcheck

	// Attach UDP IPv6 send message tracing
	udpv6SMLink, err := link.AttachTracing(link.TracingOptions{
		Program: objs.bpfPrograms.Udpv6Sendmsg,
	})
	if err != nil {
		return fmt.Errorf("ebpf: failed to open trace Udp IPv6 sendmsg: %w", err)
	}
	defer udpv6SMLink.Close() //nolint:errcheck

	// Setup ticker.
	ticker := time.NewTicker(collectInterval)
	defer ticker.Stop()

	// Collect bandwidth at every tick.
	for {
		select {
		case <-ticker.C:
			reportBandwidth(ctx, objs, bandwidthUpdates)
		case <-ctx.Done():
			return nil
		}
	}
}