-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Modify IPSet Setfilter to make it suitable for filtering ipsets dynamically #9669
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,8 @@ type bpfIPSets struct { | |
opRecorder logutils.OpRecorder | ||
|
||
lg *log.Entry | ||
|
||
filterIPSet func(string) bool | ||
} | ||
|
||
func NewBPFIPSets( | ||
|
@@ -133,6 +135,14 @@ func (m *bpfIPSets) deleteIPSetAndReleaseID(ipSet *bpfIPSet) { | |
// to ApplyUpdates(), the IP sets will be replaced with the new contents and the set's metadata | ||
// will be updated as appropriate. | ||
func (m *bpfIPSets) AddOrReplaceIPSet(setMetadata ipsets.IPSetMetadata, members []string) { | ||
if m.filterIPSet != nil && !m.filterIPSet(setMetadata.SetID) { | ||
ipSet := m.getExistingIPSetString(setMetadata.SetID) | ||
if ipSet != nil { | ||
ipSet.Deleted = true | ||
m.markIPSetDirty(ipSet) | ||
} | ||
return | ||
} | ||
ipSet := m.getOrCreateIPSet(setMetadata.SetID) | ||
ipSet.Type = setMetadata.Type | ||
m.lg.WithFields(log.Fields{"stringID": setMetadata.SetID, "uint64ID": ipSet.ID, "members": members}).Info("IP set added") | ||
|
@@ -370,9 +380,11 @@ func (m *bpfIPSets) markIPSetDirty(data *bpfIPSet) { | |
m.dirtyIPSetIDs.Add(data.ID) | ||
} | ||
|
||
func (m *bpfIPSets) SetFilter(ipSetNames set.Set[string]) { | ||
// Not needed for this IP set dataplane. All known IP sets | ||
// are written into the corresponding BPF map. | ||
func (m *bpfIPSets) SetFilter(fn func(ipSetName string) bool) { | ||
m.filterIPSet = fn | ||
} | ||
|
||
func (m *bpfIPSets) MarkDirty(ipsetNames set.Set[string]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel a bit uneasy that we have a flexible filter function but we're not implementing the rescan here. Someone could come along later and use the filter function without realising this isn't implemented. Should at least comment "Not implemented because the only filter we use with this IP set is 100% static, based on the IP set name." |
||
} | ||
|
||
type bpfIPSet struct { | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -770,7 +770,12 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { | |||||||||||
bpfutils.RemoveBPFSpecialDevices() | ||||||||||||
} else { | ||||||||||||
// In BPF mode we still use iptables for raw egress policy. | ||||||||||||
dp.RegisterManager(newRawEgressPolicyManager(rawTableV4, ruleRenderer, 4, ipSetsV4.SetFilter, config.RulesConfig.NFTables)) | ||||||||||||
mgr := newRawEgressPolicyManager(rawTableV4, ruleRenderer, 4, ipSetsV4.MarkDirty, config.RulesConfig.NFTables) | ||||||||||||
ipSetsV4.SetFilter(func(ipSetName string) bool { | ||||||||||||
neededIPSets := mgr.GetNeededIPSets() | ||||||||||||
return neededIPSets.Contains(ipSetName) | ||||||||||||
}) | ||||||||||||
dp.RegisterManager(mgr) | ||||||||||||
} | ||||||||||||
|
||||||||||||
interfaceRegexes := make([]string, len(config.RulesConfig.WorkloadIfacePrefixes)) | ||||||||||||
|
@@ -1035,7 +1040,12 @@ func NewIntDataplaneDriver(config Config) *InternalDataplane { | |||||||||||
config.MaxIPSetSize)) | ||||||||||||
dp.RegisterManager(newPolicyManager(rawTableV6, mangleTableV6, filterTableV6, ruleRenderer, 6, config.RulesConfig.NFTables)) | ||||||||||||
} else { | ||||||||||||
dp.RegisterManager(newRawEgressPolicyManager(rawTableV6, ruleRenderer, 6, ipSetsV6.SetFilter, config.RulesConfig.NFTables)) | ||||||||||||
mgr := newRawEgressPolicyManager(rawTableV6, ruleRenderer, 6, ipSetsV6.MarkDirty, config.RulesConfig.NFTables) | ||||||||||||
ipSetsV6.SetFilter(func(ipSetName string) bool { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth a comment here saying what this filter stuff is about.
Suggested change
|
||||||||||||
neededIPSets := mgr.GetNeededIPSets() | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a very inefficient way to do this check. Every call to the filter will build the full "needed sets" However, now you've switched to a "pull" model for this, you should be able to do a lot better. What if you made the API |
||||||||||||
return neededIPSets.Contains(ipSetName) | ||||||||||||
}) | ||||||||||||
dp.RegisterManager(mgr) | ||||||||||||
} | ||||||||||||
|
||||||||||||
dp.RegisterManager(newEndpointManager( | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,6 +193,8 @@ func (m *IPSets) ApplyDeletions() bool { | |
return false | ||
} | ||
|
||
func (s *IPSets) SetFilter(ipSetNames set.Set[string]) { | ||
// Not needed for Windows. | ||
func (m *IPSets) SetFilter(fn func(ipSetName string) bool) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth commenting that these are deliberately not implemented |
||
} | ||
|
||
func (m *IPSets) MarkDirty(ipsetNames set.Set[string]) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,7 +99,7 @@ type IPSets struct { | |
|
||
// Optional filter. When non-nil, only these IP set IDs will be rendered into the dataplane | ||
// as Linux IP sets. | ||
neededIPSetNames set.Set[string] | ||
filterIPSet func(string) bool | ||
} | ||
|
||
func NewIPSets(ipVersionConfig *IPVersionConfig, recorder logutils.OpRecorder) *IPSets { | ||
|
@@ -1092,31 +1092,29 @@ func (s *IPSets) updateDirtiness(name string) { | |
} | ||
} | ||
|
||
func (s *IPSets) SetFilter(ipSetNames set.Set[string]) { | ||
oldSetNames := s.neededIPSetNames | ||
if oldSetNames == nil && ipSetNames == nil { | ||
return | ||
} | ||
s.logCxt.Debugf("Filtering to needed IP set names: %v", ipSetNames) | ||
s.neededIPSetNames = ipSetNames | ||
for name, meta := range s.setNameToAllMetadata { | ||
if s.ipSetNeeded(name) { | ||
s.setNameToProgrammedMetadata.Desired().Set(name, meta) | ||
} else { | ||
s.setNameToProgrammedMetadata.Desired().Delete(name) | ||
} | ||
s.updateDirtiness(name) | ||
} | ||
func (s *IPSets) SetFilter(fn func(string) bool) { | ||
s.filterIPSet = fn | ||
} | ||
|
||
func (s *IPSets) ipSetNeeded(name string) bool { | ||
if s.neededIPSetNames == nil { | ||
if s.filterIPSet == nil { | ||
// We're not filtering down to a "needed" set, so all IP sets are needed. | ||
return true | ||
} | ||
|
||
// We are filtering down, so compare against the needed set. | ||
return s.neededIPSetNames.Contains(name) | ||
return s.filterIPSet(name) | ||
} | ||
|
||
func (s *IPSets) MarkDirty(ipsetNames set.Set[string]) { | ||
for name, meta := range s.setNameToAllMetadata { | ||
if ipsetNames.Contains(name) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now the wrong check because |
||
s.setNameToProgrammedMetadata.Desired().Set(name, meta) | ||
} else { | ||
s.setNameToProgrammedMetadata.Desired().Delete(name) | ||
} | ||
s.updateDirtiness(name) | ||
} | ||
} | ||
|
||
// CanonicaliseMember converts the string representation of an IP set member to a canonical | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,7 +97,7 @@ type IPSets struct { | |
|
||
// Optional filter. When non-nil, only these IP set IDs will be rendered into the dataplane | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of date comment |
||
// as Linux IP sets. | ||
neededIPSetNames set.Set[string] | ||
filterIPSet func(string) bool | ||
|
||
nft knftables.Interface | ||
} | ||
|
@@ -781,15 +781,13 @@ func (s *IPSets) updateDirtiness(name string) { | |
} | ||
} | ||
|
||
func (s *IPSets) SetFilter(ipSetNames set.Set[string]) { | ||
oldSetNames := s.neededIPSetNames | ||
if oldSetNames == nil && ipSetNames == nil { | ||
return | ||
} | ||
s.logCxt.Debugf("Filtering to needed IP set names: %v", ipSetNames) | ||
s.neededIPSetNames = ipSetNames | ||
func (s *IPSets) SetFilter(fn func(ipSetName string) bool) { | ||
s.filterIPSet = fn | ||
} | ||
|
||
func (s *IPSets) MarkDirty(ipsetNames set.Set[string]) { | ||
for name, meta := range s.setNameToAllMetadata { | ||
if s.ipSetNeeded(name) { | ||
if ipsetNames.Contains(name) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, new filter func should govern the check. |
||
s.setNameToProgrammedMetadata.Desired().Set(name, meta) | ||
} else { | ||
s.setNameToProgrammedMetadata.Desired().Delete(name) | ||
|
@@ -799,13 +797,13 @@ func (s *IPSets) SetFilter(ipSetNames set.Set[string]) { | |
} | ||
|
||
func (s *IPSets) ipSetNeeded(name string) bool { | ||
if s.neededIPSetNames == nil { | ||
if s.filterIPSet == nil { | ||
// We're not filtering down to a "needed" set, so all IP sets are needed. | ||
return true | ||
} | ||
|
||
// We are filtering down, so compare against the needed set. | ||
return s.neededIPSetNames.Contains(name) | ||
return s.filterIPSet(name) | ||
} | ||
|
||
// CanonicaliseMember converts the string representation of an nftables set member to a canonical | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth a comment saying what this does. In particular:
nil
mean?true
"filter in" or "filter out"