Subject: Re: [PATCH net 2/2] selftests/rtnetlink.sh: add mngtempaddr test

From: Hangbin Liu <[email-masked]>
Date: Thu, 14 Nov 2024 08:46:33 +0000

Hi Sam,

On Wed, Nov 13, 2024 at 12:43:00PM -0800, Sam Edwards wrote:
> > +# If the mngtmpaddr or tempaddr missing, return 0 and stop waiting
> > +check_tempaddr_exists()
> > +{
> > +       local start=${1-"1"}
> > +       addr_list=$(ip -j -n $testns addr show dev ${devdummy})
> > +       for i in $(seq $start 4); do
> > +               if ! echo ${addr_list} | \
> > +                    jq -r '.[].addr_info[] | select(.mngtmpaddr == true) | .local' | \
> > +                    grep -q "200${i}"; then
> > +                       check_err $? "No mngtmpaddr 200${i}:db8::1"
> > +                       return 0
> > +               fi
> > +
> > +               if ! echo ${addr_list} | \
> > +                    jq -r '.[].addr_info[] | select(.temporary == true) | .local' | \
> > +                    grep -q "200${i}"; then
> > +                       check_err $? "No tempaddr for 200${i}:db8::1"
> > +                       return 0
> > +               fi
> > +       done
> > +       return 1
> > +}
> 
> The variant of this function that I implemented is a lot less "fixed"
> and gathers all IPv6 prefixes (by /64) into one of 3 sets:
> 1. mngtmpaddr
> 2. temporary, not deprecated
> 3. temporary (whether deprecated or not)
> 
> It then ensures that set 3 is a subset of set 1, and set 1 is a subset
> of set 2. (And if it's easy: it should also ensure that no 'temporary'
> has a *_lft in excess of its parent's.)

I'm not totally get your explanation here. e.g. with preferred_lft 10,
valid_lft 30. I got the following result.

# ip addr show dummy0
3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 2e:f7:df:87:44:64 brd ff:ff:ff:ff:ff:ff
    inet6 2001::743:ec1e:5c19:404f/64 scope global temporary dynamic
       valid_lft 25sec preferred_lft 5sec
    inet6 2001::938f:432:f32d:602f/64 scope global temporary dynamic
       valid_lft 19sec preferred_lft 0sec
    inet6 2001::5b65:c0a3:cd8c:edf8/64 scope global temporary deprecated dynamic
       valid_lft 3sec preferred_lft 0sec
    inet6 2001::8a7e:6e8d:83f1:9ea0/64 scope global temporary deprecated dynamic
       valid_lft 0sec preferred_lft 0sec
    inet6 2001::1/64 scope global mngtmpaddr
       valid_lft forever preferred_lft forever

So there are 1 mngtmpaddr, 2 temporary address (not deprecated). 4 total
temporary address. Based on your rule. It should be set 1 is a subset of
set 2. Set 2 is a subset of 3.

And how do we ensure that no 'temporary' has a *_lft in excess of its parent's.

> Doing it this way allows the test case to create, modify, and delete
> mngtmpaddrs according to the needs of the test, and the check()
> function only ensures that the rules are being obeyed, it doesn't make
> assumptions about the expected state of the addresses.

I'm not sure if this is totally enough. What if there are 3 mngtmpaddrs
and 4 temporary address. But actually 1 mngtmpaddrs doesn't have temporary
address. Maybe check() needs to check only 1 prefix each time.
 
> > +
> > +kci_test_mngtmpaddr()
> > +{
> > +       local ret=0
> > +
> > +       setup_ns testns
> > +       if [ $? -ne 0 ]; then
> > +               end_test "SKIP mngtmpaddr tests: cannot add net namespace $testns"
> > +               return $ksft_skip
> > +       fi
> > +
> > +       # 1. Create a dummy Ethernet interface
> > +       run_cmd ip -n $testns link add ${devdummy} type dummy
> > +       run_cmd ip -n $testns link set ${devdummy} up
> > +       run_cmd ip netns exec $testns sysctl -w net.ipv6.conf.${devdummy}.use_tempaddr=1
> 
> Test should also set .temp_prefered_lft and .temp_valid_lft here.
> 
> I also set .max_desync_factor=0 because this is a dummy interface that
> doesn't have any latency, which allows the prefer lifetime to be
> pretty short. (See below.)

Thanks, I will fix the test.
> 
> > +       # 2. Create several (3-4) mngtmpaddr addresses on that interface.
> > +       # with temp_*_lft configured to be pretty short (10 and 35 seconds
> > +       # for prefer/valid respectively)
> > +       for i in $(seq 1 4); do
> > +               run_cmd ip -n $testns addr add 200${i}:db8::1/64 dev ${devdummy} mngtmpaddr
> 
> I don't really like using 200X:db8::1 as the test addresses.
> 2001:db8::/32 is the IANA designated prefix for examples/documentation
> (and, by extension, unit tests) so we should really try to remain
> inside that.
> 
> Personally, I tend to use 2001:db8:7e57:X::/64 ("test" in leetspeak)
> just to minimize the chances of conflicting with something else in the
> system. Though, with the test happening in its own netns, *that* level
> of caution may not be necessary.
> 
> Still, 2001:db8::/32 is what IPv6 folks expect, so I'd want to stay in there.

OK, I will use 2001:db8::/32 for testing.

> 
> > +               tempaddr=$(ip -j -n $testns addr show dev ${devdummy} | \
> > +                          jq -r '.[].addr_info[] | select(.temporary == true) | .local' | \
> > +                          grep 200${i})
> > +               #3. Confirm that temporary addresses are created immediately.
> 
> This could simply be a call to the above genericized check() function.
> 
> > +               if [ -z $tempaddr ]; then
> > +                       check_err 1 "no tempaddr created for 200${i}:db8::1"
> > +               else
> > +                       run_cmd ip -n $testns addr change $tempaddr dev ${devdummy} \
> > +                               preferred_lft 10 valid_lft 35
> 
> While Linux is (apparently) happy to let userspace modify the
> tempaddr's remaining lifetime like this, I don't think this is a
> common or recommended practice. Rather, the test should be letting
> Linux manage the tempaddr lifetimes and rotate the addresses itself.

OK

> 
> > +               fi
> > +       done
> 
> Here is a good place to create an address that *isn't* mngtmpaddr,
> confirm there is no temporary (via call to check() function), then add
> the `mngtmpaddr` flag after the fact.

OK, I will
> 
> > +
> > +       #4. Confirm that a preferred temporary address exists for each mngtmpaddr
> > +       #   address at all times, polling once per second for at least 5 minutes.
> > +       slowwait 300 check_tempaddr_exists
> 
> So I previously said "wait 5 minutes" but I later saw in the
> documentation for the selftest suite that maintainers really don't
> like it when a test takes more than ~45 seconds to run. We might want
> to drop this wait to 30 by default and accelerate the timetable on
> prefer/valid lifetimes to something like 10/25.

Yes, 5m is too long for a single test.

> > +
> > +       end_test "PASS: mngtmpaddr add/remove correctly"
> > +       ip netns del "$testns"
> 
> Do we need to make sure the netns gets cleaned up via `trap ... EXIT`
> so that it doesn't leak if the user interrupts the test? Or does the
> greater test fixture take care of that for us?

No, rtnetlink.sh doesn't have a trap function. I plan to add the trap
function separately.

Thanks
Hangbin