github.com/cilium/cilium@v1.16.2/pkg/socketlb/socketlb.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package socketlb
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/cilium/ebpf"
    13  
    14  	"github.com/cilium/cilium/pkg/bpf"
    15  	"github.com/cilium/cilium/pkg/cgroups"
    16  	"github.com/cilium/cilium/pkg/datapath/linux/sysctl"
    17  	"github.com/cilium/cilium/pkg/logging"
    18  	"github.com/cilium/cilium/pkg/logging/logfields"
    19  	"github.com/cilium/cilium/pkg/option"
    20  )
    21  
    22  const (
    23  	Subsystem = "socketlb"
    24  
    25  	Connect4     = "cil_sock4_connect"
    26  	SendMsg4     = "cil_sock4_sendmsg"
    27  	RecvMsg4     = "cil_sock4_recvmsg"
    28  	GetPeerName4 = "cil_sock4_getpeername"
    29  	PostBind4    = "cil_sock4_post_bind"
    30  	PreBind4     = "cil_sock4_pre_bind"
    31  	Connect6     = "cil_sock6_connect"
    32  	SendMsg6     = "cil_sock6_sendmsg"
    33  	RecvMsg6     = "cil_sock6_recvmsg"
    34  	GetPeerName6 = "cil_sock6_getpeername"
    35  	PostBind6    = "cil_sock6_post_bind"
    36  	PreBind6     = "cil_sock6_pre_bind"
    37  )
    38  
    39  var (
    40  	log = logging.DefaultLogger.WithField(logfields.LogSubsys, Subsystem)
    41  
    42  	cgroupProgs = []string{
    43  		Connect4, SendMsg4, RecvMsg4, GetPeerName4,
    44  		PostBind4, PreBind4, Connect6, SendMsg6,
    45  		RecvMsg6, GetPeerName6, PostBind6, PreBind6}
    46  )
    47  
    48  // TODO: Clean up bpffs root logic and make this a var.
    49  func cgroupLinkPath() string {
    50  	return filepath.Join(bpf.CiliumPath(), Subsystem, "links/cgroup")
    51  }
    52  
    53  // Enable attaches necessary bpf programs for socketlb based on ciliums config.
    54  //
    55  // On restart, Enable can also detach unnecessary programs if specific configuration
    56  // options have changed.
    57  // It expects bpf_sock.c to be compiled previously, so that bpf_sock.o is present
    58  // in the Runtime dir.
    59  func Enable(sysctl sysctl.Sysctl) error {
    60  	if err := os.MkdirAll(cgroupLinkPath(), 0777); err != nil {
    61  		return fmt.Errorf("create bpffs link directory: %w", err)
    62  	}
    63  
    64  	spec, err := bpf.LoadCollectionSpec(filepath.Join(option.Config.StateDir, "bpf_sock.o"))
    65  	if err != nil {
    66  		return fmt.Errorf("failed to load collection spec for bpf_sock.o: %w", err)
    67  	}
    68  
    69  	coll, commit, err := bpf.LoadCollection(spec, &bpf.CollectionOptions{
    70  		CollectionOptions: ebpf.CollectionOptions{
    71  			Maps: ebpf.MapOptions{PinPath: bpf.TCGlobalsPath()},
    72  		},
    73  	})
    74  	var ve *ebpf.VerifierError
    75  	if errors.As(err, &ve) {
    76  		if _, err := fmt.Fprintf(os.Stderr, "Verifier error: %s\nVerifier log: %+v\n", err, ve); err != nil {
    77  			return fmt.Errorf("writing verifier log to stderr: %w", err)
    78  		}
    79  	}
    80  	if err != nil {
    81  		return fmt.Errorf("failed loading eBPF collection into the kernel: %w", err)
    82  	}
    83  	defer coll.Close()
    84  
    85  	// Map a program name to its enabled status. Programs disabled by default.
    86  	enabled := make(map[string]bool)
    87  	for _, p := range cgroupProgs {
    88  		enabled[p] = false
    89  	}
    90  
    91  	if option.Config.EnableIPv4 {
    92  		enabled[Connect4] = true
    93  		enabled[SendMsg4] = true
    94  		enabled[RecvMsg4] = true
    95  
    96  		if option.Config.EnableSocketLBPeer {
    97  			enabled[GetPeerName4] = true
    98  		}
    99  
   100  		if option.Config.EnableNodePort && option.Config.NodePortBindProtection {
   101  			enabled[PostBind4] = true
   102  		}
   103  
   104  		if option.Config.EnableHealthDatapath {
   105  			enabled[PreBind4] = true
   106  		}
   107  	}
   108  
   109  	// v6 will be non-nil if v6 support is compiled out.
   110  	_, v6 := sysctl.ReadInt([]string{"net", "ipv6", "conf", "all", "forwarding"})
   111  
   112  	if option.Config.EnableIPv6 ||
   113  		(option.Config.EnableIPv4 && v6 == nil) {
   114  		enabled[Connect6] = true
   115  		enabled[SendMsg6] = true
   116  		enabled[RecvMsg6] = true
   117  
   118  		if option.Config.EnableSocketLBPeer {
   119  			enabled[GetPeerName6] = true
   120  		}
   121  
   122  		if option.Config.EnableNodePort && option.Config.NodePortBindProtection {
   123  			enabled[PostBind6] = true
   124  		}
   125  
   126  		if option.Config.EnableHealthDatapath {
   127  			enabled[PreBind6] = true
   128  		}
   129  	}
   130  
   131  	for p, s := range enabled {
   132  		if s {
   133  			if err := attachCgroup(coll, p, cgroups.GetCgroupRoot(), cgroupLinkPath()); err != nil {
   134  				return fmt.Errorf("cgroup attach: %w", err)
   135  			}
   136  			continue
   137  		}
   138  		if err := detachCgroup(p, cgroups.GetCgroupRoot(), cgroupLinkPath()); err != nil {
   139  			return fmt.Errorf("cgroup detach: %w", err)
   140  		}
   141  	}
   142  
   143  	if err := commit(); err != nil {
   144  		return fmt.Errorf("committing bpf pins: %w", err)
   145  	}
   146  
   147  	return nil
   148  }
   149  
   150  // Disable detaches all bpf programs for socketlb.
   151  func Disable() error {
   152  	for _, p := range cgroupProgs {
   153  		if err := detachCgroup(p, cgroups.GetCgroupRoot(), cgroupLinkPath()); err != nil {
   154  			return fmt.Errorf("detach cgroup: %w", err)
   155  		}
   156  	}
   157  
   158  	return nil
   159  }