-
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
sdn: try cleaning up OVS rules even if sandbox is gone #18166
sdn: try cleaning up OVS rules even if sandbox is gone #18166
Conversation
b71decb
to
db7b59d
Compare
Hm... we could find the veth name in this case too; given the OVS flow, we can extract the port number and use ovs-vsctl to get the corresponding port name ( |
/test unit |
@danwinship ok, how about now? Let's just stuff the sandbox ID into external-ids and use that to clean things up when we can. The one case where we need the hostVeth name is deleting the port, and we can get that if we have the sandbox ID. (open question, can we just delete the port & interface records from the OVSDB directly, or does 'del-port' do something special?) As a further optimization, we could stuff the IP address into external-ids too and kill the flow note stuff perhaps? Much nicer parsing OVSDB output than dump-flows. |
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.
LGTM
/retest |
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.
Generally LATM ("looks awesome to me").
(open question, can we just delete the port & interface records from the OVSDB directly, or does 'del-port' do something special?)
That doesn't appear to be documented. (Note that you can't just ovs-vsctl destroy
most objects anyway; you have to remove references to them (from br0's ports
property in this case) and let OVS GC them.)
As a further optimization, we could stuff the IP address into external-ids too and kill the flow note stuff perhaps? Much nicer parsing OVSDB output than dump-flows.
Yes
pkg/network/node/ovscontroller.go
Outdated
func (oc *ovsController) ensureOvsPort(hostVeth string) (int, error) { | ||
return oc.ovs.AddPort(hostVeth, -1) | ||
func (oc *ovsController) ensureOvsPort(hostVeth, sandboxID string) (int, error) { | ||
return oc.ovs.AddPort(hostVeth, -1, "external-ids=sandbox="+sandboxID, "--", "set", "Port", hostVeth, "external-ids=sandbox="+sandboxID) |
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.
Ugh.
Fortunately, I don't think there's any need to bother with Port properties. Commands that act on Ports will allow a Port name rather than a UUID (like we used to do in ClearPodBandwidth()), and the Port name is the same as the Interface name, so if you changed ovsif.Find() to let you specify the column you wanted returned, then you could have getPortsForSandbox() return a list of Interface names rather than a list of Port UUIDs, and that would work everywhere. In fact, it would simplify TearDownPod().
pkg/network/node/ovscontroller.go
Outdated
return err | ||
} | ||
|
||
portUUIDs, err := oc.getPortsForSandbox(sandboxID) |
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.
If we now absolutely depend on every port having a sandbox ID in its external-ids then we need to make AlreadySetUp() fail for bridges with non-external-id'ed ports attached. So change ruleVersion
at the top of the file. (In which case you'll also want danwinship@dbbf89ac.)
UpdatePod() will also need to be updated to call ensureOvsPort().
pkg/util/ovs/ovs.go
Outdated
uuids := make([]string, 0) | ||
for _, line := range strings.Split(output, "\n") { | ||
parts := strings.Split(line, ":") | ||
if len(parts) >= 2 && strings.TrimSpace(parts[0]) == "_uuid" { |
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 can force ovs-vsctl to do all this for you. --no-heading --columns=_uuid find ...
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.
And then use strings.Fields to get the trimmed array.
pkg/network/node/ovscontroller.go
Outdated
func (oc *ovsController) SetPodBandwidth(hostVeth string, ingressBPS, egressBPS int64) error { | ||
// note pod ingress == OVS egress and vice versa | ||
func (oc *ovsController) getPortsForSandbox(sandboxID string) ([]string, error) { | ||
return oc.ovs.Find("port", "external-ids=sandbox="+sandboxID) |
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.
That does a full match on external-ids (ie, it will fail if external-ids also contains other keys). Changing the =
between external-ids
and sandbox
to a :
will change it to a subkey match (checking only that external-ids contains a matching sandbox key)
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.
+1
pkg/network/node/ovscontroller.go
Outdated
func (oc *ovsController) SetPodBandwidth(hostVeth, sandboxID string, ingressBPS, egressBPS int64) error { | ||
// note pod ingress == OVS egress and vice versa | ||
|
||
if err := oc.ClearPodBandwidth(nil, sandboxID); err != 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.
You could remove the hostVeth
arg to SetPodBandwidth() and just call getPortsForSandbox() and then pass that list to ClearPodBandwidth() (which then no longer needs its own call-getPortsForSandbox() special case), and change the remaining hostVeth references in SetPodBandwidth() to use the portsList instead. (I'm not totally sure if this would be a net improvement.)
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.
@danwinship I'd rather still pass it in so we know what the most-recently-created veth will be for actually setting the bandwidth. Otherwise we'd have to assume it's the first item in the ports array, or do it for all ports. We already have the info in the veth name here.
But I agree we don't need ClearPodBandwidth() to do its own getPortsForSandboxID().
c17cd2b
to
22f3e02
Compare
@danwinship @rajatchopra PTAL thanks! Addressed all your comments. |
/test extended_conformance_install issue #17882 |
lgtm except I think you still need to update UpdatePod? Right now the changed ruleVersion means it will run UpdatePod on all the pods, but UpdatePod won't actually set the external-id |
@danwinship do we? If we bump the flow version, on restart that out to blows the entire bridge away on upgrade including all the flows, ports, interfaces, qos, etc. That makes Update() fail and the pod's sandbox gets killed and then completely restarted. |
duh, right. (not bothering to /lgtm yet since you have to rebase) |
22f3e02
to
db19d04
Compare
@danwinship rebased |
/lgtm |
/test cmd |
/test extended_conformance_install issue #17556 |
/approve |
If a sandbox is deleted underneath kubernetes its netns will be gone and its veth interface will be deleted by the kernel. That means we can't inspect the veth for its IP address and other details, which are used to remove OVS flows for the interface. But we've already got code to find out the IP using the sandbox ID which kubelet passes down to us. Let's use that code to at least delete the stale OVS flows. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1518684
Store the sandbox ID in the OVSDB as an external-id and use that to find things we need to clean up. Previously these were leaked if the network namespace was removed underneath kubernetes.
db19d04
to
87fdfb0
Compare
/test unit |
@danwinship @knobunc can I get another LGTM? nothing has changed in the code, but I mistakenly repushed because I thought that might trigger re-evaluation of the pkg/util/ovs/OWNERS changes |
// note pod ingress == OVS egress and vice versa | ||
// Returned list can also be used for port names | ||
func (oc *ovsController) getInterfacesForSandbox(sandboxID string) ([]string, error) { | ||
return oc.ovs.Find("interface", "name", "external-ids:sandbox="+sandboxID) |
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.
ovs AddPort() and Create() has 'external-ids=' and Find() has 'external-ids:', initially thought ':' is a typo but looking at the man page, column[:key]=value is the correct syntax.
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.
@pravisankar yeah we want a substring match in Find, while Add/Create set it.
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: danwinship, dcbw, pravisankar The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
/test extended_conformance_install issue #17556 |
/retest |
Automatic merge from submit-queue. |
If a sandbox is deleted underneath kubernetes its netns will
be gone and its veth interface will be deleted by the kernel.
That means we can't inspect the veth for its IP address and
other details, which are used to remove OVS flows for the
interface.
But we've already got code to find out the IP using the
sandbox ID which kubelet passes down to us. Let's use
that code to at least delete the stale OVS flows.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1518684
@danwinship @openshift/networking @knobunc