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

fix(policy): use new compute for rules and fix rules intersect #12340

Merged
merged 13 commits into from
Jan 10, 2025
3 changes: 1 addition & 2 deletions pkg/core/xds/inspect/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ func getOutboundRuleAttachments(rules core_rules.Rules, networking *mesh_proto.D
}
attachment := byUniqueClusterName[name]
if attachment == nil {
subset := core_rules.SubsetFromTags(outboundTags)
computedRule := rules.Compute(subset)
computedRule := rules.Compute(core_rules.Element(outboundTags))
if computedRule == nil {
continue
}
Expand Down
108 changes: 103 additions & 5 deletions pkg/plugins/policies/core/rules/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,58 @@ func NewSubset(m map[string]string) Subset {
return s
}

// ContainsElement returns true if there exists a key in 'other' that matches the current set,
// also the corresponding k-v pair must match the set rule.
// Empty set is a superset for all elements.
//
// For example if you have a Subset with Tags: [{key: zone, value: east, not: true}, {key: service, value: frontend, not: false}]
// an Element with k-v pairs: 1) service: frontend 2) version: zone1
// there's a k-v pair 'service: frontend' in Element that matches the Subset Tag rule {key: service, value: frontend, not: false}
func (ss Subset) ContainsElement(other Element) bool {
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved
// 1. find the overlaps of element and current subset
// 2. verify the overlaps
// 3. verify the left of current subset

if len(ss) == 0 {
return true
}
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved
if len(other) == 0 {
return false
}

hasOverlapKey := false
for _, tag := range ss {
tmpVal, ok := other[tag.Key]
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved
if ok {
hasOverlapKey = true

// contradict
if tag.Value == tmpVal && tag.Not {
return false
}
// intersect
if tag.Value == tmpVal && !tag.Not {
continue
}
// intersect
if tag.Value != tmpVal && tag.Not {
continue
}
// contradict
if tag.Value != tmpVal && !tag.Not {
return false
}
} else if !tag.Not {
// For those items that don't exist in element should not make an impact.
// For example, the DP with tag {"service: frontend"} doesn't match
// the policy with matching tags [{"service: frontend"}, {"zone": "east"}]
return false
}
}

return hasOverlapKey
}

// IsSubset returns true if 'other' is a subset of the current set.
// Empty set is a superset for all subsets.
func (ss Subset) IsSubset(other Subset) bool {
Expand Down Expand Up @@ -196,7 +248,7 @@ func (ss Subset) Intersect(other Subset) bool {
}
oTags, ok := otherByKeysOnlyPositive[tag.Key]
if !ok {
return true
continue
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved
}
for _, otherTag := range oTags {
if otherTag != tag {
Expand Down Expand Up @@ -235,6 +287,29 @@ func SubsetFromTags(tags map[string]string) Subset {
return subset
}

type Element map[string]string

func (e Element) WithKeyValue(key, value string) Element {
if e == nil {
e = Element{}
}

e[key] = value
return e
}

func MeshElement() Element {
return Element{}
}

func MeshServiceElement(name string) Element {
return Element{mesh_proto.ServiceTag: name}
}

func MeshExternalServiceElement(name string) Element {
return Element{mesh_proto.ServiceTag: name}
}
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved

// NumPositive returns a number of tags without negation
func (ss Subset) NumPositive() int {
pos := 0
Expand Down Expand Up @@ -290,8 +365,29 @@ func (r *Rule) GetBackendRefOrigin(hash common_api.MatchesHash) (core_model.Reso

type Rules []*Rule

// Compute returns configuration for the given subset.
func (rs Rules) Compute(sub Subset) *Rule {
// Compute returns Rule for the given element.
func (rs Rules) Compute(element Element) *Rule {
for _, rule := range rs {
if rule.Subset.ContainsElement(element) {
return rule
}
}
return nil
}

// ComputeConf returns configuration for the given element.
func ComputeConf[T any](rs Rules, element Element) *T {
computed := rs.Compute(element)
if computed != nil {
return pointer.To(computed.Conf.(T))
}

return nil
}

// LegacyCompute returns Rule for the given subset.
// Deprecated: use Compute instead
func (rs Rules) LegacyCompute(sub Subset) *Rule {
Icarus9913 marked this conversation as resolved.
Show resolved Hide resolved
for _, rule := range rs {
if rule.Subset.IsSubset(sub) {
return rule
Expand All @@ -300,8 +396,10 @@ func (rs Rules) Compute(sub Subset) *Rule {
return nil
}

func ComputeConf[T any](rs Rules, sub Subset) *T {
if computed := rs.Compute(sub); computed != nil {
// LegacyComputeConf returns configuration for the given subset.
// Deprecated: use ComputeConf instead
func LegacyComputeConf[T any](rs Rules, sub Subset) *T {
if computed := rs.LegacyCompute(sub); computed != nil {
return pointer.To(computed.Conf.(T))
}
return nil
Expand Down
Loading
Loading