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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Nov 14, 2024 at 12:46 AM Hangbin Liu <liuhangbin@xxxxxxxxx> wrote:
>
> 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.

Hi Hangbin,

My apologies, I should have shared my version of the check function
before. Here it is:

```bash
# Called to validate the addresses on $IFNAME:
#
# 1. Every `temporary` address must have a matching `mngtmpaddr`
# 2. Every `mngtmpaddr` address must have some un`deprecated` `temporary`
#
# Fails the whole test script if a problem is detected, else returns silently.
validate()
{
    mng_prefixes=()
    undep_prefixes=()
    temp_addrs=()

    while read -r line; do
        line_array=($line)
        address="${line_array[1]}"
        prefix="$(echo "$address" | cut -d: -f1-4)::/64"
        if echo "$line" | grep -q mngtmpaddr; then
            mng_prefixes+=("$prefix")
        elif echo "$line" | grep -q temporary; then
            temp_addrs+=("$address")
            if echo "$line" | grep -qv deprecated; then
                undep_prefixes+=("$prefix")
            fi
        fi
    done < <(ip -6 addr show dev $IFNAME | grep '^\s*inet6')

    # 1. All temporary addresses (temp and dep) must have a matching mngtmpaddr
    for address in ${temp_addrs[@]}; do
        prefix="$(echo "$address" | cut -d: -f1-4)::/64"
        if [[ ! " ${mng_prefixes[*]} " =~ " $prefix " ]]; then
            echo "FAIL: Temporary $address with no matching mngtmpaddr!";
            exit 1
        fi
    done

    # 2. All mngtmpaddr addresses must have a temporary address (not dep)
    for prefix in ${mng_prefixes[@]}; do
        if [[ ! " ${undep_prefixes[*]} " =~ " $prefix " ]]; then
            echo "FAIL: No undeprecated temporary in $prefix!";
            exit 1
        fi
    done
}
```

Of course this is using awful text parsing and not JSON output. But
the idea is that it groups addresses by their /64 prefix, to confirm
that every /64 containing a mngtmpaddrs address also contains an
undeprecated temporary, and that every /64 containing a temporary
(deprecated or not) contains a mngtmpaddrs.

This can be extended for the lifetime checking: when we build the set
of mngtmpaddrs /64s, we also note the valid/preferred_life_time values
for each mngtmpaddr. Then later when we confirm rule 1 (all temporary
addresses must have a matching mngtmpaddr) we also confirm that each
temporary does not outlive the mngtmpaddr in the same /64.

Happy Friday,
Sam

>
> > > +
> > > +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





[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux