Page MenuHomeFreeBSD

if_gif: Add netlink support with tests
Needs ReviewPublic

Authored by pouria on Jun 19 2026, 2:18 PM.
Tags
None
Referenced Files
F163665282: D57666.diff
Sat, Jul 25, 7:17 AM
Unknown Object (File)
Sat, Jul 18, 8:42 AM
Unknown Object (File)
Wed, Jul 15, 1:23 PM
Unknown Object (File)
Mon, Jul 13, 7:03 PM
Unknown Object (File)
Mon, Jul 6, 2:31 PM
Unknown Object (File)
Fri, Jul 3, 12:57 PM
Unknown Object (File)
Tue, Jun 30, 11:45 PM
Unknown Object (File)
Sun, Jun 28, 2:50 PM

Details

Reviewers
melifaro
glebius
markj
ae
Group Reviewers
network
Summary

Migrate to new if_clone KPI and implement netlink support
for gif(4). Also break GIFSOPTS ioctl logic out of gif_ioctl.

Test Plan
kyua test -k /usr/tests/Kyuafile sys/net/if_gif 
kyua test -k /usr/tests/Kyuafile sys/netlink/test_rtnl_gif

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 74634
Build 71517: arc lint + arc unit

Event Timeline

pouria added reviewers: network, glebius, markj, ae.
sys/net/if_gif.c
293

Don't we need to use a lock and check sc != NULL?

335

Same here, we should verify sc != NULL first, or prove it's not possible after all.

pouria marked 2 inline comments as done.

Address @markj comments.

sys/net/if_gif.c
106

Why introduce a macro? Other operations on git_ioctl_sx just use the sx(9) interface directly.

349

I don't think this really makes sense: the interface is about to go away, so why try to optimize for other threads accessing it?

700

Why do we no longer bring the interface down in this case?

sys/net/if_gif.c
106

Simply because other drivers are implemented similarly.
I can remove it.

349

It's not an optimization.
We need this one because if_link_state_change (and there are more) will try to notify other threads that this interface is going down.
Without this, either dump_nl causes a panic or gets stuck.

700

We will do this in gif_clone_destroy after setting ifp->if_sofc to null and downgrading our lock to ensure dump_nl returns early.

sys/net/if_gif.c
349

What exactly is happening? Your explanation doesn't make sense to me, it sounds like there is a deeper bug and downgrading the lock just happens to hide it.

Eh, ok, so further below we release our ifp reference, but meanwhile, the link state change is being handled asynchronously, and there is nothing ensuring that the ifp won't be freed. There is even a comment in if_link_state_change() which points out the bug: /* XXXGL: reference ifp? */.

Downgrading the lock just happens to hide the bug if you're lucky, but that's not the right solution.

What's the purpose of bringing the interface down to begin with if we're about to destroy the interface?

sys/net/if_gif.c
349

Thank you for your review.

What exactly is happening? Your explanation doesn't make sense to me, it sounds like there is a deeper bug and downgrading the lock just happens to hide it.

Yes, there is a deeper problem, and no, I'm not trying to hide it by downgrading.
I've done the same in D57669.

Here is the problem:
If anyone tries to dump/modify the interface using netlink (async) during clone_destroy, there is a gap where the softc is freed but the interface still exists.
Netlink acquires a reference to ifp during modify_link and rtnl_handle_getlink calls in sys/netlink/route/iface.c: 484, 489, 634, and 644 to ensure ifp won't get freed until it's done, and then it calls the [dump|modify]_nl.

Drivers can ensure the softc pointer is consistent using rmlock/rwlock like geneve(4), or they can downgrade their lock (which I'm proposing) like below:

gif_clone_dump_nl()
...
	sx_slock(&gif_ioctl_sx);
	sc = ifp->if_softc;
	if (sc == NULL)
		goto ret;

Eh, ok, so further below we release our ifp reference, but meanwhile, the link state change is being handled asynchronously, and there is nothing ensuring that the ifp won't be freed. There is even a comment in if_link_state_change() which points out the bug: /* XXXGL: reference ifp? */.

netlink does it for us.

Downgrading the lock just happens to hide the bug if you're lucky, but that's not the right solution.

What's the purpose of bringing the interface down to begin with if we're about to destroy the interface?

It's not a problem of if_link_state_change() because anyone can call dump_nl in another thread at the same time.
The purpose of if_link_state_change() in every interface driver is to notify that the interface is going down, which gives time to other software/modules to prepare themselves.

sys/net/if_gif.c
349

Drivers can ensure the softc pointer is consistent using rmlock/rwlock like geneve(4), or they can downgrade their lock (which I'm proposing) like below:

What does downgrading the lock accomplish, specifically? If we do not downgrade, then gif_clone_dump_nl() will block on the ioctl lock until gif_clone_destroy() releases the lock. When it finally acquires the lock it'll observe if_softc == NULL and return. Can you provide more details on the crash or hang that you saw?

Basically, I am very skeptical that downgrading a lock can ever be the correct solution to a hang or crash. At best it is making the bug harder to hit.

netlink does it for us.

That is too late. It needs to be done before the task is scheduled. Look at do_link_state_change(): what is keeping the ifnet alive while it is running eventhandlers etc.?

sys/net/if_gif.c
349

What does downgrading the lock accomplish, specifically? If we do not downgrade, then gif_clone_dump_nl() will block on the ioctl lock until gif_clone_destroy() releases the lock. When it finally acquires the lock it'll observe if_softc == NULL and return. Can you provide more details on the crash or hang that you saw?

After moving if_link_state_change() out of gif_delete_tunnel(), I'm not able to reproduce that, not sure why, maybe that's enough and I was wrong.

Basically, I am very skeptical that downgrading a lock can ever be the correct solution to a hang or crash. At best it is making the bug harder to hit.

There are multiple benefits to downgrading the lock, particularly in the case of clone_destroy:

  1. If we maintain the WLOCK until if_detach completes, do_link_state_change become pointless, because by the time software or other modules are notified, the interface is destroyed by if_detach() and simultaneously we have another notification by if_detach_internal to rtnl_handle_ifnet_event which says the interface is gone.
  2. If we release the WLOCK only after setting ifp->if_softc to NULL, theoretically another thread might attempt an ifp-only modification (such as changing the address or mtu) simultaneously, and it might result in a panic.

Downgrading a lock prevents another thread to acquire an exclusive lock without pausing other read operations.
That's why I believe it's more safe and helpful.

netlink does it for us.

That is too late. It needs to be done before the task is scheduled. Look at do_link_state_change(): what is keeping the ifnet alive while it is running eventhandlers etc.?

The caller is responsible for this.
Now, due to our current implementation constraints it doesn't make sense to reference ifp during task_enqueue, so all drivers must ensure they call it at the appropriate time.

In contrast to if_gre, we actually can continue without lock downgrade, but I believe it could be unsafe to do so.