[libvirt] [PATCH v2] test_driver: properly handle DHCP ranges and IPv6 networks in testDomainInterfaceAddresses

Ilias Stamatis stamatis.iliass at gmail.com
Fri Jun 21 09:49:27 UTC 2019


On Fri, Jun 21, 2019 at 10:03 AM Michal Privoznik <mprivozn at redhat.com> wrote:
>
> On 6/20/19 7:36 PM, Ilias Stamatis wrote:
> > On Thu, Jun 20, 2019 at 5:57 PM Michal Privoznik <mprivozn at redhat.com> wrote:
> >>
> >> On 6/19/19 6:45 PM, Ilias Stamatis wrote:
> >>> testDomainInterfaceAddresses always returns the same hard-coded
> >>> addresses. Change the behavior such as if there is a DHCP range defined,
> >>> addresses are returned from that pool.
> >>>
> >>> The specific address returned depends on both the domain id and the
> >>> specific guest interface in an attempt to return unique addresses *most
> >>> of the time*.
> >>>
> >>> Additionally, properly handle IPv6 networks which were previously
> >>> ignored completely.
> >>>
> >>> Signed-off-by: Ilias Stamatis <stamatis.iliass at gmail.com>
> >>> ---
> >>>    src/test/test_driver.c | 44 +++++++++++++++++++++++++++++++++++++-----
> >>>    1 file changed, 39 insertions(+), 5 deletions(-)
> >>>
> >>> diff --git a/src/test/test_driver.c b/src/test/test_driver.c
> >>> index 2a0ffbc6c5..21bd95941e 100755
> >>> --- a/src/test/test_driver.c
> >>> +++ b/src/test/test_driver.c
> >>> @@ -3414,6 +3414,10 @@ static int testDomainBlockStats(virDomainPtr domain,
> >>>        return ret;
> >>>    }
> >>>
> >>> +
> >>> +static virNetworkObjPtr testNetworkObjFindByName(testDriverPtr privconn, const char *name);
> >>> +
> >>> +
> >>>    static int
> >>>    testDomainInterfaceAddresses(virDomainPtr dom,
> >>>                                 virDomainInterfacePtr **ifaces,
> >>> @@ -3422,11 +3426,15 @@ testDomainInterfaceAddresses(virDomainPtr dom,
> >>>    {
> >>>        size_t i;
> >>>        size_t ifaces_count = 0;
> >>> +    size_t addr_offset;
> >>>        int ret = -1;
> >>>        char macaddr[VIR_MAC_STRING_BUFLEN];
> >>>        virDomainObjPtr vm = NULL;
> >>>        virDomainInterfacePtr iface = NULL;
> >>>        virDomainInterfacePtr *ifaces_ret = NULL;
> >>> +    virSocketAddr addr;
> >>> +    virNetworkObjPtr net = NULL;
> >>> +    virNetworkDefPtr net_def = NULL;
> >>>
> >>>        virCheckFlags(0, -1);
> >>>
> >>> @@ -3447,6 +3455,12 @@ testDomainInterfaceAddresses(virDomainPtr dom,
> >>>            goto cleanup;
> >>>
> >>>        for (i = 0; i < vm->def->nnets; i++) {
> >>> +        if (!(net = testNetworkObjFindByName(dom->conn->privateData,
> >>> +                                             vm->def->nets[i]->data.network.name)))
> >>
> >> This is unsafe. We can access ->data.network iff type is NETWORK.
> >>
> >>> +            goto cleanup;
> >>> +
> >>> +        net_def = virNetworkObjGetDef(net);
> >>> +
> >>>            if (VIR_ALLOC(iface) < 0)
> >>>                goto cleanup;
> >>>
> >>> @@ -3460,14 +3474,33 @@ testDomainInterfaceAddresses(virDomainPtr dom,
> >>>            if (VIR_ALLOC(iface->addrs) < 0)
> >>>                goto cleanup;
> >>>
> >>> -        iface->addrs[0].type = VIR_IP_ADDR_TYPE_IPV4;
> >>> -        iface->addrs[0].prefix = 24;
> >>> -        if (virAsprintf(&iface->addrs[0].addr, "192.168.0.%zu", 1 + i) < 0)
> >>> -            goto cleanup;
> >>> -
> >>
> >> Instead of removing, we can use this for !NETWORK types.
> >>
> >>>            iface->naddrs = 1;
> >>> +        iface->addrs[0].prefix = virSocketAddrGetIPPrefix(&net_def->ips->address,
> >>> +                                                          &net_def->ips->netmask,
> >>> +                                                          net_def->ips->prefix);
> >>> +
> >>> +        if (net_def->ips->nranges > 0)
> >>> +            addr = net_def->ips->ranges[0].start;
> >>> +        else
> >>> +            addr = net_def->ips->address;
> >>> +
> >>> +        /* try using different addresses per different inf and domain */
> >>> +        addr_offset = 20 * (vm->def->id - 1) + i + 1;
> >>> +
> >>> +        if (net_def->ips->family && STREQ(net_def->ips->family, "ipv6")) {
> >>> +            iface->addrs[0].type = VIR_IP_ADDR_TYPE_IPV6;
> >>> +            addr.data.inet6.sin6_addr.s6_addr[15] += addr_offset;
> >>> +        } else {
> >>> +            iface->addrs[0].type = VIR_IP_ADDR_TYPE_IPV4;
> >>> +            addr.data.inet4.sin_addr.s_addr = \
> >>> +                htonl(ntohl(addr.data.inet4.sin_addr.s_addr) + addr_offset);
> >>> +        }
> >>> +
> >>> +        if (!(iface->addrs[0].addr = virSocketAddrFormat(&addr)))
> >>> +            goto cleanup;
> >>>
> >>>            VIR_APPEND_ELEMENT_INPLACE(ifaces_ret, ifaces_count, iface);
> >>> +        virNetworkObjEndAPI(&net);
> >>
> >> This should be moved into a separate function.
> >>
> >>>        }
> >>>
> >>>        VIR_STEAL_PTR(*ifaces, ifaces_ret);
> >>> @@ -3475,6 +3508,7 @@ testDomainInterfaceAddresses(virDomainPtr dom,
> >>>
> >>>     cleanup:
> >>>        virDomainObjEndAPI(&vm);
> >>> +    virNetworkObjEndAPI(&net);
> >>>
> >>>        if (ifaces_ret) {
> >>>            for (i = 0; i < ifaces_count; i++)
> >>
> >>
> >> With all that fixed, I've ACKed and pushed this patch. Thank you for
> >> taking care of this.
> >>
> >> Michal
> >
> > Just a tiny nitpick by me as well on the code you pushed.
> >
> > The addr_offset can be used also for the non-network infs in order to
> > attempt always having unique ips.
> >
> > ie instead of:
> > if (virAsprintf(&iface->addrs[0].addr, "192.168.0.%zu", 1 + i) < 0)
> >
> > it can be:
> > if (virAsprintf(&iface->addrs[0].addr, "192.168.0.%zu", addr_offset) < 0)
>
> Ah right.
>
> >
> > Also, I don't know how strict we are on enforcing the coding
> > guidelines but 2 variables are not declared in the beginning of the
> > function but later.
>
> Ideally (and honestly I don't know how our coding style is specified in
> this regard O:-)), any variable would be defined at the lowest possible
> scope. For instance, if a variable is used only within a loop body, then
> it increases code readability if the variable is defined only inside the
> loop (at its beginning of course). Because when I'm reading the code and
> find such variable I can be sure that it's not used outside of the loop
> and thus if I'm not interested in the loop I can skip it and don't have
> to track the variable or find out its meaning.
>
> Of course, this is not always possible, for instance, if there's a
> variable that holds a pointer to an object that needs to be unrefed at
> the end of every iteration and there are some 'goto cleanup'-s inside
> the loop body. Just like in your patch. Then of course the variable
> needs to be defined for the whole function so that 'cleanup' label can
> do the unref.
>
> A picture is worth a thousand words:
>
> void f() {
>    int i;
>    int tmp;
>
>    for (i = 0; i < 100; i++) {
>      tmp = rand() % 10;
>      printf("sleeping for %d seconds\n", tmp);
>      sleep(tmp);
>    }
>
>    /* some buggy area here */
> }
>
> versus:
>
> void f() {
>    int i;
>
>    for (i = 0; i < 100; i++) {
>      int tmp = rand() % 10;
>      printf("sleeping for %d seconds\n", tmp);
>      sleep(tmp);
>    }
>
>    /* some buggy area here */
> }
>
>
> IMO, the second version is more readable.
>
> Michal

I totally agree with you, it's more readable for me too.

Just so far I haven't encountered in the code. Also e.g. C99 allows
variables to be declared inside a loop ie

for (size_t i = 0; ...

...but I haven't seen that being used anywhere either.

Anyway I just wasn't sure about the guidelines, that's why I brought it up.

Thanks,
Ilias




More information about the libvir-list mailing list