Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.13 Backports 2024-05-06 #32386

Merged
merged 8 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 25 additions & 2 deletions .github/workflows/conformance-aks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ jobs:
yq -o=json "${work_dir}/k8s-versions.yaml" | jq . > "${destination_directory}/azure.json"

- name: Generate Matrix
id: set-matrix
run: |
cd /tmp/generated/azure

Expand All @@ -105,7 +104,31 @@ jobs:

echo "Generated matrix:"
cat /tmp/matrix.json
echo "matrix=$(jq -c . < /tmp/matrix.json)" >> $GITHUB_OUTPUT

- name: Login to Azure
uses: azure/login@6b2456866fc08b011acb422a92a4aa20e2c4de32 # v2.1.0
with:
creds: ${{ secrets.AZURE_PR_SP_CREDS }}

- name: Filter Matrix
id: set-matrix
run: |
cp /tmp/matrix.json /tmp/result.json
jq -c '.include[]' /tmp/matrix.json | while read i; do
VERSION=$(echo $i | jq -r '.version')
LOCATION=$(echo $i | jq -r '.location')
az aks get-versions --location $LOCATION > /tmp/output
if grep -q -F $VERSION /tmp/output; then
echo "Version $VERSION is valid for location $LOCATION"
else
echo "Removing version $VERSION as it's not valid for location $LOCATION"
jq 'del(.include[] | select(.version == "'$VERSION'"))' /tmp/result.json > /tmp/result.json.tmp
mv /tmp/result.json.tmp /tmp/result.json
fi
done
echo "Filtered matrix:"
cat /tmp/result.json
echo "matrix=$(jq -c . < /tmp/result.json)" >> $GITHUB_OUTPUT

installation-and-connectivity:
name: Installation and Connectivity Test
Expand Down
2 changes: 1 addition & 1 deletion daemon/cmd/fqdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ func (d *Daemon) notifyOnDNSMsg(lookupTime time.Time, ep *endpoint.Endpoint, epI

select {
case <-updateCtx.Done():
log.Error("Timed out waiting for datapath updates of FQDN IP information; returning response")
log.Warning("Timed out waiting for datapath updates of FQDN IP information; returning response. Consider increasing --tofqdns-proxy-response-max-delay if this keeps happening.")
metrics.ProxyDatapathUpdateTimeout.Inc()
case <-updateComplete:
}
Expand Down
51 changes: 44 additions & 7 deletions pkg/datapath/linux/ipsec/ipsec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"time"

"github.com/fsnotify/fsnotify"
"github.com/prometheus/procfs"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"

Expand Down Expand Up @@ -358,16 +359,11 @@ func xfrmStateReplace(new *netlink.XfrmState, remoteRebooted bool) error {
continue
}

err := netlink.XfrmStateDel(&s)
err, deferFn := xfrmTemporarilyRemoveState(scopedLog, s, dir)
if err != nil {
scopedLog.WithError(err).Errorf("Failed to remove old XFRM %s state", dir)
} else {
scopedLog.Infof("Temporarily removed old XFRM %s state", dir)
defer func(oldXFRMState netlink.XfrmState, dir string) {
if err := netlink.XfrmStateAdd(&oldXFRMState); err != nil {
scopedLog.WithError(err).Errorf("Failed to re-add old XFRM %s state", dir)
}
}(s, dir)
defer deferFn()
}
}
}
Expand All @@ -394,6 +390,47 @@ func xfrmStateReplace(new *netlink.XfrmState, remoteRebooted bool) error {
return netlink.XfrmStateAdd(new)
}

// Temporarily remove an XFRM state to allow the addition of another,
// conflicting XFRM state. This function removes the conflicting state and
// prepares a defer callback to re-add it with proper logging.
func xfrmTemporarilyRemoveState(scopedLog *logrus.Entry, state netlink.XfrmState, dir string) (error, func()) {
stats, err := procfs.NewXfrmStat()
errorCnt := 0
if err != nil {
log.WithError(err).Error("Error while getting XFRM stats before state removal")
} else {
if dir == "IN" {
errorCnt = stats.XfrmInNoStates
} else {
errorCnt = stats.XfrmOutNoStates
}
}

start := time.Now()
if err := netlink.XfrmStateDel(&state); err != nil {
return err, nil
}
return nil, func() {
if err := netlink.XfrmStateAdd(&state); err != nil {
scopedLog.WithError(err).Errorf("Failed to re-add old XFRM %s state", dir)
}
elapsed := time.Since(start)

stats, err := procfs.NewXfrmStat()
if err != nil {
log.WithError(err).Error("Error while getting XFRM stats after state removal")
errorCnt = 0
} else {
if dir == "IN" {
errorCnt = stats.XfrmInNoStates - errorCnt
} else {
errorCnt = stats.XfrmOutNoStates - errorCnt
}
}
scopedLog.WithField(logfields.Duration, elapsed).Infof("Temporarily removed old XFRM %s state (%d packets dropped)", dir, errorCnt)
}
}

// Attempt to remove any XFRM state that conflicts with the state we just tried
// to add. To find those conflicting states, we need to use the same logic that
// the kernel used to reject our check with EEXIST. That logic is upstream in
Expand Down
13 changes: 13 additions & 0 deletions pkg/fqdn/dnsproxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ func (p *DNSProxy) checkRestored(endpointID uint64, destPortProto restore.PortPr
if !exists && destPortProto.IsPortV2() {
// Check if there is a Version 1 restore.
ipRules, exists = p.restored[endpointID][destPortProto.ToV1()]
log.WithFields(logrus.Fields{
logfields.EndpointID: endpointID,
logfields.Port: destPortProto.Port(),
logfields.Protocol: destPortProto.Protocol(),
}).Debugf("Checking if restored V1 IP rules (exists: %t) for endpoint: %+v", exists, ipRules)
if !exists {
return false
}
Expand Down Expand Up @@ -517,6 +522,14 @@ func (allow perEPAllow) setPortRulesForIDFromUnifiedFormat(cache regexCache, end
// passed-in endpointID and destPort with setPortRulesForID
func (allow perEPAllow) getPortRulesForID(endpointID uint64, destPortProto restore.PortProto) (rules CachedSelectorREEntry, exists bool) {
rules, exists = allow[endpointID][destPortProto]
if !exists && destPortProto.Protocol() != 0 {
rules, exists = allow[endpointID][destPortProto.ToV1()]
log.WithFields(logrus.Fields{
logfields.EndpointID: endpointID,
logfields.Port: destPortProto.Port(),
logfields.Protocol: destPortProto.Protocol(),
}).Debugf("Checking for V1 port rule (exists: %t) for endpoint: %+v", exists, rules)
}
return
}

Expand Down
20 changes: 12 additions & 8 deletions pkg/policy/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,22 +570,26 @@ func (r *rule) resolveIngressPolicy(
func (r *rule) matches(securityIdentity *identity.Identity) bool {
r.metadata.Mutex.Lock()
defer r.metadata.Mutex.Unlock()
var ruleMatches bool
isNode := securityIdentity.ID == identity.ReservedIdentityHost

if ruleMatches, cached := r.metadata.IdentitySelected[securityIdentity.ID]; cached {
return ruleMatches
}
isNode := securityIdentity.ID == identity.ReservedIdentityHost

// Short-circuit if the rule's selector type (node vs. endpoint) does not match the
// identity's type
if (r.NodeSelector.LabelSelector != nil) != isNode {
r.metadata.IdentitySelected[securityIdentity.ID] = false
return ruleMatches
return false
}

// Fall back to costly matching.
if ruleMatches = r.getSelector().Matches(securityIdentity.LabelArray); ruleMatches {
// Update cache so we don't have to do costly matching again.
r.metadata.IdentitySelected[securityIdentity.ID] = true
} else {
r.metadata.IdentitySelected[securityIdentity.ID] = false
ruleMatches := r.getSelector().Matches(securityIdentity.LabelArray)

// Update cache so we don't have to do costly matching again.
// the local Host identity has mutable labels, so we cannot use the cache
if !isNode {
r.metadata.IdentitySelected[securityIdentity.ID] = ruleMatches
}

return ruleMatches
Expand Down
17 changes: 15 additions & 2 deletions pkg/policy/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2603,10 +2603,23 @@ func (ds *PolicyTestSuite) TestMatches(c *C) {
c.Assert(hostRule.matches(selectedIdentity), Equals, false)
c.Assert(hostRule.metadata.IdentitySelected, checker.DeepEquals, map[identity.NumericIdentity]bool{selectedIdentity.ID: false})

// host endpoint is selected by rule, so we it should be added to EndpointsSelected.
// host endpoint is selected by rule, but host labels are mutable, so don't cache them
c.Assert(hostRule.matches(hostIdentity), Equals, true)
c.Assert(hostRule.metadata.IdentitySelected, checker.DeepEquals,
map[identity.NumericIdentity]bool{selectedIdentity.ID: false, hostIdentity.ID: true})
map[identity.NumericIdentity]bool{selectedIdentity.ID: false})

// Assert that mutable host identities are handled
// First, add an additional label, ensure that match succeeds
hostLabels.MergeLabels(labels.NewLabelsFromModel([]string{"foo=bar"}))
hostIdentity = identity.NewIdentity(identity.ReservedIdentityHost, hostLabels)
c.Assert(hostRule.matches(hostIdentity), Equals, true)

// Then, change host to id=c, which is not selected, and ensure match is correct
hostIdentity = identity.NewIdentity(identity.ReservedIdentityHost, labels.NewLabelsFromModel([]string{"id=c"}))
c.Assert(hostRule.matches(hostIdentity), Equals, false)
c.Assert(hostRule.metadata.IdentitySelected, checker.DeepEquals,
map[identity.NumericIdentity]bool{selectedIdentity.ID: false})

}

func BenchmarkRuleString(b *testing.B) {
Expand Down
2 changes: 1 addition & 1 deletion plugins/cilium-cni/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func interfaceAdd(ipConfig *current.IPConfig, ipam *models.IPAMAddressResponse,

if err := routingInfo.Configure(
ipConfig.Address.IP,
int(conf.DeviceMTU),
int(conf.RouteMTU),
conf.EgressMultiHomeIPRuleCompat,
false,
); err != nil {
Expand Down