-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
OpenShift SDN: Changed ovs.Transaction from pseudo to real atomic transaction #19393
OpenShift SDN: Changed ovs.Transaction from pseudo to real atomic transaction #19393
Conversation
@openshift/sig-networking PTAL |
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.
I think exposing Bundle
in the API adds a lot of complexity without much benefit. In particular, if you drop it from the public API, then you can also drop basically all of your changes to fake_ovs, and also remove BundleAddFlowRepr
and BundleDeleteFlowRepr
as APIs (and just have them be internal details of ovsExec
's AddFlow
and DeleteFlows
implementations).
pkg/util/ovs/ovs.go
Outdated
stdin := bytes.NewBufferString(stdinString) | ||
kcmd.SetStdin(stdin) | ||
|
||
glog.V(4).Infof("Executing: %s %s |\n%s", cmd, strings.Join(args, " "), stdinString) |
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.
The use of |
there is weird: it makes it look like you're piping the output of ovs-ofctl to the string.
Actually, just changing |
to <<
should make it clear what's going on, shell-syntax-wise, I think?
pkg/util/ovs/fake_ovs.go
Outdated
addPrefix := "flow add" | ||
delPrefix := "flow delete" | ||
|
||
if strings.Contains(bundleFlow, addPrefix) { |
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.
strings.HasPrefix
pkg/util/ovs/fake_ovs.go
Outdated
@@ -283,16 +284,12 @@ func (fake *ovsFake) Bundle(bundleFlows []string) error { | |||
} | |||
|
|||
if isAdd { | |||
tx.AddFlow(flow) | |||
fake.addFlowHelper(flow) |
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.
you need to check the error return here
37d263e
to
8207b0b
Compare
8207b0b
to
6c4fda1
Compare
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: pravisankar The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@danwinship Updated, PTAL |
6c4fda1
to
ffc8186
Compare
/retest |
pkg/util/ovs/ovs.go
Outdated
@@ -106,7 +107,7 @@ type ovsExec struct { | |||
} | |||
|
|||
// New returns a new ovs.Interface | |||
func New(execer exec.Interface, bridge string, minVersion string) (Interface, error) { | |||
func New(execer exec.Interface, bridge string, minVersion string) (*ovsExec, error) { |
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.
Hm... isn't that bad style? Maybe you could just have TestBundle() cast it from Interface to *ovsExec.
Alternatively, after the next commit, TestBundle() doesn't really do anything beyond what TestTransactionSuccess() and TestTransactionFailure() do, so you could just drop TestBundle() (and maybe add a TestEmptyTransaction() in the next commit if you want to explicitly test that case too.)
pkg/network/node/ovscontroller.go
Outdated
@@ -496,7 +491,7 @@ func (oc *ovsController) UpdateEgressNetworkPolicyRules(policies []networkapi.Eg | |||
otx.DeleteFlows("table=101, reg0=%d, cookie=1/1", vnid) |
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.
UpdateEgressNetworkPolicyRules no longer needs to do the "temporarily drop all outgoing traffic to avoid race conditions" thing.
You can also revert the changes from #19346 since they're no longer needed
pkg/util/ovs/ovs_test.go
Outdated
@@ -53,8 +53,7 @@ func ensureTestResults(t *testing.T, fexec *fakeexec.FakeExec) { | |||
|
|||
func TestTransactionSuccess(t *testing.T) { | |||
fexec := normalSetup() | |||
addTestResult(t, fexec, "ovs-ofctl -O OpenFlow13 add-flow br0 flow1", "", nil) | |||
addTestResult(t, fexec, "ovs-ofctl -O OpenFlow13 add-flow br0 flow2", "", nil) | |||
addTestResult(t, fexec, "ovs-ofctl -O OpenFlow13 bundle br0 -", "", nil) |
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.
(It would be nice if we could test the stdin value too...)
} | ||
|
||
func (fake *ovsFake) NewTransaction() Transaction { | ||
return &ovsFakeTx{fake: fake, err: fake.ensureExists()} | ||
return &ovsFakeTx{fake: fake, flows: []string{}} |
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.
Note that there's a mild behavior change here: it used to check that you had called ovsif.AddBridge()
on the ovsFake
, but now it doesn't. (We apparently don't test this case in fake_ovs_test.go
.) Anyway, you could just move the fake.ensureExists()
call to Commit
pkg/util/ovs/fake_ovs.go
Outdated
err := tx.err | ||
tx.err = nil | ||
return err | ||
func (tx *ovsFakeTx) Commit() error { |
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.
This doesn't actually implement transactional behavior: if you do
tx.AddFlow("table=10, actions=drop")
tx.AddFlow("@!#$!@#$!@#$")
tx.Commit()
then it will return an error saying that the second flow couldn't be parsed, but the "table=10, actions=drop"
flow will still have been added.
There should probably be a test of transactionality in fake_ovs_test.go
7176cdf
to
68f3e6d
Compare
@danwinship Addressed all your comments, PTAL |
68f3e6d
to
06ac661
Compare
Looks good to me. @dcbw can you take a look please? |
- bundle() enables execution of given add and/or delete ovs flows in a single atomic transaction
- Leverages ovs.bundle() to perform atomic transactions - Now ovs.Transaction interface has AddFlow(), DeleteFlows() and Commit() methods General usage: otx := ovs.NewTransaction() otx.AddFlow(flow1) // No execution, only caches flow context ... otx.DeleteFlows(flowN) // No execution, only caches flow context ... err := otx.Commit() // Executes all cached flows as single atomic transaction - With this change, most of the operations in ovs controller like setup, addHostSubnet, addService, etc. has only one ovs bundle call. So there won't be partial commited changes and it reduces the downtime during watch resync events.
- With ovs atomic transaction, flows are actually executed when Commit() is called so we no longer need the earlier workaround.
06ac661
to
105395d
Compare
/lgtm |
/retest |
2 similar comments
/retest |
/retest |
/retest Please review the full test history for this PR and help us cut down flakes. |
General usage:
otx := ovs.NewTransaction()
otx.AddFlow(flow1) // No execution, only caches flow context
...
otx.DeleteFlows(flowN) // No execution, only caches flow context
...
err := otx.Commit() // Executes all cached flows as single atomic transaction
addHostSubnet, addService, etc. has only one ovs bundle call. So there
won't be partial commited changes and it reduces the downtime during
watch resync events.