github.com/cilium/cilium@v1.16.2/tools/sysctlfix/main.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"path"
    12  	"time"
    13  
    14  	"github.com/coreos/go-systemd/v22/dbus"
    15  	"github.com/spf13/pflag"
    16  
    17  	"github.com/cilium/cilium/pkg/safeio"
    18  )
    19  
    20  // This tool attempts to write a sysctl config file to the sysctl config directory with the highest precedence so
    21  // we can overwrite any other config and ensure correct sysctl options for Cilium to function.
    22  
    23  var (
    24  	flagSet = pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
    25  
    26  	sysctlD = flagSet.String("sysctl-conf-dir", "/etc/sysctl.d/", "Path to the sysctl config directory")
    27  	// The 99-zzz prefix ensures our config file gets precedence over most if not all other files.
    28  	ciliumOverwrites = flagSet.String(
    29  		"sysctl-config-file",
    30  		"99-zzz-override_cilium.conf",
    31  		"Filename of the cilium sysctl overwrites config file",
    32  	)
    33  	// Name of the systemd-sysctl unit to restart after making changes
    34  	sysctlUnit = flagSet.String(
    35  		"systemd-sysctl-unit",
    36  		"systemd-sysctl.service",
    37  		"Name of the systemd sysctl unit to reload",
    38  	)
    39  )
    40  
    41  var sysctlConfig = `
    42  # Disable rp_filter on Cilium interfaces since it may cause mangled packets to be dropped
    43  -net.ipv4.conf.lxc*.rp_filter = 0
    44  -net.ipv4.conf.cilium_*.rp_filter = 0
    45  # The kernel uses max(conf.all, conf.{dev}) as its value, so we need to set .all. to 0 as well.
    46  # Otherwise it will overrule the device specific settings.
    47  net.ipv4.conf.all.rp_filter = 0
    48  `
    49  
    50  // This program is executed by an init container so we purposely don't
    51  // exit with any error codes. In case of errors, the function will print warnings,
    52  // but we don't block cilium agent pod from running.
    53  func main() {
    54  	err := flagSet.Parse(os.Args[1:])
    55  	if err != nil {
    56  		fmt.Printf("parse flags: %s\n", err)
    57  		return
    58  	}
    59  
    60  	info, err := os.Stat(*sysctlD)
    61  	if err != nil {
    62  		fmt.Printf("can't stat sysctl.d dir '%s': %s\n", *sysctlD, err)
    63  		return
    64  	}
    65  
    66  	if !info.IsDir() {
    67  		fmt.Printf("'%s' is not a directory\n", *sysctlD)
    68  		return
    69  	}
    70  
    71  	overwritesPath := path.Join(*sysctlD, *ciliumOverwrites)
    72  	f, err := os.OpenFile(overwritesPath, os.O_RDWR|os.O_CREATE, 0644)
    73  	if err != nil {
    74  		fmt.Printf("unable to create cilium sysctl overwrites config: %s\n", err)
    75  		return
    76  	}
    77  	defer f.Close()
    78  
    79  	currentContents, err := safeio.ReadAllLimit(f, safeio.MB)
    80  	if err != nil {
    81  		fmt.Printf("read config: %s\n", err)
    82  		return
    83  	}
    84  
    85  	if string(currentContents) == sysctlConfig {
    86  		fmt.Println("sysctl config up-to-date, nothing to do")
    87  		return
    88  	}
    89  
    90  	_, err = f.Seek(0, io.SeekStart)
    91  	if err != nil {
    92  		fmt.Printf("error while seeking to start of sysctl config: %s\n", err)
    93  		return
    94  	}
    95  
    96  	// Truncate the whole file
    97  	err = f.Truncate(0)
    98  	if err != nil {
    99  		fmt.Printf("error while truncating sysctl config: %s\n", err)
   100  		return
   101  	}
   102  
   103  	_, err = fmt.Fprint(f, sysctlConfig)
   104  	if err != nil {
   105  		fmt.Printf("error while writing to sysctl config: %s\n", err)
   106  		return
   107  	}
   108  
   109  	fmt.Println("sysctl config created/updated")
   110  
   111  	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
   112  	defer cancel()
   113  
   114  	conn, err := dbus.NewSystemdConnectionContext(ctx)
   115  	if err != nil {
   116  		fmt.Printf("error while creating SystemD D-Bus connection: %s\n", err)
   117  		return
   118  	}
   119  
   120  	_, err = conn.GetUnitPropertiesContext(ctx, *sysctlUnit)
   121  	if err != nil {
   122  		fmt.Printf("can't verify unit '%s' exists: %s\n", *sysctlUnit, err)
   123  		return
   124  	}
   125  
   126  	// https://www.freedesktop.org/wiki/Software/systemd/dbus/
   127  	// "The mode needs to be one of replace, fail, isolate, ignore-dependencies, ignore-requirements.
   128  	//  If "replace" the call will start the unit and its dependencies, possibly replacing already queued jobs that
   129  	//  conflict with this."
   130  	const mode = "replace"
   131  
   132  	// Restart the systemd-sysctl unit, this will trigger SystemD to apply the new config to all existing interfaces
   133  	// which is required for host-interfaces and reloads on existing cilium deployments.
   134  	_, err = conn.RestartUnitContext(ctx, *sysctlUnit, mode, nil)
   135  	if err != nil {
   136  		fmt.Printf("error while restarting unit '%s': %s\n", *sysctlUnit, err)
   137  		return
   138  	}
   139  
   140  	fmt.Printf("systemd unit '%s' restarted\n", *sysctlUnit)
   141  }