Skip to content

Commit

Permalink
Log generated iptables rules too in addition to the original config file
Browse files Browse the repository at this point in the history
We now have many toggles to adjust the rules. Having them dumped in logs
helps debugging and eliminates the need to inspect nodes in many cases.
  • Loading branch information
jingyuanliang committed Oct 22, 2024
1 parent 93dfa6e commit ea2d9db
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 44 deletions.
110 changes: 69 additions & 41 deletions cmd/ip-masq-agent/ip-masq-agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

utilyaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/component-base/logs"
"k8s.io/component-base/logs/logreduction"
"k8s.io/component-base/version/verflag"
"k8s.io/ip-masq-agent/cmd/ip-masq-agent/testing/fakefs"
"k8s.io/ip-masq-agent/pkg/interval"
Expand All @@ -44,6 +45,8 @@ const (
linkLocalCIDRIPv6 = "fe80::/10"
// path to a yaml or json file
configPath = "/etc/config/ip-masq-agent"
// How frequently to write identical logs at verbosity 2 (otherwise 4)
identicalLogDelay = 24 * time.Hour
)

var (
Expand Down Expand Up @@ -116,9 +119,10 @@ func NewMasqConfig(masqAllReservedRanges bool) *MasqConfig {

// MasqDaemon object
type MasqDaemon struct {
config *MasqConfig
iptables utiliptables.Interface
ip6tables utiliptables.Interface
config *MasqConfig
iptables utiliptables.Interface
ip6tables utiliptables.Interface
logReduction *logreduction.LogReduction
}

// NewMasqDaemon returns a MasqDaemon with default values, including an initialized utiliptables.Interface
Expand All @@ -129,9 +133,10 @@ func NewMasqDaemon(c *MasqConfig) *MasqDaemon {
iptables := utiliptables.New(execer, protocolv4)
ip6tables := utiliptables.New(execer, protocolv6)
return &MasqDaemon{
config: c,
iptables: iptables,
ip6tables: ip6tables,
config: c,
iptables: iptables,
ip6tables: ip6tables,
logReduction: logreduction.NewLogReduction(identicalLogDelay),
}
}

Expand Down Expand Up @@ -174,17 +179,17 @@ func (m *MasqDaemon) Run() {
defer time.Sleep(time.Duration(m.config.ResyncInterval))
// resync config
if err := m.osSyncConfig(); err != nil {
klog.Errorf("error syncing configuration: %v", err)
klog.Errorf("Error syncing configuration: %v", err)
return
}
// resync rules
if err := m.syncMasqRules(); err != nil {
klog.Errorf("error syncing masquerade rules: %v", err)
klog.Errorf("Error syncing masquerade rules: %v", err)
return
}
// resync ipv6 rules
if err := m.syncMasqRulesIPv6(); err != nil {
klog.Errorf("error syncing masquerade rules for ipv6: %v", err)
klog.Errorf("Error syncing masquerade rules for IPv6: %v", err)
return
}
}()
Expand All @@ -198,15 +203,30 @@ func (m *MasqDaemon) osSyncConfig() error {
return m.syncConfig(fs)
}

func (m *MasqDaemon) logVerbose(message string, parentID string) klog.Verbose {
if m.logReduction.ShouldMessageBePrinted(message, parentID) {
return klog.V(2)
}
return klog.V(4)
}

// Syncs the config to the file at ConfigPath, or uses defaults if the file could not be found
// Error if the file is found but cannot be parsed.
func (m *MasqDaemon) syncConfig(fs fakefs.FileSystem) error {
logSyncParentID := "config-sync"
logFileParentID := "config-file"

var yaml []byte
var err error
c := NewMasqConfig(*noMasqueradeAllReservedRangesFlag)
defer func() {
// Calculating verbosity here (outside the `if` below) and using `yaml`
// (instead of `json`) allows reprinting at file change (even if the parsed
// json doesn't change) as well as any error condition change.
v := m.logVerbose(fmt.Sprintf("%v\x00%s", err, yaml), logFileParentID)
if err == nil {
json, _ := utiljson.Marshal(c)
klog.V(2).Infof("using config: %s", string(json))
v.Infof("Using config: %s", string(json))
}
}()

Expand All @@ -218,13 +238,13 @@ func (m *MasqDaemon) syncConfig(fs fakefs.FileSystem) error {
m.config.MasqLinkLocal = c.MasqLinkLocal
m.config.MasqLinkLocalIPv6 = c.MasqLinkLocalIPv6
m.config.ResyncInterval = c.ResyncInterval
klog.V(2).Infof("no config file found at %q, using default values", configPath)
m.logVerbose("not-found", logSyncParentID).Infof("No config file found at %q, using default values.", configPath)
return nil
}
klog.V(2).Infof("config file found at %q", configPath)
m.logVerbose("found", logSyncParentID).Infof("Config file found at %q", configPath)

// file exists, read and parse file
yaml, err := fs.ReadFile(configPath)
yaml, err = fs.ReadFile(configPath)
if err != nil {
return err
}
Expand Down Expand Up @@ -287,6 +307,8 @@ func validateCIDR(cidr string) error {
}

func (m *MasqDaemon) syncMasqRules() error {
logParentID := "ipv4"

// make sure our custom chain for non-masquerade exists
if _, err := m.iptables.EnsureChain(utiliptables.TableNAT, masqChain); err != nil {
return err
Expand Down Expand Up @@ -318,6 +340,7 @@ func (m *MasqDaemon) syncMasqRules() error {
writeMasqRules(lines, toPorts)

writeLine(lines, "COMMIT")
m.logVerbose(lines.String(), logParentID).Infof("IPv4 masquerading rules: %q", lines)

if err := m.iptables.RestoreAll(lines.Bytes(), utiliptables.NoFlushTables, utiliptables.NoRestoreCounters); err != nil {
return err
Expand All @@ -327,40 +350,45 @@ func (m *MasqDaemon) syncMasqRules() error {

func (m *MasqDaemon) syncMasqRulesIPv6() error {
isIPv6Enabled := *enableIPv6
logParentID := "ipv6"

if isIPv6Enabled {
// make sure our custom chain for ipv6 non-masquerade exists
if _, err := m.ip6tables.EnsureChain(utiliptables.TableNAT, masqChain); err != nil {
return err
}
// ensure that any non-local in POSTROUTING jumps to masqChain
if err := m.ensurePostroutingJumpIPv6(); err != nil {
return err
}
// build up lines to pass to ip6tables-restore
lines6 := bytes.NewBuffer(nil)
writeLine(lines6, "*nat")
writeLine(lines6, utiliptables.MakeChainLine(masqChain)) // effectively flushes masqChain atomically with rule restore

// link-local IPv6 CIDR is non-masquerade by default
if !m.config.MasqLinkLocalIPv6 {
writeNonMasqRule(lines6, linkLocalCIDRIPv6)
}
if !isIPv6Enabled {
m.logVerbose("", logParentID).Infof("IPv6 masquerading rules: not enabled.")
return nil
}

for _, cidr := range m.config.NonMasqueradeCIDRs {
if isIPv6CIDR(cidr) {
writeNonMasqRule(lines6, cidr)
}
// make sure our custom chain for ipv6 non-masquerade exists
if _, err := m.ip6tables.EnsureChain(utiliptables.TableNAT, masqChain); err != nil {
return err
}
// ensure that any non-local in POSTROUTING jumps to masqChain
if err := m.ensurePostroutingJumpIPv6(); err != nil {
return err
}
// build up lines to pass to ip6tables-restore
lines6 := bytes.NewBuffer(nil)
writeLine(lines6, "*nat")
writeLine(lines6, utiliptables.MakeChainLine(masqChain)) // effectively flushes masqChain atomically with rule restore

// link-local IPv6 CIDR is non-masquerade by default
if !m.config.MasqLinkLocalIPv6 {
writeNonMasqRule(lines6, linkLocalCIDRIPv6)
}

for _, cidr := range m.config.NonMasqueradeCIDRs {
if isIPv6CIDR(cidr) {
writeNonMasqRule(lines6, cidr)
}
}

// masquerade all other traffic that is not bound for a --dst-type LOCAL destination
writeMasqRules(lines6, toPorts)
// masquerade all other traffic that is not bound for a --dst-type LOCAL destination
writeMasqRules(lines6, toPorts)

writeLine(lines6, "COMMIT")
writeLine(lines6, "COMMIT")
m.logVerbose(lines6.String(), logParentID).Infof("IPv6 masquerading rules: %q", lines6)

if err := m.ip6tables.RestoreAll(lines6.Bytes(), utiliptables.NoFlushTables, utiliptables.NoRestoreCounters); err != nil {
return err
}
if err := m.ip6tables.RestoreAll(lines6.Bytes(), utiliptables.NoFlushTables, utiliptables.NoRestoreCounters); err != nil {
return err
}
return nil
}
Expand Down
8 changes: 5 additions & 3 deletions cmd/ip-masq-agent/ip-masq-agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"testing"
"time"

"k8s.io/component-base/logs/logreduction"
"k8s.io/ip-masq-agent/cmd/ip-masq-agent/testing/fakefs"
"k8s.io/ip-masq-agent/pkg/interval"
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
Expand Down Expand Up @@ -93,9 +94,10 @@ func NewFakeMasqDaemon() *MasqDaemon {
},
}
return &MasqDaemon{
config: &MasqConfig{},
iptables: iptables,
ip6tables: ip6tables,
config: &MasqConfig{},
iptables: iptables,
ip6tables: ip6tables,
logReduction: logreduction.NewLogReduction(0),
}
}

Expand Down
78 changes: 78 additions & 0 deletions vendor/k8s.io/component-base/logs/logreduction/logreduction.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ k8s.io/component-base/logs
k8s.io/component-base/logs/api/v1
k8s.io/component-base/logs/internal/setverbositylevel
k8s.io/component-base/logs/klogflags
k8s.io/component-base/logs/logreduction
k8s.io/component-base/metrics
k8s.io/component-base/metrics/legacyregistry
k8s.io/component-base/metrics/prometheus/feature
Expand Down

0 comments on commit ea2d9db

Please sign in to comment.