Skip to content

Commit

Permalink
datapath/linux: make sure we have a local rule with proto kernel
Browse files Browse the repository at this point in the history
Add a check on agent startup which ensures that a local lookup rule with
proto kernel exists and also cleans up an old local proto unspec rule in
case it exists and is before the new rule because rule deletion doesn't
take protocol into account, i.e. "rule del pref 100 proto kernel" will
delete a pref 100 proto unspec if it was added before the proto kernel
one. Check for the rule only if the proxy rule is also present,
otherwise init.sh won't have to move it.

Signed-off-by: Nikolay Aleksandrov <nikolay@isovalent.com>
  • Loading branch information
Nikolay Aleksandrov authored and youngnick committed Mar 25, 2023
1 parent 9e3abdf commit 291852a
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
4 changes: 4 additions & 0 deletions daemon/cmd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ func (d *Daemon) init() error {
return fmt.Errorf("failed while reinitializing datapath: %w", err)
}

if err := linuxdatapath.NodeEnsureLocalIPRule(); err != nil {
return fmt.Errorf("failed to ensure local IP rules: %w", err)
}

if option.Config.SockopsEnable {
eppolicymap.CreateEPPolicyMap()
if err := sockops.SockmapEnable(); err != nil {
Expand Down
87 changes: 87 additions & 0 deletions pkg/datapath/linux/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1883,3 +1883,90 @@ func NodeDeviceNameWithDefaultRoute() (string, error) {
}
return link.Attrs().Name, nil
}

func deleteOldLocalRule(rule route.Rule, family int) error {
var familyStr string

// sanity check, nothing to do if the rule is the same
if linux_defaults.RTProto == unix.RTPROT_UNSPEC {
return nil
}

if family == netlink.FAMILY_V4 {
familyStr = "IPv4"
} else {
familyStr = "IPv6"
}

localRules, err := route.ListRules(family, &rule)
if err != nil {
return fmt.Errorf("could not list local %s rules: %w", familyStr, err)
}

// we need to check for the old rule and make sure it's before the new one
oldPos := -1
found := false
for pos, rule := range localRules {
// mark the first unspec rule that matches
if oldPos == -1 && rule.Protocol == unix.RTPROT_UNSPEC {
oldPos = pos
}

if rule.Protocol == linux_defaults.RTProto {
// mark it as found only if it's before the new one
if oldPos != -1 {
found = true
}
break
}
}

if found == true {
err := route.DeleteRule(rule)
if err != nil {
return fmt.Errorf("could not delete old %s local rule: %w", familyStr, err)
}
log.WithFields(logrus.Fields{"family": familyStr}).Info("Deleting old local lookup rule")
}

return nil
}

// NodeEnsureLocalIPRule checks if Cilium local lookup rule (usually 100)
// was installed and has proper protocol
func NodeEnsureLocalIPRule() error {
// we have the Cilium local lookup rule only if the proxy rule is present
if !option.Config.InstallIptRules || !option.Config.EnableL7Proxy {
return nil
}

localRule := route.Rule{Priority: linux_defaults.RulePriorityLocalLookup, Table: unix.RT_TABLE_LOCAL, Mark: -1, Mask: -1, Protocol: linux_defaults.RTProto}
oldRule := localRule
oldRule.Protocol = unix.RTPROT_UNSPEC

if option.Config.EnableIPv4 {
err := route.ReplaceRule(localRule)
if err != nil {
return fmt.Errorf("could not replace IPv4 local rule: %w", err)
}

err = deleteOldLocalRule(oldRule, netlink.FAMILY_V4)
if err != nil {
return err
}
}

if option.Config.EnableIPv6 {
err := route.ReplaceRuleIPv6(localRule)
if err != nil {
return fmt.Errorf("could not replace IPv6 local rule: %w", err)
}

err = deleteOldLocalRule(oldRule, netlink.FAMILY_V6)
if err != nil {
return err
}
}

return nil
}

0 comments on commit 291852a

Please sign in to comment.