Skip to content

Commit 779e965

Browse files
authored
[NPM] generic Policy Manager and some windows specific policy updates (#1045)
* removing some redundant info * Adding some policy related changes * initial pass on some update pod dependencies * adding update pod logic * cleaning up some unused code * Adding some basic test cases * Correcting some test cases * fixing a testcase * correcting some golints * fixing a test * Fixing some golints: * Addressing a comment
1 parent 1b86e8d commit 779e965

15 files changed

+1069
-185
lines changed

npm/pkg/dataplane/dataplane.go

Lines changed: 194 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,53 @@ package dataplane
33
import (
44
"fmt"
55

6-
"github.com/Azure/azure-container-networking/npm"
76
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
87
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/policies"
8+
npmerrors "github.com/Azure/azure-container-networking/npm/util/errors"
9+
"k8s.io/klog"
10+
)
11+
12+
const (
13+
// AzureNetworkName is default network Azure CNI creates
14+
AzureNetworkName = "azure"
915
)
1016

1117
type DataPlane struct {
1218
policyMgr *policies.PolicyManager
1319
ipsetMgr *ipsets.IPSetManager
1420
networkID string
21+
nodeName string
1522
// key is PodKey
1623
endpointCache map[string]*NPMEndpoint
1724
}
1825

1926
type NPMEndpoint struct {
2027
Name string
2128
ID string
29+
IP string
2230
// Map with Key as Network Policy name to to emulate set
2331
// and value as struct{} for minimal memory consumption
2432
NetPolReference map[string]struct{}
2533
}
2634

27-
func NewDataPlane() *DataPlane {
35+
// UpdateNPMPod pod controller will populate and send this datastructure to dataplane
36+
// to update the dataplane with the latest pod information
37+
// this helps in calculating if any update needs to have policies applied or removed
38+
type UpdateNPMPod struct {
39+
Name string
40+
Namespace string
41+
PodIP string
42+
NodeName string
43+
IPSetsToAdd []string
44+
IPSetsToRemove []string
45+
}
46+
47+
func NewDataPlane(nodeName string) *DataPlane {
2848
return &DataPlane{
2949
policyMgr: policies.NewPolicyManager(),
30-
ipsetMgr: ipsets.NewIPSetManager(),
50+
ipsetMgr: ipsets.NewIPSetManager(AzureNetworkName),
3151
endpointCache: make(map[string]*NPMEndpoint),
52+
nodeName: nodeName,
3253
}
3354
}
3455

@@ -44,22 +65,14 @@ func (dp *DataPlane) ResetDataPlane() error {
4465
}
4566

4667
// CreateIPSet takes in a set object and updates local cache with this set
47-
func (dp *DataPlane) CreateIPSet(setName string, setType ipsets.SetType) error {
48-
err := dp.ipsetMgr.CreateIPSet(setName, setType)
49-
if err != nil {
50-
return fmt.Errorf("[DataPlane] error while creating set: %w", err)
51-
}
52-
return nil
68+
func (dp *DataPlane) CreateIPSet(setName string, setType ipsets.SetType) {
69+
dp.ipsetMgr.CreateIPSet(setName, setType)
5370
}
5471

5572
// DeleteSet checks for members and references of the given "set" type ipset
5673
// if not used then will delete it from cache
57-
func (dp *DataPlane) DeleteIPSet(name string) error {
58-
err := dp.ipsetMgr.DeleteIPSet(name)
59-
if err != nil {
60-
return fmt.Errorf("[DataPlane] error while deleting set: %w", err)
61-
}
62-
return nil
74+
func (dp *DataPlane) DeleteIPSet(name string) {
75+
dp.ipsetMgr.DeleteIPSet(name)
6376
}
6477

6578
// AddToSet takes in a list of IPSet names along with IP member
@@ -102,8 +115,14 @@ func (dp *DataPlane) RemoveFromList(listName string, setNames []string) error {
102115
return nil
103116
}
104117

118+
// ShouldUpdatePod will let controller know if its needs to aggregate pod data for update pod call.
119+
func (dp *DataPlane) ShouldUpdatePod() bool {
120+
return dp.shouldUpdatePod()
121+
}
122+
105123
// UpdatePod is to be called by pod_controller ONLY when a new pod is CREATED.
106-
func (dp *DataPlane) UpdatePod(pod *npm.NpmPod) error {
124+
func (dp *DataPlane) UpdatePod(pod *UpdateNPMPod) error {
125+
// TODO check pod is in this Node if yes continue
107126
err := dp.updatePod(pod)
108127
if err != nil {
109128
return fmt.Errorf("[DataPlane] error while updating pod: %w", err)
@@ -125,8 +144,34 @@ func (dp *DataPlane) ApplyDataPlane() error {
125144
}
126145

127146
// AddPolicy takes in a translated NPMNetworkPolicy object and applies on dataplane
128-
func (dp *DataPlane) AddPolicy(policies *policies.NPMNetworkPolicy) error {
129-
err := dp.policyMgr.AddPolicy(policies)
147+
func (dp *DataPlane) AddPolicy(policy *policies.NPMNetworkPolicy) error {
148+
klog.Infof("[DataPlane] Add Policy called for %s", policy.Name)
149+
// Create and add references for Selector IPSets first
150+
err := dp.addIPSetReferences(policy.PodSelectorIPSets, policy.Name, ipsets.SelectorType)
151+
if err != nil {
152+
klog.Infof("[DataPlane] error while adding Selector IPSet references: %s", err.Error())
153+
return fmt.Errorf("[DataPlane] error while adding Selector IPSet references: %w", err)
154+
}
155+
156+
// Create and add references for Rule IPSets
157+
err = dp.addIPSetReferences(policy.RuleIPSets, policy.Name, ipsets.NetPolType)
158+
if err != nil {
159+
klog.Infof("[DataPlane] error while adding Rule IPSet references: %s", err.Error())
160+
return fmt.Errorf("[DataPlane] error while adding Rule IPSet references: %w", err)
161+
}
162+
163+
err = dp.ApplyDataPlane()
164+
if err != nil {
165+
return fmt.Errorf("[DataPlane] error while applying dataplane: %w", err)
166+
}
167+
// TODO calculate endpoints to apply policy on
168+
endpointList, err := dp.getEndpointsToApplyPolicy(policy)
169+
if err != nil {
170+
return err
171+
}
172+
173+
policy.PodEndpoints = endpointList
174+
err = dp.policyMgr.AddPolicy(policy, nil)
130175
if err != nil {
131176
return fmt.Errorf("[DataPlane] error while adding policy: %w", err)
132177
}
@@ -135,19 +180,147 @@ func (dp *DataPlane) AddPolicy(policies *policies.NPMNetworkPolicy) error {
135180

136181
// RemovePolicy takes in network policy name and removes it from dataplane and cache
137182
func (dp *DataPlane) RemovePolicy(policyName string) error {
138-
err := dp.policyMgr.RemovePolicy(policyName)
183+
klog.Infof("[DataPlane] Remove Policy called for %s", policyName)
184+
// because policy Manager will remove from policy from cache
185+
// keep a local copy to remove references for ipsets
186+
policy, ok := dp.policyMgr.GetPolicy(policyName)
187+
if !ok {
188+
klog.Infof("[DataPlane] Policy %s is not found. Might been deleted already", policyName)
189+
return nil
190+
}
191+
// Use the endpoint list saved in cache for this network policy to remove
192+
err := dp.policyMgr.RemovePolicy(policy.Name, nil)
139193
if err != nil {
140194
return fmt.Errorf("[DataPlane] error while removing policy: %w", err)
141195
}
196+
// Remove references for Rule IPSets first
197+
err = dp.deleteIPSetReferences(policy.RuleIPSets, policy.Name, ipsets.NetPolType)
198+
if err != nil {
199+
return err
200+
}
201+
202+
// Remove references for Selector IPSets
203+
err = dp.deleteIPSetReferences(policy.PodSelectorIPSets, policy.Name, ipsets.SelectorType)
204+
if err != nil {
205+
return err
206+
}
207+
208+
err = dp.ApplyDataPlane()
209+
if err != nil {
210+
return fmt.Errorf("[DataPlane] error while applying dataplane: %w", err)
211+
}
212+
142213
return nil
143214
}
144215

145216
// UpdatePolicy takes in updated policy object, calculates the delta and applies changes
146217
// onto dataplane accordingly
147-
func (dp *DataPlane) UpdatePolicy(policies *policies.NPMNetworkPolicy) error {
148-
err := dp.policyMgr.UpdatePolicy(policies)
218+
func (dp *DataPlane) UpdatePolicy(policy *policies.NPMNetworkPolicy) error {
219+
klog.Infof("[DataPlane] Update Policy called for %s", policy.Name)
220+
ok := dp.policyMgr.PolicyExists(policy.Name)
221+
if !ok {
222+
klog.Infof("[DataPlane] Policy %s is not found. Might been deleted already", policy.Name)
223+
return dp.AddPolicy(policy)
224+
}
225+
226+
// TODO it would be ideal to calculate a diff of policies
227+
// and remove/apply only the delta of IPSets and policies
228+
229+
// Taking the easy route here, delete existing policy
230+
err := dp.policyMgr.RemovePolicy(policy.Name, nil)
149231
if err != nil {
150232
return fmt.Errorf("[DataPlane] error while updating policy: %w", err)
151233
}
234+
// and add the new updated policy
235+
err = dp.policyMgr.AddPolicy(policy, nil)
236+
if err != nil {
237+
return fmt.Errorf("[DataPlane] error while updating policy: %w", err)
238+
}
239+
return nil
240+
}
241+
242+
func (dp *DataPlane) addIPSetReferences(sets map[string]*ipsets.IPSet, netpolName string, referenceType ipsets.ReferenceType) error {
243+
// Create IPSets first along with reference updates
244+
for _, set := range sets {
245+
dp.ipsetMgr.CreateIPSet(set.Name, set.Type)
246+
err := dp.ipsetMgr.AddReference(set.Name, netpolName, referenceType)
247+
if err != nil {
248+
npmErrorString := npmerrors.AddSelectorReference
249+
if referenceType == ipsets.NetPolType {
250+
npmErrorString = npmerrors.AddNetPolReference
251+
}
252+
return npmerrors.Errorf(npmErrorString, false, fmt.Sprintf("[dataplane] failed to add reference with err: %s", err.Error()))
253+
}
254+
}
255+
256+
// TODO is there a possibility for a list set of selector referencing rule ipset?
257+
// if so this below addition would throw an error because rule ipsets are not created
258+
// Check if any list sets are provided with members to add
259+
for _, set := range sets {
260+
// Check if any 2nd level IPSets are generated by Controller with members
261+
// Apply members to the list set
262+
if set.Kind == ipsets.ListSet {
263+
if len(set.MemberIPSets) > 0 {
264+
memberList := []string{}
265+
for _, memberSet := range set.MemberIPSets {
266+
memberList = append(memberList, memberSet.Name)
267+
}
268+
err := dp.ipsetMgr.AddToList(set.Name, memberList)
269+
if err != nil {
270+
npmErrorString := npmerrors.AddSelectorReference
271+
if referenceType == ipsets.NetPolType {
272+
npmErrorString = npmerrors.AddNetPolReference
273+
}
274+
return npmerrors.Errorf(npmErrorString, false, fmt.Sprintf("[dataplane] failed to AddToList in addIPSetReferences with err: %s", err.Error()))
275+
276+
}
277+
}
278+
}
279+
}
280+
281+
return nil
282+
}
283+
284+
func (dp *DataPlane) deleteIPSetReferences(sets map[string]*ipsets.IPSet, netpolName string, referenceType ipsets.ReferenceType) error {
285+
for _, set := range sets {
286+
// TODO ignore set does not exist error
287+
// TODO add delete ipset after removing members
288+
err := dp.ipsetMgr.DeleteReference(set.Name, netpolName, referenceType)
289+
if err != nil {
290+
npmErrorString := npmerrors.DeleteSelectorReference
291+
if referenceType == ipsets.NetPolType {
292+
npmErrorString = npmerrors.DeleteNetPolReference
293+
}
294+
return npmerrors.Errorf(npmErrorString, false, fmt.Sprintf("[dataplane] failed to deleteIPSetReferences with err: %s", err.Error()))
295+
}
296+
}
297+
298+
// Check if any list sets are provided with members to add
299+
// TODO for nested IPsets check if we are safe to remove members
300+
// if k1:v0:v1 is created by two network policies
301+
// and both have same members
302+
// then we should not delete k1:v0:v1 members ( special case for nested ipsets )
303+
for _, set := range sets {
304+
// Delete if any 2nd level IPSets are generated by Controller with members
305+
if set.Kind == ipsets.ListSet {
306+
if len(set.MemberIPSets) > 0 {
307+
memberList := []string{}
308+
for _, memberSet := range set.MemberIPSets {
309+
memberList = append(memberList, memberSet.Name)
310+
}
311+
err := dp.ipsetMgr.RemoveFromList(set.Name, memberList)
312+
if err != nil {
313+
npmErrorString := npmerrors.DeleteSelectorReference
314+
if referenceType == ipsets.NetPolType {
315+
npmErrorString = npmerrors.DeleteNetPolReference
316+
}
317+
return npmerrors.Errorf(npmErrorString, false, fmt.Sprintf("[dataplane] failed to RemoveFromList in deleteIPSetReferences with err: %s", err.Error()))
318+
}
319+
}
320+
}
321+
322+
// Try to delete these IPSets
323+
dp.ipsetMgr.DeleteIPSet(set.Name)
324+
}
152325
return nil
153326
}

npm/pkg/dataplane/dataplane_linux.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package dataplane
22

33
import (
4-
"github.com/Azure/azure-container-networking/npm"
4+
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/policies"
55
"k8s.io/klog"
66
)
77

@@ -11,8 +11,17 @@ func (dp *DataPlane) initializeDataPlane() error {
1111
return nil
1212
}
1313

14+
func (dp *DataPlane) getEndpointsToApplyPolicy(policy *policies.NPMNetworkPolicy) (map[string]string, error) {
15+
// NOOP in Linux at the moment
16+
return nil, nil
17+
}
18+
19+
func (dp *DataPlane) shouldUpdatePod() bool {
20+
return false
21+
}
22+
1423
// updatePod is no-op in Linux
15-
func (dp *DataPlane) updatePod(pod *npm.NpmPod) error {
24+
func (dp *DataPlane) updatePod(pod *UpdateNPMPod) error {
1625
return nil
1726
}
1827

0 commit comments

Comments
 (0)