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

passt, sidecar: Look for optional link #12354

Merged
merged 1 commit into from
Jul 18, 2024

Conversation

qinqon
Copy link
Contributor

@qinqon qinqon commented Jul 15, 2024

What this PR does

Before this PR:
Passt uses the source device "eth0" for domain xml

After this PR:
At some enviroments that should be "ovn-udn1" this PR try this first, if it do not exist do a fallback to eth0.

ovn-kubernetes place where the interface is not eth0:

Why we need it and why it was done in this way

The following tradeoffs were made:
Using harcoded value is not flexible, but we plan to make it configurable in the future.

The following alternatives were considered:
Try to find the interface that has the default gw, problem is that at multus you can configure de default network at other interfaces.

Checklist

This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR.
Approvers are expected to review this list.

Release note

Use optional interface at passt binding sidecar

@kubevirt-bot kubevirt-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. labels Jul 15, 2024
@kubevirt-bot kubevirt-bot added the lgtm Indicates that a PR is ready to be merged. label Jul 15, 2024
@kubevirt-bot kubevirt-bot removed the lgtm Indicates that a PR is ready to be merged. label Jul 15, 2024
@qinqon qinqon force-pushed the passt-add-extra-interface branch from 7638063 to 861dcfa Compare July 15, 2024 16:30
@kubevirt-bot kubevirt-bot added the sig/buildsystem Denotes an issue or PR that relates to changes in the build system. label Jul 15, 2024
@qinqon qinqon force-pushed the passt-add-extra-interface branch from 861dcfa to 047220a Compare July 15, 2024 17:15
@qinqon qinqon requested a review from EdDev July 15, 2024 17:15
"kubevirt.io/kubevirt/pkg/network/namescheme"
"kubevirt.io/kubevirt/pkg/network/vmispec"
)

type NetworkHandler interface {
Copy link
Member

Choose a reason for hiding this comment

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

  • I see no reason for it to be exposed.
  • It should describe the behavior, so consider a name like linkFinder or linkGetter. (please adjust the member name as well please, per your choice)

type NetworkConfiguratorOptions struct {
IstioProxyInjectionEnabled bool
UseVirtioTransitional bool
NetworkHandler NetworkHandler
Copy link
Member

Choose a reason for hiding this comment

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

Ahh this is a bit ugly.
It is not a configuration option, so it looks like an attempt to ride on some existing struct.

The simple option: Pass it to the NewPasstNetworkConfigurator directly.
The complex option: Use a builder pattern to avoid adding that nil all over the places that do not need it.

I am good with both options at this stage.

// link do not exist
// FIXME: This will be configurable in the future.
const (
optionalLinkName = "ovn-udn1"
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a link that shows from where this is coming from?
Not a must if it is linked in the commit message.

Comment on lines 223 to 224
_, err := p.handler.LinkByName(optionalLinkName)
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

nit: Can be inlined (i.e. if _, err := p...; err != nil {).

Comment on lines 225 to 226
_, notFound := err.(vishnetlink.LinkNotFoundError)
if notFound {
Copy link
Member

Choose a reason for hiding this comment

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

nit: Same

Comment on lines 328 to 333
fakeNetlink := fakenetlink.New()
fakeNetlink.LinkAdd(&vishnetlink.Veth{
LinkAttrs: vishnetlink.LinkAttrs{
Name: "ovn-udn1",
},
})
Copy link
Member

Choose a reason for hiding this comment

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

I do not think we need to use the fake for this simple test.

Creating a stub should do the job:

type netlinkStub struct{}
func (nl netLinkStub) LinkByName(name string) (vishnetlink.Link, error) {
    return &vishnetlink.Veth{LinkAttrs: vishnetlink.LinkAttrs{Name: "ovn-udn1"}}
}

We do not really need to mimic any real logic of netlink here.

@@ -65,9 +73,13 @@ func NewPasstNetworkConfigurator(ifaces []vmschema.Interface, networks []vmschem
if iface.Binding == nil || iface.Binding != nil && iface.Binding.Name != PasstPluginName {
return nil, fmt.Errorf("interface %q is not set with Passt network binding plugin", network.Name)
}
if opts.NetworkHandler == nil {
opts.NetworkHandler = &netlink.NetLink{}
Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, the unit tests that do not use a stub/fake netlink, will in practice try to call netlink and look for the interface. We do not really want to mix the OS into this, so this is a good reasoning for not making the link getter optional. But it can be solved by making sure the tests always pass in a stub that returns the error.

@fabiand
Copy link
Member

fabiand commented Jul 15, 2024 via email

@EdDev
Copy link
Member

EdDev commented Jul 15, 2024

Could a CNI not just set en ENV var with the DEV name to use?

The CNI is executed in the pod network namespace only, it cannot touch the container env variable.

@fabiand
Copy link
Member

fabiand commented Jul 15, 2024 via email

@qinqon qinqon force-pushed the passt-add-extra-interface branch from 047220a to 9c6f579 Compare July 16, 2024 05:32
@qinqon
Copy link
Contributor Author

qinqon commented Jul 16, 2024

The SPEC does at least not permit it. I still wonder if it could be configured - as we know the pod. DPs can only do this.

One idea as a follow up PR after we unblock the kubevirt binding for ovn-k primary networks is to add a "intefaceName" option at the Kubevirt CR binding option ? then kubevirt can pass it to the sidecard and also to the NetworkSelectionElement virt-launcher annotation that already has a "interface" field:

k8s.v1.cni.cncf.io/networks: '[{"name":"netbindingpasst","namespace":"passt-poc","interface":"ovn-udn1"}

For the Kubevirt CR it would be something like

kubectl patch kubevirts -n kubevirt kubevirt --type=json -p='[{"op": "add", "path": "/spec/configuration/network",   "value": {
            "binding": {
                "ovn-passt": {
                    "networkAttachmentDefinition": "default/netbindingpasst",
                    "sidecarImage": "quay.io/kubevirt/network-passt-binding:20231205_29a16d5c9",
                    "interface": "ovn-udn1",
                    "migration": {
                        "method": "link-refresh"
                    },
                    "computeResourceOverhead": {
                      "requests": {
                        "memory": "500Mi",
                      }
                    }
                }
            }
        }}]'

@qinqon qinqon force-pushed the passt-add-extra-interface branch 2 times, most recently from 61d71ba to efde4a6 Compare July 16, 2024 06:46
@qinqon qinqon requested a review from EdDev July 16, 2024 07:21
@ormergi
Copy link
Contributor

ormergi commented Jul 16, 2024

@qinqon Maybe the binding plugin's downard API can be utilized to avoid passing the interface name (low level detail, depend on env), in a way it"ll mount the network-status annotation so the sidecar can take the interface name form there.
Please see the downward API design [1] and vDPA example [2].

The sidecar could realize the interface-name from the device-info.
In case device-info doesnt provide the right info, the downward API could be extended to provide the interface-name, in other words the network-status bits with the network-intreface name instead of the device-info part.

[1] https://github.com/kubevirt/community/blob/main/design-proposals/network-binding-plugin/network-binding-plugin.md#reacting-to-cni-results-multus-networksstatus-annotation
[2] https://github.com/kubevirt/community/blob/main/design-proposals/network-binding-plugin/network-binding-plugin.md#appendix-f-concrete-example-for-vdpa-binding

@ormergi
Copy link
Contributor

ormergi commented Jul 16, 2024

/assign

Comment on lines 157 to 161

sourceLinkName, err := p.discoverSourceLinkName()
if err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I would move the link discovery to top of this function, to make if fail faster.

@@ -88,7 +88,7 @@ func (s V1alpha3Server) OnDefineDomain(_ context.Context, params *hooksV1alpha3.
IstioProxyInjectionEnabled: istioProxyInjectionEnabled,
}

passtConfigurator, err := domain.NewPasstNetworkConfigurator(vmi.Spec.Domain.Devices.Interfaces, vmi.Spec.Networks, opts)
passtConfigurator, err := domain.NewPasstNetworkConfigurator(vmi.Spec.Domain.Devices.Interfaces, vmi.Spec.Networks, opts, nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it have the concrete link discoverer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On nill it fallback to netlink, so everything is fine.

Copy link
Contributor

@ormergi ormergi Jul 17, 2024

Choose a reason for hiding this comment

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

Oh, I missed that part.

nit: I would pass the concrete link-discoverer here &netlink.NetLink{}, instead of having NewPasstNetworkConfigurator account for it.
IMO it would also make the code cleaner and more predictable.

At some systems the passt binding has to use ovn-udn1 as source link for
the domain xml. This change add this as an optional link name and do a
fallback to eth0 if the optional link is not found.

Signed-off-by: Enrique Llorente <ellorent@redhat.com>
@qinqon qinqon force-pushed the passt-add-extra-interface branch from efde4a6 to 873c23d Compare July 16, 2024 15:54
@qinqon qinqon requested a review from ormergi July 16, 2024 15:54
@fabiand
Copy link
Member

fabiand commented Jul 16, 2024 via email

Copy link
Contributor

@ormergi ormergi left a comment

Choose a reason for hiding this comment

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

Overall looks good

I left one suggestion, please consider it.

@@ -88,7 +88,7 @@ func (s V1alpha3Server) OnDefineDomain(_ context.Context, params *hooksV1alpha3.
IstioProxyInjectionEnabled: istioProxyInjectionEnabled,
}

passtConfigurator, err := domain.NewPasstNetworkConfigurator(vmi.Spec.Domain.Devices.Interfaces, vmi.Spec.Networks, opts)
passtConfigurator, err := domain.NewPasstNetworkConfigurator(vmi.Spec.Domain.Devices.Interfaces, vmi.Spec.Networks, opts, nil)
Copy link
Contributor

@ormergi ormergi Jul 17, 2024

Choose a reason for hiding this comment

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

Oh, I missed that part.

nit: I would pass the concrete link-discoverer here &netlink.NetLink{}, instead of having NewPasstNetworkConfigurator account for it.
IMO it would also make the code cleaner and more predictable.

@kubevirt-bot kubevirt-bot added the lgtm Indicates that a PR is ready to be merged. label Jul 17, 2024
Copy link
Member

@EdDev EdDev left a comment

Choose a reason for hiding this comment

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

Thank you.

The inline comments can be treated later if there is no time at the moment, nothing urgent there.

The usage of the hard-coded optional alternative link name is not that nice, but there is a challenge to pass this information through other means at the moment.

  • Passing information from the CNI step to the sidecar is not trivial.
  • Adding an API field for this is too noisy.
  • Using an admission webhook is possible (adding an env variable for the sidecar given the NAD information) and this could be considered for graduation.

/approve

Comment on lines +35 to +45
type defaultNetLinkStub struct{}

func (nl defaultNetLinkStub) LinkByName(name string) (vishnetlink.Link, error) {
return nil, vishnetlink.LinkNotFoundError{}
}

type netLinkStub struct{}

func (nl netLinkStub) LinkByName(name string) (vishnetlink.Link, error) {
return &vishnetlink.Veth{LinkAttrs: vishnetlink.LinkAttrs{Name: name}}, nil
}
Copy link
Member

Choose a reason for hiding this comment

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

I usually prefer these stubs at the tail of the file. But we can adjust it as a follow up.

@@ -65,10 +72,14 @@ func NewPasstNetworkConfigurator(ifaces []vmschema.Interface, networks []vmschem
if iface.Binding == nil || iface.Binding != nil && iface.Binding.Name != PasstPluginName {
return nil, fmt.Errorf("interface %q is not set with Passt network binding plugin", network.Name)
}
if linkFinder == nil {
Copy link
Member

Choose a reason for hiding this comment

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

I would prefer not to have this asked here, as it opens up the option in the tests to use the concrete unintentionally.

We can fix it later though.

)

if _, err := p.linkFinder.LinkByName(optionalLinkName); err != nil {
if _, notFound := err.(vishnetlink.LinkNotFoundError); notFound {
Copy link
Member

Choose a reason for hiding this comment

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

nit: errors.As is also an alternative.

Copy link
Contributor Author

@qinqon qinqon Jul 18, 2024

Choose a reason for hiding this comment

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

That's not working since LinkNotFoundError do not do a proper error implementation, it just wrap an error
https://github.com/vishvananda/netlink/blob/d13535d71ed3e430e26c7538cd6266d026b26f54/link.go#L1412

This is how is tested at their own tests
https://github.com/vishvananda/netlink/blob/main/link_test.go#L2919

@@ -309,5 +324,29 @@ var _ = Describe("pod network configurator", func() {

Expect(testMutator.Mutate(mutatedDomSpec)).To(Equal(mutatedDomSpec))
})
It("should set domain interface source link to the optional one if exists", func() {
Copy link
Member

Choose a reason for hiding this comment

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

Newline is missing (splitting between tests).


Expect(testMutator.Mutate(mutatedDomSpec)).To(Equal(mutatedDomSpec))
})

Copy link
Member

Choose a reason for hiding this comment

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

redundant newline

vmschema "kubevirt.io/api/core/v1"

"kubevirt.io/kubevirt/cmd/sidecars/network-passt-binding/domain"

domainschema "kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

type defaultNetLinkStub struct{}
Copy link
Member

Choose a reason for hiding this comment

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

nit: You do not really need two stub types.

type netLinkStub struct{
    link vishnetlink.Link
    err   error
}

func (nl netLinkStub) LinkByName(name string) (vishnetlink.Link, error) {
    return link, err
}

netlinkStubWithNoLink = &netLinkStub{err: vishnetlink.LinkNotFoundError{}}

And for the single place where you need the link, you just fill it up there:
&netLinkStub{link: &vishnetlink.Veth{LinkAttrs: vishnetlink.LinkAttrs{Name: name}}}

But this is not really a must.

@kubevirt-bot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: EdDev

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 /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubevirt-bot kubevirt-bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 18, 2024
@kubevirt-commenter-bot
Copy link

Required labels detected, running phase 2 presubmits:
/test pull-kubevirt-e2e-windows2016
/test pull-kubevirt-e2e-kind-1.27-vgpu
/test pull-kubevirt-e2e-kind-sriov
/test pull-kubevirt-e2e-k8s-1.30-ipv6-sig-network
/test pull-kubevirt-e2e-k8s-1.28-sig-network
/test pull-kubevirt-e2e-k8s-1.28-sig-storage
/test pull-kubevirt-e2e-k8s-1.28-sig-compute
/test pull-kubevirt-e2e-k8s-1.28-sig-operator
/test pull-kubevirt-e2e-k8s-1.29-sig-network
/test pull-kubevirt-e2e-k8s-1.29-sig-storage
/test pull-kubevirt-e2e-k8s-1.29-sig-compute
/test pull-kubevirt-e2e-k8s-1.29-sig-operator

@qinqon
Copy link
Contributor Author

qinqon commented Jul 18, 2024

Thank you.

The inline comments can be treated later if there is no time at the moment, nothing urgent there.

The usage of the hard-coded optional alternative link name is not that nice, but there is a challenge to pass this information through other means at the moment.

  • Passing information from the CNI step to the sidecar is not trivial.
  • Adding an API field for this is too noisy.
  • Using an admission webhook is possible (adding an env variable for the sidecar given the NAD information) and this could be considered for graduation.

/approve

Tnaks so much!

We will prepare a jira to make kubevirt ovn-kubernetes primary networks aware and address these comments at follow up PR.

@qinqon
Copy link
Contributor Author

qinqon commented Jul 18, 2024

/test pull-kubevirt-e2e-k8s-1.28-sig-compute

@kubevirt-bot kubevirt-bot merged commit 7a7ed78 into kubevirt:main Jul 18, 2024
41 checks passed
@qinqon
Copy link
Contributor Author

qinqon commented Jul 19, 2024

/cherry-pick release-1.3

@kubevirt-bot
Copy link
Contributor

@qinqon: new pull request created: #12409

In response to this:

/cherry-pick release-1.3

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/buildsystem Denotes an issue or PR that relates to changes in the build system. sig/network size/M
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants