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

Extend ACL API to support changing match critera and logging for an existing ACL #139

Merged
merged 1 commit into from
Apr 14, 2021

Conversation

anfredette
Copy link
Contributor

@anfredette anfredette commented Mar 16, 2021

  • Support setting ACL name in ACLAddEntity()
  • Add ACL set support for ACL name, match and logging for an existing ACL
  • Use ACL UUID to identify ACL in ACLDelEntity()

Addresses Issues #137 and #138

Signed-off-by: Andre Fredette [email protected]

Copy link
Contributor

@hzhou8 hzhou8 left a comment

Choose a reason for hiding this comment

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

Thanks for the change. Could you explain why these APIs are needed? Can we achieve the same by deleting the old and adding new ACLs? The user can do both operations in a single transaction, which for my understanding would result in the same outcome in terms of both feature and performance. Did I misunderstand it?

@anfredette
Copy link
Contributor Author

Thanks for your comment.

These APIs are implementing functionality currently supported by the ovn-nbctl database commands and used by ovn-kubernetes. ACLSetMatchEntity() would get called to update the gress policy when an address set is added to or deleted from a pod. ACLSetLoggingEntity() would get called when the logging is enabled/disabled or severity is changed.

I agree that the end state would be equivalent if the user deleted the existing ACL and then re-added the ACL with the new information. This would require more work in ovn-k because we don't currently have all the necessary info to recreate the ACL in the place where it's needed. I haven't tried to work it out yet, but I'm assuming it's possible.

Intuitively, it would seem to have less of a performance impact to update a field in a row than it would to delete the row and re-create it. But, I can't comment on the real performance impact.

I also wonder whether deleting an ACL and then re-adding it (even if it's in the same transaction) would impact the data plane more if the ACL was deleted and readded vs. updated. E.g., is it possible for any packets to slip through while it's being deleted and readded?

I also wonder why these set APIs are different from other the other set APIs that we have.

@hzhou8
Copy link
Contributor

hzhou8 commented Mar 25, 2021

Thanks for your comment.

These APIs are implementing functionality currently supported by the ovn-nbctl database commands and used by ovn-kubernetes. ACLSetMatchEntity() would get called to update the gress policy when an address set is added to or deleted from a pod. ACLSetLoggingEntity() would get called when the logging is enabled/disabled or severity is changed.

I agree that the end state would be equivalent if the user deleted the existing ACL and then re-added the ACL with the new information. This would require more work in ovn-k because we don't currently have all the necessary info to recreate the ACL in the place where it's needed. I haven't tried to work it out yet, but I'm assuming it's possible.

In fact to call the "set" API you already have to provide most information of an ACL just so that it can be identified. Maybe the only thing you don't provide is for ACLSetMatchEntity() you don't need the log/meter part. If you want to keep the original log settings when updating an ACL's match condition, and assume you don't know what log settings should it be when you try to update the ACL, then one approach is to Get the ACL (which happens locally) first so you know all the existing information and then do a single transaction with "delete + add".

Intuitively, it would seem to have less of a performance impact to update a field in a row than it would to delete the row and re-create it. But, I can't comment on the real performance impact.

Intuitively yes, but in fact, OVN has to regenerate the flows for the changed ACL, which costs the same as if it is deleted and added back. If in the future this can be optimized in OVN of course we can look into ways to optimize it. (I hope with the new API framework introduced by #136 and related work this would be easily supported in general)

I also wonder whether deleting an ACL and then re-adding it (even if it's in the same transaction) would impact the data plane more if the ACL was deleted and readded vs. updated. E.g., is it possible for any packets to slip through while it's being deleted and readded?

This shouldn't be worried as long as the operations are performed in a single transaction, which in turn ensures OVS changes happens atomically.

I also wonder why these set APIs are different from other the other set APIs that we have.

For other existing "set" APIs, their interfaces are more straightforward - they usually provides "name" as an identifier. For ACL, since we are not using "name" (which is a field added in a late version of the schema), the API would look really scary. And more importantly, if we continue this way there can be more and more "set" APIs added - in theory each field of each table requires a "set" API, which is a huge burden for maintenance. For this specific case, since I don't see real benefit of providing the new APIs instead of using "delete + add", for the reason I mentioned regarding the OVN implementation behind, I am hesitating about adding these APIs. But I am still open to opinions. Let me know if you still strongly feel it is needed.

@anfredette
Copy link
Contributor Author

Sorry for the delay, but I wanted to run this by someone else from the ovn-kubernetes team before I responded. So, I discussed it with @trozet this morning. He is in agreement with me that it's preferable to use sets in these cases (and probably others). I believe that the setting of any attribute should be fair game if there's a use case for it. Though I don't think we need to arbitrarily add sets for everything. In many cases, they are not needed. Objects get created with everything they need and are never modified until they are deleted. In other cases, it makes more sense to have an add/delete API such as with ports being added and deleted from port groups as pods get created and deleted.

Some of the reasoning/concerns (not necessarily in priority order):

  1. Consistent with the ovn-nbctl API
  2. Less impact to the code being migrated from the ovn-nbctl API to the go-ovn API.
  3. Less work for the user code than deleting and recreating.
  4. Less work in the go-ovn client API code
  • with the delete/add sequence, we'd end up searching the list of ACLs twice - once to find the one to delete and another time to confirm that it doesn't already exist on the add.
  • According to cloc, the delete/add sequence is 122 lines of code, while SetMatch and SetLog are 27 and 37 lines of code, respectively.
  • If we had to also do a get first it would be more.
  1. We don't know what the impact on the rest of the system will be (e.g., ovn northd, sbdb, controllers).
  2. The UUID for the object will change unnecessarily (does anyone care?)
  3. What would happen to dependent non-root rows if their reference in a root table is deleted? Are they preserved as long as everything happens in a single transaction?

I made a few more comments below.

In fact to call the "set" API you already have to provide most information of an ACL just so that it can be identified. Maybe the only thing you don't provide is for ACLSetMatchEntity() you don't need the log/meter part. If you want to keep the original log settings when updating an ACL's match condition, and assume you don't know what log settings should it be when you try to update the ACL, then one approach is to Get the ACL (which happens locally) first so you know all the existing information and then do a single transaction with "delete + add".

The missing fields are:

  • ACLSetMatchEntity: action, external_ids, logflag, meter, severity
  • ACLSetLoggingEntity: action, external_ids

There are solutions, if necessary.

Intuitively, it would seem to have less of a performance impact to update a field in a row than it would to delete the row and re-create it. But, I can't comment on the real performance impact.

Intuitively yes, but in fact, OVN has to regenerate the flows for the changed ACL, which costs the same as if it is deleted and added back. If in the future this can be optimized in OVN of course we can look into ways to optimize it. (I hope with the new API framework introduced by #136 and related work this would be easily supported in general)

I agree that #136 will help, but it may be a while until it's fully usable.

I also wonder why these set APIs are different from other the other set APIs that we have.

For other existing "set" APIs, their interfaces are more straightforward - they usually provides "name" as an identifier. For ACL, since we are not using "name" (which is a field added in a late version of the schema), the API would look really scary. And more importantly, if we continue this way there can be more and more "set" APIs added - in theory each field of each table requires a "set" API, which is a huge burden for maintenance. For this specific case, since I don't see real benefit of providing the new APIs instead of using "delete + add", for the reason I mentioned regarding the OVN implementation behind, I am hesitating about adding these APIs. But I am still open to opinions. Let me know if you still strongly feel it is needed.

Right, because we don't support names or UUIDs for ACLs, it's necessary to provide the entity, direction, match, and priority to uniquely identify the ACL, so it's not as clean as some of the others. On a related note, @vgozer has requested that "name" be added to the ACL APIs in #137. I'd be interested to hear your opinion on it.

As mentioned above, I don't think we necessarily need a set API for every field, but if someone has a use case and offers an implementation, I'd support them.

Thanks,
Andre

@hzhou8
Copy link
Contributor

hzhou8 commented Mar 26, 2021

@anfredette thanks for the points. I agree with you "set" APIs are useful and harmless.

Right, because we don't support names or UUIDs for ACLs, it's necessary to provide the entity, direction, match, and priority to uniquely identify the ACL, so it's not as clean as some of the others. On a related note, @vgozer has requested that "name" be added to the ACL APIs in #137. I'd be interested to hear your opinion on it.

Do you think it is reasonable to support "name" in ACL APIs first and then add "set" APIs only using the "name"? Or do we need two sets of "set" APIs: the ones using "name" and the one using "match + priority + direction"?

@anfredette
Copy link
Contributor Author

Do you think it is reasonable to support "name" in ACL APIs first and then add "set" APIs only using the "name"? Or do we need two sets of "set" APIs: the ones using "name" and the one using "match + priority + direction"?

I think it would be best to just have one set of APIs. I’d like to confirm with everyone how ACL name will work. For example, is it required? I’m out today. I’ll follow up on Monday with comments on #139. Thanks!

@anfredette
Copy link
Contributor Author

I've pushed a patch updating the client API code per discussion on Issue #137. I am requesting feedback before fully implementing the changes. Thanks, Andre

client.go Outdated
// Set name for ACL
ACLSetName(aclUUID string, aclName string) (*OvnCommand, error)
// Set match criteria for ACL
ACLSetMatchEntity(entityType EntityType, entityUUID, aclUUID, newMatch string) (*OvnCommand, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think entity type and name/id are not needed for the "set" APIs if ACL uuid is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We ensure that the 3-tuple <direction, match, priority> is unique for a given entity. If we allow the user to change one of these items, we need to make sure that the new 3-tuple does not conflict with another ACL on the same entity. The ACL record does not contain the entity on which it was created. So, if we don't pass in the entity, the code would need to potentially loop through every ACL on every entity to find the entity on which the ACL was created before it could confirm that the new 3-tuple was still unique for that entity.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would leave this check to the client instead of in go-ovn API. When using aclUUID it is natural to assume this task on client side. In fact even if entity is passed in, go-ovn API can't guarantee the uniqueness because the same ACL may be used by multiple entities, and this API can only pass in one of them.

So I'd make the "Set" API simple (and efficient). If needed, a Get (or ListBy) API (as discussed earlier) can be provided for querying if certain ACLs existed, before calling the "Set" API.

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 would leave this check to the client instead of in go-ovn API. When using aclUUID it is natural to assume this task on client side. In fact even if entity is passed in, go-ovn API can't guarantee the uniqueness because the same ACL may be used by multiple entities, and this API can only pass in one of them.

I don't think the go-ovn API currently allows a given ACL to be associated with more than one entity. I think it can be done via the ovn-nbctl database API, but I don't think we do that in ovn-kubernetes. So, it seems possible that at some point, it could happen that an ACL is associated with more than one entity.

So I'd make the "Set" API simple (and efficient). If needed, a Get (or ListBy) API (as discussed earlier) can be provided for querying if certain ACLs existed, before calling the "Set" API.

That's fine.

client.go Outdated
@@ -73,19 +73,21 @@ type Client interface {
LSLBList(ls string) ([]*LoadBalancer, error)

// Add ACL to entity (PORT_GROUP or LOGICAL_SWITCH)
ACLAddEntity(entityType EntityType, entity, direct, match, action string, priority int, external_ids map[string]string, logflag bool, meter string, severity string) (*OvnCommand, error)
ACLAddEntity(entityType EntityType, entityUUID, aclName, direct, match, action string, priority int, external_ids map[string]string, logflag bool, meter, severity string) (*OvnCommand, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why entityUUID is preferred than entityName? I know this has been a big discussion on slack. I replied there as well.

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'll respond in slack so we can keep the discussion in one place and then comment back here when there is a decision.

@anfredette anfredette force-pushed the pg-acls-set branch 4 times, most recently from 759a0c9 to b98b241 Compare April 9, 2021 19:13
@anfredette
Copy link
Contributor Author

This PR is ready for review.

- Support setting ACL name in ACLAddEntity()
- Add ACL set support for ACL name, match and logging for an existing ACL
- Use ACL UUID to identify ACL in ACLDelEntity()

Addresses Issues eBay#137 and eBay#138

Signed-off-by: Andre Fredette <[email protected]>
@anfredette
Copy link
Contributor Author

I just added one more negative test case. Now it's really ready for review :-)

@hzhou8 hzhou8 merged commit 7376ba9 into eBay:master Apr 14, 2021
@hzhou8
Copy link
Contributor

hzhou8 commented Apr 14, 2021

Thanks @anfredette

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants