Page MenuHomeFreeBSD

tuntap: add SIOCGIFCAP and SIOCSIFCAP ioctls
AcceptedPublic

Authored by timo.voelker_fh-muenster.de on Jul 13 2025, 2:24 PM.
Tags
None
Referenced Files
F131455107: D51289.diff
Wed, Oct 8, 5:51 AM
Unknown Object (File)
Sun, Sep 28, 1:46 AM
Unknown Object (File)
Sat, Sep 27, 5:30 AM
Unknown Object (File)
Sun, Sep 21, 3:31 PM
Unknown Object (File)
Sat, Sep 20, 4:56 PM
Unknown Object (File)
Sat, Sep 20, 4:55 PM
Unknown Object (File)
Thu, Sep 11, 9:28 AM
Unknown Object (File)
Thu, Sep 11, 4:05 AM

Details

Summary

Add SIOCGIFCAP ioctl-command for tun/tap character device to be used by bhyve for offloading in the future.
Add SIOCSIFCAP for symmetry.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

Adding Mark as a solid intersection between 'has touched tun/tap' and bhyve, though my recollection is that nothing would prevent a concurrent TAPSVNETHDR so we probably want SIOCGIFCAP to also take the lock and provide a consistent view of if_capabilities/if_capenable?

I'm also unsure that SIOCSIFCAP is sufficient; do we need to take into account the possible loss (or addition) of TAP_VNET_HDR_CAPS and reject that? Ditto that question for the interface ioctl handler, apparently.

Adding Mark as a solid intersection between 'has touched tun/tap' and bhyve, though my recollection is that nothing would prevent a concurrent TAPSVNETHDR so we probably want SIOCGIFCAP to also take the lock and provide a consistent view of if_capabilities/if_capenable?

Yes, I agree.

These ioctls should be documented in tun.4 as well.

I'm also unsure that SIOCSIFCAP is sufficient; do we need to take into account the possible loss (or addition) of TAP_VNET_HDR_CAPS and reject that? Ditto that question for the interface ioctl handler, apparently.

tun_caps_changed() and tunwrite_l2(), for example, seem to handle the possibility that some of those caps are disabled. I'm not sure why we'd reject a request to clear something from TAP_VNET_HDR_CAPS?

[... snip ...]

I'm also unsure that SIOCSIFCAP is sufficient; do we need to take into account the possible loss (or addition) of TAP_VNET_HDR_CAPS and reject that? Ditto that question for the interface ioctl handler, apparently.

tun_caps_changed() and tunwrite_l2(), for example, seem to handle the possibility that some of those caps are disabled. I'm not sure why we'd reject a request to clear something from TAP_VNET_HDR_CAPS?

Sorry, this was both poorly thought out and poorly communicated. My general concern here is that we could put ourselves into a weird position if we start disabling capabilities that we'd expect if tun_vhdrlen != 0 and that it'd be better to force TAPSVNETHDR to disable it instead, but I'm not sure that there's anything technically wrong with that and it's perhaps better to just assume userland knows what they're doing if it's relatively harmless.

Some more thoughts:

  • The interface ioctl path is gated behind PRIV_NET_SETIFCAP; should we do the same here? We're issued through the cdev via an fd that would indicate we have some sort of ownership of it, so I would imagine not.
  • The interface ioctl path also kicks back EINVAL if one would try to enable a capability not in if_capabilities; should we do the same here?
  • Do we need to set if_lastchange here?
This comment was removed by kevans.

Thanks for your review @kevans

we probably want SIOCGIFCAP to also take the lock and provide a consistent view of if_capabilities/if_capenable?

You mean a lock that protects lines 1660 and 1661?

My general concern here is that we could put ourselves into a weird position if we start disabling capabilities that we'd expect if tun_vhdrlen != 0 and that it'd be better to force TAPSVNETHDR to disable it instead

Currently, I don't need SIOCSIFCAP. I can just remove the code if that resolves concerns.

The interface ioctl path is gated behind PRIV_NET_SETIFCAP; should we do the same here?

I don't know what that is. I can't find PRIV_NET_SETIFCAP in tuntap.c.

The interface ioctl path also kicks back EINVAL if one would try to enable a capability not in if_capabilities; should we do the same here?

I can't find the code that kicks back EINVAL in tuntap.c. Is it somewhere outside?

Do we need to set if_lastchange here?

I don't know what that is.

Thanks for your review @markj

These ioctls should be documented in tun.4 as well.

Since the existing SIOCGIFCAP for the interface is not documented in tun.4, my assumption was that such an ioctl is generic and does not need documentation in a specific interface man mage. Is that not correct?

Thanks for your review @kevans

we probably want SIOCGIFCAP to also take the lock and provide a consistent view of if_capabilities/if_capenable?

You mean a lock that protects lines 1660 and 1661?

Correct

My general concern here is that we could put ourselves into a weird position if we start disabling capabilities that we'd expect if tun_vhdrlen != 0 and that it'd be better to force TAPSVNETHDR to disable it instead

Currently, I don't need SIOCSIFCAP. I can just remove the code if that resolves concerns.

I think I'm OK either way- you're preserving an existing problem at most, and it's not even a major problem.

The interface ioctl path is gated behind PRIV_NET_SETIFCAP; should we do the same here?

I don't know what that is. I can't find PRIV_NET_SETIFCAP in tuntap.c.

The interface ioctl path also kicks back EINVAL if one would try to enable a capability not in if_capabilities; should we do the same here?

I can't find the code that kicks back EINVAL in tuntap.c. Is it somewhere outside?

Both of these are provided by the path that gets us into an ifnet's if_ioctl -- see ifioctl in if.c, SIOCSIFCAP.

Do we need to set if_lastchange here?

I don't know what that is.

Time of last administrative change (also done by ifioctl noted above), I'm unsure if it really matters much.

My general concern here is that we could put ourselves into a weird position if we start disabling capabilities that we'd expect if tun_vhdrlen != 0 and that it'd be better to force TAPSVNETHDR to disable it instead

Currently, I don't need SIOCSIFCAP. I can just remove the code if that resolves concerns.

I think I'm OK either way- you're preserving an existing problem at most, and it's not even a major problem.

I would like address your concerns, but I'm not sure if I fully understand them. Here is my understanding.

tap interface has initially these capabilities:

IFCAP_LINKSTATE, IFCAP_MEXTPG, IFCAP_RXCSUM, IFCAP_RXCSUM_IPV6, IFCAP_LRO

and these are enabled by default:

IFCAP_LINKSTATE, IFCAP_MEXTPG

Setting a vhdrlen > 0 with TAPSVNETHDR adds these capabilities without enabling them:

IFCAP_RXCSUM, IFCAP_TXCSUM, IFCAP_RXCSUM_IPV6, IFCAP_TXCSUM_IPV6, IFCAP_VLAN_HWCSUM, IFCAP_TSO, IFCAP_LRO, IFCAP_VLAN_HWTSO

Now, with the new SIOCSIFCAP one can enable or disable these capabilities. Is this your concern?

I assume the code never expects one of these capabilities enabled, otherwise setting vhdrlen > 0 with TAPSVNETHDR would have enabled them directly. Right?

Addressed @kevans's comment regarding using a lock for SIOCGIFCAP.

I don't know what that is. I can't find PRIV_NET_SETIFCAP in tuntap.c.

AFAIK, tunioctl is not called after ifhwioctl, however, I don't think it's necessary, since other cases of tunioctl are also lack privilege check.

I can't find the code that kicks back EINVAL in tuntap.c. Is it somewhere outside?

It's in sys/net/if.c at 2614:

if (ifr->ifr_reqcap & ~ifp->if_capabilities)
    return (EINVAL);

I think it should be there too.

Do we need to set if_lastchange here?

I don't know what that is.

It's the time of last administrative change which is set by default in ifhwioctl for tunifioctl.
I don't think it should be updated here in tunioctl. It's not clear whether changes made by tunioctl (as opposed to tunifioctl) are considered administrative.
Also, if we're going to update if_lastchange here, we must update the other ioctl cases as well.

For SIOCSIFCAP, check if requested capabilities are supported before enabling them.

I don't know what that is. I can't find PRIV_NET_SETIFCAP in tuntap.c.

AFAIK, tunioctl is not called after ifhwioctl, however, I don't think it's necessary, since other cases of tunioctl are also lack privilege check.

Agree.

I can't find the code that kicks back EINVAL in tuntap.c. Is it somewhere outside?

It's in sys/net/if.c at 2614:

if (ifr->ifr_reqcap & ~ifp->if_capabilities)
    return (EINVAL);

I think it should be there too.

I made a small test. Without this check it is possible to enable capabilities that are not supported. I just added this if statement.

Do we need to set if_lastchange here?

I don't know what that is.

It's the time of last administrative change which is set by default in ifhwioctl for tunifioctl.
I don't think it should be updated here in tunioctl. It's not clear whether changes made by tunioctl (as opposed to tunifioctl) are considered administrative.
Also, if we're going to update if_lastchange here, we must update the other ioctl cases as well.

Agree.

Thanks for your explanations.

This revision is now accepted and ready to land.Sep 1 2025, 11:32 AM

Do we need to set if_lastchange here?

I don't know what that is.

It's the time of last administrative change which is set by default in ifhwioctl for tunifioctl.
I don't think it should be updated here in tunioctl. It's not clear whether changes made by tunioctl (as opposed to tunifioctl) are considered administrative.
Also, if we're going to update if_lastchange here, we must update the other ioctl cases as well.

Agree.

Thanks for your explanations.

@ae @melifaro
could you take a look and share your thoughts on the if_lastchange here?