Page MenuHomeFreeBSD

Properly handle case when system is out of network interface numbers
Needs ReviewPublic

Authored by hselasky on Oct 17 2018, 4:50 PM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Oct 15, 3:39 AM
Unknown Object (File)
Sat, Oct 11, 2:32 PM
Unknown Object (File)
Mon, Oct 6, 5:16 PM
Unknown Object (File)
Thu, Oct 2, 10:53 AM
Unknown Object (File)
Fri, Sep 26, 2:54 AM
Unknown Object (File)
Sep 14 2025, 9:19 AM
Unknown Object (File)
Sep 11 2025, 12:58 PM
Unknown Object (File)
Sep 1 2025, 11:11 PM

Details

Reviewers
kib
mmacy
slavash
Group Reviewers
network
Summary

Whenever ifindex_alloc() returns USHRT_MAX the old pointer must be set else if_alloc() may free bogus value on the stack causing various kinds of failures in addition to going into an infinite loop. This change is a minor refactoring of the ifindex management. Use a single SX lock to protect the interface pointer array. Because this code is not in the fast path prefer simplicity over complexity. Some minor adaptions for epoch(9) usage.

Test Plan

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 20337

Event Timeline

Can you reupload the diff with full context ?

kib added inline comments.
sys/net/if.c
577

I suggest adding a printf() there stating the cause of failure at least in dmesg.

This revision is now accepted and ready to land.Oct 18 2018, 10:59 AM

Update as per kib's suggestion.

This revision now requires review to proceed.Oct 18 2018, 11:50 AM
This revision is now accepted and ready to land.Oct 18 2018, 12:52 PM

Found more issues related - fix while at it.

This revision now requires review to proceed.Oct 18 2018, 2:05 PM
sys/net/if.c
1310

This means that the thread never leaves the kernel and is not interruptible, am I wrong ? previous version of the patch did not looped indefinitely.

hselasky added inline comments.
sys/net/if.c
1310

Yes, that is correct, until there is a network device available. Is panicing better here?

Can we drop the operation, leaving the kernel structures in consistent state ?

eugen_grosbein.net added inline comments.
sys/net/if.c
1310

It would be better to place some limit on the loop then fail.
No reason to panic here. There are not many consumers of of if_vmove() and I see no reason why they cannot fail too.

Silly question; can you explain that test case? How do 255 multicast addresses assigned to 255 interfaces make you run out of ifindex space?

But more importantly I was wondering why this was epoch()ified in first place; if_grow() is a 8 times in an uptime operation if my memory serves me right. Taking a lock for that and waiting a few ms longer won't slow you down much more than a timer tick does during packet processing. Just seems weird to me.

Silly question; can you explain that test case? How do 255 multicast addresses assigned to 255 interfaces make you run out of ifindex space?

The code was hung for other reasons in epoch_wait_preempt() due to an EPOCH LOR, and you're right that the test doesn't hang with condition idx == USHRT_MAX. This was my first shot. Then I realized the code was a bit broken in other ways too.

hselasky added inline comments.
sys/net/if.c
1310

Sure, I'll try to extend the patch.

@bz: Try modifying the script to create 65536 /dev/tun devices.

@bz: Try modifying the script to create 65536 /dev/tun devices.

lo(4) or disc(4) might be easier. And you don't need addresses on then; And you don't need 64k though that's good to test the edge case as well for the newly discovered problem, for the original bumping over the next power-of-2 would have called if_grow() and given you a test.

I am still wondering if simply reverting to classic locking for this might make a lot more sense?

hselasky edited the summary of this revision. (Show Details)

Taking advice from @bz to use a single SX lock for managing ifindex allocation.

What's the reason we can't just use the IFNET_WLOCK() and be good with it and not rewriting the entire code but going back to what it was?
The original version if_grow() could not fail, ifindex_alloc() had at best one retry, ... I am still not getting why this wasn't good enough?

@bz: Answering your one question off the bat: IF_WLOCK() doesn't allow sleeping I.E. malloc() with M_WAITOK. That was one point for this change to allow all operation under one lock, instead of unlocking and then trying to catch races and goto retry and so on.

I'll come back to your second question tomorrow.

@hselasky this is getting super complicated - how much can we avoid by replacing the epoch_wait()+free() with an epoch_call()?

@mmacy: The problem in this patch is that the network device table is growing dynamically and that we are replacing it as we need more ifunits. Given this code is called pretty rarely, I don't see any point using epoch_call() to free the old structure. Using epoch_call() does not get rid of the grow SX-lock.