Skip to content

Conversation

@JungukCho
Copy link
Contributor

@JungukCho JungukCho commented Nov 12, 2021

Reason for Change:

This PR is to support egress and generalizes translation for egress and ingress.

Issue Fixed:

Requirements:

Notes:

  1. [NPM] General translation logic for linux and windows [NPM] General translation logic for linux and windows #1055
  2. refactor: [NPM] parsing label selector for general translation logic refactor: [NPM] parsing label selector for general translation logic #1077
  3. refactor: [NPM] General translation logic (mainly clean-up codes and correct bugs) refactor: [NPM] General translation logic (mainly clean-up codes and correct bugs) #1105

As @huntergregory summarized, next PR will deal with below lists.

  1. switching to PeerList instead of SrcList and DstList like you suggested
  2. deciding what to do for pod selector structs

@JungukCho JungukCho added the npm Related to NPM. label Nov 12, 2021
Copy link
Contributor

@huntergregory huntergregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, should some srclist become dstlist for egress?

I should have noticed this last PR, but can we consolidate some structs/fields? Right now, we have the NPMNetworkPolicy.PodSelectorList, which is idential to information in NPMNetworkPolicy.PodSelectorIPSets with an additional included bool for each set. We also have labelSelector struct in parseSelector.go which is identical and copied over to the two structures above. We can consolidate these three duplicate structures/fields into a into a new struct in the policy package to prevent duplication and reduce the amount of code (less complex and less bug-prone):

Proposal

Remove the labelSelector struct and NPMNetworkPolicy.PodSelectorList field, and make the type of NPMNetworkPolicy.PodSelectorIPSets as IncludedTranslatedIPSet

type IncludedTranslatedIPSet struct {
    Included bool
    ipsets  *[]TranslatedIPSet
}

To limit scope of this PR, we can leave the old NPMNetworkPolicy fields and add this as a new field. That way, current DP is unaffected, and we can follow up with a PR in DP.

acl := policies.NewACLPolicy(npmNetPol.NameSpace, npmNetPol.Name, policies.Allowed, direction)
ruleIPSets, setInfo := allowAllInternal(matchType)
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, ruleIPSets)
acl.SrcList = append(acl.SrcList, setInfo)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be dstlist for egress?

nsSelectorIPSets, nsSrcList := nameSpaceSelector(policies.SrcMatch, &flattenNSSelctor[i])
npmNetPol.RuleIPSets = append(npmNetPol.RuleIPSets, nsSelectorIPSets...)
peerAndPortRule(npmNetPol, rule.Ports, nsSrcList)
// #2. From fields exist in rule
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: from or to field exists

// to handle multiple values in matchExpressions spec.
flattenNSSelctor := flattenNameSpaceSelector(peer.NamespaceSelector)
for i := range flattenNSSelctor {
nsSelectorIPSets, nsSrcList := nameSpaceSelector(matchType, &flattenNSSelctor[i])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: flattenNSSelector

for i, rule := range ingress {
translateRule(npmNetPol, policies.Ingress, policies.SrcMatch, i, rule.Ports, rule.From)
}
// Except for allow all traffic case in #1, the rest of them should not have default drop rules.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: should this say "should have default drop rule"? (same with comment in ingress == nil check)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for egress function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Good catch!

}

// #2. If ingress is nil (in yaml file, it is specified with '[]'), it means "Deny all" - it does not allow receiving any traffic from others.
if ingress == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could remove this check since the for loop will do nothing if ingress is nil

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar for egress function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Initially, I did it and functionally there is no different, but to better understanding code and maintenance of code, I explicitly put two exceptional cases (e.g., allAllow and allDeny).
In this translation package, there are some codes which can be reduced, but just make different functions as well for better understanding (e.g., parsePodSelector or parseNSSelector, etc).

I am fine to either way (current one or merging one).
Please let me know if you think merging (only for loop) is better.
I can revise and put comment about it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For understanding and maintenance, makes sense to keep. Having an extra if-check shouldn't hurt performance anyways

const (
SrcMatch MatchType = 0
DstMatch MatchType = 1
SrcMatch MatchType = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to change this type to string for easier debugging from print statements. I could do that in my PR or you could

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine if you have ideas to better code, but do we have matchTypeStrings map just below this code?

@huntergregory There is one question about DstDstMatch (https://github.com/Azure/azure-container-networking/blob/master/npm/pkg/dataplane/policies/policy.go#L188)

// TODO(jungukcho) Question - Why it is 3, not 2?
DstDstMatch MatchType = 3

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had all the combinations before (SrcSrcMatch was 2), so it's leftover from that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, since there's a map already, this should be a separate PR change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, I will revise it to below code.

// Possible MatchTypes.
const (
	SrcMatch MatchType = 0
	DstMatch MatchType = 1
	// MatchTypes with 2 locations (e.g. DstDst) are for ip and port respectively.
	DstDstMatch MatchType = 2
	// This is used for podSelector under spec. It can be Src or Dst based on existence of ingress or egress rule.
	EitherMatch MatchType = 3
)

// (e.g., IPBlock, podSelector, namespaceSelector, or both podSelector and namespaceSelector)
func peerAndPortRule(npmNetPol *policies.NPMNetworkPolicy, ports []networkingv1.NetworkPolicyPort, setInfo []policies.SetInfo) {
// (e.g., IPBlock, podSelector, namespaceSelector, or both podSelector and namespaceSelector).
func peerAndPortRule(npmNetPol *policies.NPMNetworkPolicy, direction policies.Direction, ports []networkingv1.NetworkPolicyPort, setInfo []policies.SetInfo) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this affect the acl dstlist for egress? if so should modify the variable names used as args to calls to this func to be something like srcOrDstList

You confirmed ports are always for the destination for either ingress/egress, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.
I will walk through dstlist and srclist.

Yes. Confirmed that ports are always for destination.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revised them now with a method.

However, it seems we can do better job with only one PeerList instead of having two SrcList and DstList.
I put the comment about it, but want to do it next PR even though it makes sense since it needs to change in multiple places. wdyt?

@JungukCho
Copy link
Contributor Author

Just curious, should some srclist become dstlist for egress?

I will walk through srcList and dstList again.

I should have noticed this last PR, but can we consolidate some structs/fields? Right now, we have the NPMNetworkPolicy.PodSelectorList, which is idential to information in NPMNetworkPolicy.PodSelectorIPSets with an additional included bool for each set. We also have labelSelector struct in parseSelector.go which is identical and copied over to the two structures above. We can consolidate these three duplicate structures/fields into a into a new struct in the policy package to prevent duplication and reduce the amount of code (less complex and less bug-prone):

Proposal

Remove the labelSelector struct and NPMNetworkPolicy.PodSelectorList field, and make the type of NPMNetworkPolicy.PodSelectorIPSets as IncludedTranslatedIPSet

type IncludedTranslatedIPSet struct {
    Included bool
    ipsets  *[]TranslatedIPSet
}

Yes. Good suggestion.
I think you mentioned this in previous PR, I put it in some notes, but missed it in this PR.
Let me walk through this issue again and get back to you.

To limit scope of this PR, we can leave the old NPMNetworkPolicy fields and add this as a new field. That way, current DP is unaffected, and we can follow up with a PR in DP.
As you said, it would be good to a single PR to add and remove related codes if we decide to revise the struct. wdyt?

@huntergregory
Copy link
Contributor

To limit scope of this PR, we can leave the old NPMNetworkPolicy fields and add this as a new field. That way, current DP is unaffected, and we can follow up with a PR in DP.

As you said, it would be good to a single PR to add and remove related codes if we decide to revise the struct. wdyt?

If we change later, we can get to integration testing quicker, but then we might notice bugs and have to make fixes based on structs that we won't use later. I don't have a strong opinion.

@JungukCho
Copy link
Contributor Author

JungukCho commented Nov 15, 2021

To limit scope of this PR, we can leave the old NPMNetworkPolicy fields and add this as a new field. That way, current DP is unaffected, and we can follow up with a PR in DP.

As you said, it would be good to a single PR to add and remove related codes if we decide to revise the struct. wdyt?

If we change later, we can get to integration testing quicker, but then we might notice bugs and have to make fixes based on structs that we won't use later. I don't have a strong opinion.

Anyway if we change some codes, we need to do integration test again even though it is non-functional change (and we don't waste time your point - but then we might notice bugs and have to make fixes based on structs that we won't use later.). So, let's complete some necessary code change and PRs first and then plan integration test. We don't need to rush.

@JungukCho
Copy link
Contributor Author

To limit scope of this PR, we can leave the old NPMNetworkPolicy fields and add this as a new field. That way, current DP is unaffected, and we can follow up with a PR in DP.

As you said, it would be good to a single PR to add and remove related codes if we decide to revise the struct. wdyt?

If we change later, we can get to integration testing quicker, but then we might notice bugs and have to make fixes based on structs that we won't use later. I don't have a strong opinion.

Anyway if we change some codes, we need to do integration test again even though it is non-functional change (and we don't waste time your point - but then we might notice bugs and have to make fixes based on structs that we won't use later.). So, let's complete some necessary code change and PRs first and then plan integration test. We don't need to rush.

Just curious, should some srclist become dstlist for egress?

I will walk through srcList and dstList again.

I should have noticed this last PR, but can we consolidate some structs/fields? Right now, we have the NPMNetworkPolicy.PodSelectorList, which is idential to information in NPMNetworkPolicy.PodSelectorIPSets with an additional included bool for each set. We also have labelSelector struct in parseSelector.go which is identical and copied over to the two structures above. We can consolidate these three duplicate structures/fields into a into a new struct in the policy package to prevent duplication and reduce the amount of code (less complex and less bug-prone):

Proposal

Remove the labelSelector struct and NPMNetworkPolicy.PodSelectorList field, and make the type of NPMNetworkPolicy.PodSelectorIPSets as IncludedTranslatedIPSet

type IncludedTranslatedIPSet struct {
    Included bool
    ipsets  *[]TranslatedIPSet
}

Yes. Good suggestion. I think you mentioned this in previous PR, I put it in some notes, but missed it in this PR. Let me walk through this issue again and get back to you.

To limit scope of this PR, we can leave the old NPMNetworkPolicy fields and add this as a new field. That way, current DP is unaffected, and we can follow up with a PR in DP.
As you said, it would be good to a single PR to add and remove related codes if we decide to revise the struct. wdyt?

I walked through the code (including linux dataplane) to see how it uses data structures and think I prefer to having two members (i.e., PodSelectorIPSets and PodSelectorList) since two data structures have different data when there is multiple values in podSelector (Check this UT -

podSelectorIPSets: []*ipsets.TranslatedIPSet{
) and seems it is not easy to induce them in data plane side.

labelSelector is a local data structure used in only translation logic to create IPSet and List based on namespaceSelector and podSelector.

So, I am fine to a current code, but if you have another opinion, please let me know.
We can revise it if needed.

huntergregory
huntergregory previously approved these changes Nov 15, 2021
Copy link
Contributor

@huntergregory huntergregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. We have some cleanup work to do later in Translation & Dataplane:

  1. switching to PeerList instead of SrcList and DstList like you suggested
  2. deciding what to do for pod selector structs

ports []networkingv1.NetworkPolicyPort, peers []networkingv1.NetworkPolicyPeer) {
// TODO(jungukcho): need to clean up it.
// Leave allowExternal variable now while the condition is checked before calling this function.
allowExternal, portRuleExists, fromRuleExists := ruleExists(ports, peers)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: fromRuleExists to peerRuleExists

@JungukCho
Copy link
Contributor Author

Looks good to me. We have some cleanup work to do later in Translation & Dataplane:

  1. switching to PeerList instead of SrcList and DstList like you suggested
  2. deciding what to do for pod selector structs

Thank you for summary. Will add them in a note in this PR as well and revisit them in a next PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

npm Related to NPM.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants