<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size: 12pt; color: rgb(0, 0, 0); font-family: Calibri, Helvetica, sans-serif, "EmojiFont", "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols;" dir="ltr">
<p style="margin-top:0;margin-bottom:0"></p>
<div>Thanks again John for giving detailed review and feedback for v3 patchset.<br>
I have tried incorporating the suggestions in v4.     <br>
<br>
v4: https://www.redhat.com/archives/libvir-list/2018-June/msg01807.html<br>
<br>
</div>
<p></p>
<p style="margin-top:0;margin-bottom:0">-Jai<br>
</p>
<br>
<div style="color: rgb(49, 54, 59);">
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font style="font-size:11pt" face="Calibri, sans-serif" color="#000000"><b>From:</b> John Ferlan <jferlan@redhat.com><br>
<b>Sent:</b> 13 April 2018 00:38<br>
<b>To:</b> Jai Singh Rana; libvir-list@redhat.com<br>
<b>Cc:</b> Rana, JaiSingh<br>
<b>Subject:</b> Re: [libvirt] [PATCH v3 1/2] util: Add helper APIs to get/verify VF Representor name</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt;">
<div class="PlainText"><br>
<br>
On 04/04/2018 12:29 PM, Jai Singh Rana wrote:<br>
> Switchdev VF representor interface name on host is queried based on<br>
> Bus:Device:Function information of pci SR-IOV device in Domain's<br>
> 'hostdev' structure and subsequently verifying the required net sysfs<br>
> directory and file entries of VF representor according to switchdev<br>
> model.<br>
<br>
You are missing the S-o-b:<br>
<br>
The someone new policy is that:<br>
<br>
Contributors to libvirt projects must assert that they are in compliance<br>
with the Developer Certificate of Origin 1.1. This is achieved by adding<br>
a "Signed-off-by" line containing the contributor's name and e-mail to<br>
every commit message. The presence of this line attests that the<br>
contributor has read the above lined DCO and agrees with its statements.<br>
<br>
<a href="https://developercertificate.org/" id="LPlnk442322" class="OWAAutoLink" previewremoved="true">https://developercertificate.org/</a><br>
<br>
> ---<br>
> v3 includes changes based on v2's[1] feedback and suggestions. Fixes<br>
> warnings reported by syntax-check.<br>
> [1] <a href="https://www.redhat.com/archives/libvir-list/2018-February/msg00562.html" id="LPlnk936334" class="OWAAutoLink" previewremoved="true">
https://www.redhat.com/archives/libvir-list/2018-February/msg00562.html</a><br>
> <br>
>  po/POTFILES.in              |   1 +<br>
>  src/libvirt_private.syms    |   7 +<br>
>  src/util/Makefile.inc.am    |   2 +<br>
>  src/util/virhostdev.c       |   2 +-<br>
>  src/util/virhostdev.h       |   8 +<br>
>  src/util/virnetdevhostdev.c | 374 ++++++++++++++++++++++++++++++++++++++++++++<br>
>  src/util/virnetdevhostdev.h |  35 +++++<br>
>  7 files changed, 428 insertions(+), 1 deletion(-)<br>
>  create mode 100644 src/util/virnetdevhostdev.c<br>
>  create mode 100644 src/util/virnetdevhostdev.h<br>
> <br>
<br>
You probably don't have cppi installed, but if you did it would have<br>
pointed out a few more syntax-check issues...<br>
<br>
> diff --git a/po/POTFILES.in b/po/POTFILES.in<br>
> index d84859a4e..8cd6b86e8 100644<br>
> --- a/po/POTFILES.in<br>
> +++ b/po/POTFILES.in<br>
> @@ -234,6 +234,7 @@ src/util/virmdev.c<br>
>  src/util/virnetdev.c<br>
>  src/util/virnetdevbandwidth.c<br>
>  src/util/virnetdevbridge.c<br>
> +src/util/virnetdevhostdev.c<br>
>  src/util/virnetdevip.c<br>
>  src/util/virnetdevmacvlan.c<br>
>  src/util/virnetdevmidonet.c<br>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms<br>
> index f6897915c..fad235206 100644<br>
> --- a/src/libvirt_private.syms<br>
> +++ b/src/libvirt_private.syms<br>
> @@ -1923,6 +1923,7 @@ virHostCPUStatsAssign;<br>
>  virHostdevFindUSBDevice;<br>
>  virHostdevIsSCSIDevice;<br>
>  virHostdevManagerGetDefault;<br>
> +virHostdevNetDevice;<br>
>  virHostdevPCINodeDeviceDetach;<br>
>  virHostdevPCINodeDeviceReAttach;<br>
>  virHostdevPCINodeDeviceReset;<br>
> @@ -2306,6 +2307,12 @@ virNetDevBridgeSetSTPDelay;<br>
>  virNetDevBridgeSetVlanFiltering;<br>
>  <br>
>  <br>
> +# util/virnetdevhostdev.h<br>
> +virNetdevHostdevCheckVFRIfName;<br>
> +virNetdevHostdevGetVFRIfName;<br>
> +virNetdevHostdevVFRIfStats;<br>
> +<br>
> +<br>
>  # util/virnetdevip.h<br>
>  virNetDevIPAddrAdd;<br>
>  virNetDevIPAddrDel;<br>
> diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am<br>
> index a3c3b711f..31fe11c68 100644<br>
> --- a/src/util/Makefile.inc.am<br>
> +++ b/src/util/Makefile.inc.am<br>
> @@ -104,6 +104,8 @@ UTIL_SOURCES = \<br>
>        util/virnetdevbandwidth.h \<br>
>        util/virnetdevbridge.c \<br>
>        util/virnetdevbridge.h \<br>
> +     util/virnetdevhostdev.c \<br>
> +     util/virnetdevhostdev.h \<br>
>        util/virnetdevip.c \<br>
>        util/virnetdevip.h \<br>
>        util/virnetdevmacvlan.c \<br>
> diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c<br>
> index a12224c58..4f7b46a04 100644<br>
> --- a/src/util/virhostdev.c<br>
> +++ b/src/util/virhostdev.c<br>
> @@ -306,7 +306,7 @@ virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)<br>
>  }<br>
>  <br>
>  <br>
> -static int<br>
> +int<br>
>  virHostdevNetDevice(virDomainHostdevDefPtr hostdev,<br>
>                      int pfNetDevIdx,<br>
>                      char **linkdev,<br>
> diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h<br>
> index 54e1c66be..735220add 100644<br>
> --- a/src/util/virhostdev.h<br>
> +++ b/src/util/virhostdev.h<br>
> @@ -60,6 +60,14 @@ struct _virHostdevManager {<br>
>  };<br>
>  <br>
>  virHostdevManagerPtr virHostdevManagerGetDefault(void);<br>
> +<br>
> +int<br>
> +virHostdevNetDevice(virDomainHostdevDefPtr hostdev,<br>
> +                    int pfNetDevIdx,<br>
> +                    char **linkdev,<br>
> +                    int *vf)<br>
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4);<br>
> +<br>
>  int<br>
>  virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,<br>
>                              const char *drv_name,<br>
> diff --git a/src/util/virnetdevhostdev.c b/src/util/virnetdevhostdev.c<br>
> new file mode 100644<br>
> index 000000000..19f95bfdd<br>
> --- /dev/null<br>
> +++ b/src/util/virnetdevhostdev.c<br>
> @@ -0,0 +1,374 @@<br>
> +/*<br>
> + * virnetdevhostdev.c: utilities to get/verify Switchdev VF Representor<br>
> + *<br>
> + * This library is free software; you can redistribute it and/or<br>
> + * modify it under the terms of the GNU Lesser General Public<br>
> + * License as published by the Free Software Foundation; either<br>
> + * version 2.1 of the License, or (at your option) any later version.<br>
> + *<br>
> + * This library is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
> + * Lesser General Public License for more details.<br>
> + *<br>
> + * You should have received a copy of the GNU Lesser General Public<br>
> + * License along with this library.  If not, see<br>
> + * <<a href="http://www.gnu.org/licenses/" id="LPlnk446840" class="OWAAutoLink" previewremoved="true">http://www.gnu.org/licenses/</a>>.<br>
> + */<br>
> +<br>
> +#include <config.h><br>
> +<br>
> +#include <unistd.h><br>
> +#include <stdlib.h><br>
> +#include <stdio.h><br>
> +#include <dirent.h><br>
> +<br>
> +#include "virhostdev.h"<br>
> +#include "virnetdev.h"<br>
> +#include "virnetdevhostdev.h"<br>
> +#include "viralloc.h"<br>
> +#include "virstring.h"<br>
> +#include "virfile.h"<br>
> +#include "virerror.h"<br>
> +#include "virlog.h"<br>
> +#include "c-ctype.h"<br>
> +<br>
> +#define VIR_FROM_THIS VIR_FROM_NONE<br>
> +<br>
> +VIR_LOG_INIT("util.netdevhostdev");<br>
> +<br>
> +#ifndef IFNAMSIZ<br>
> +#define IFNAMSIZ 16<br>
<br>
cppi: src/util/virnetdevhostdev.c: line 41: not properly indented<br>
<br>
IOW: "# define"<br>
<br>
> +#endif<br>
> +<br>
> +#define IFSWITCHIDSIZ 20<br>
> +<br>
> +#ifdef __linux__<br>
<br>
FWIW: Easiest way to test that your compilation works on "linux" and<br>
something else is to simply change this line to something else that<br>
wouldn't be defined and that would show if your #else logic works...<br>
<br>
> +/**<br>
> + * virNetdevHostdevNetSysfsPath<br>
> + *<br>
> + * @pf_name: netdev name of the physical function (PF)<br>
> + * @vf: virtual function (VF) number for the device of interest<br>
> + * @vf_ifname: name of the VF representor interface<br>
> + *<br>
> + * Finds the VF representor name of VF# @vf of SRIOV PF @pfname,<br>
> + * and puts it in @vf_ifname. The caller must free @vf_ifname<br>
> + * when it's finished with it<br>
> + *<br>
> + * Returns 0 on success, -1 on failure<br>
> + */<br>
> +static int<br>
> +virNetdevHostdevNetSysfsPath(char *pf_name,<br>
> +                             int vf,<br>
> +                             char **vf_ifname)<br>
> +{<br>
> +    size_t i;<br>
> +    char *pf_switch_id = NULL;<br>
> +    char *pf_switch_id_file = NULL;<br>
> +    char *pf_subsystem_device_file = NULL;<br>
> +    char *pf_subsystem_device_switch_id = NULL;<br>
> +    char *pf_subsystem_device_port_name_file = NULL;<br>
> +    char *pf_subsystem_dir = NULL;<br>
> +    char *vf_rep_ifname = NULL;<br>
> +    char *vf_num_str = NULL;<br>
> +    DIR *dirp = NULL;<br>
> +    struct dirent *dp;<br>
> +    int ret = -1;<br>
> +<br>
> +    if (virAsprintf(&pf_switch_id_file, SYSFS_NET_DIR "%s/phys_switch_id",<br>
> +                    pf_name) < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    if (virAsprintf(&pf_subsystem_dir, SYSFS_NET_DIR "%s/subsystem",<br>
> +                    pf_name) < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    /* a failure to read just means the driver doesn't support<br>
> +     * phys_switch_id, so ignoring the error from<br>
> +     * virFileReadAllQuiet().<br>
> +     */<br>
> +    if (virFileReadAllQuiet(pf_switch_id_file, IFSWITCHIDSIZ,<br>
> +                            &pf_switch_id) <= 0) {<br>
<br>
A < 0 is an error<br>
A == 0 is empty file<br>
<br>
so be careful in just cut-copy-paste as this will fail for some unknown<br>
reason if the length of what's read == 0.<br>
<br>
This should also go after the virAsprintf for pf_switch_id_file<br>
<br>
> +        goto cleanup;<br>
> +    }<br>
<br>
And you don't really the { } for a one line goto cleanup although it<br>
passed syntax-check because of the multi-line virFileReadAddQuiet<br>
<br>
Your comments though make it seem like you want to check if the file<br>
exists first before reading (e.g. if (!virFileExists())).  Then if it<br>
doesn't exist, return.  You may also want to alter your returns to be -1<br>
error, 0 nothing gathered, and 1 something gathered.  Don't forget to<br>
document that too.<br>
<br>
Looking at patch 2 which is where virNetdevHostdevGetVFRIfName (the<br>
caller to this method) is called - if the returned name is NULL, then<br>
the data would be ignored anyway. So the 0 and 1 return could be useful.<br>
<br>
> +<br>
> +    if (virDirOpen(&dirp, pf_subsystem_dir) < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    /* Iterate over the PFs subsystem devices to find entry with matching<br>
> +     * switch_id with that of PF.<br>
> +     */<br>
> +    while (virDirRead(dirp, &dp, pf_subsystem_dir) > 0) {<br>
> +        if (STREQ(dp->d_name, pf_name))<br>
> +            continue;<br>
> +<br>
> +        VIR_FREE(pf_subsystem_device_file);<br>
> +        if (virAsprintf(&pf_subsystem_device_file, "%s/%s/phys_switch_id",<br>
> +                        pf_subsystem_dir, dp->d_name) < 0)<br>
> +            goto cleanup;<br>
> +<br>
> +    /* a failure to read just means the driver doesn't support the entry<br>
> +     * being probed for current device in subsystem dir, so ignoring the<br>
> +     * error in the following calls to virFileReadAllQuiet() and continue<br>
> +     * the loop to find device which supports this and is a  match.<br>
<br>
s/a  match/a match/<br>
<br>
> +     */<br>
<br>
Also, entire comment is incorrectly indented.<br>
<br>
Again, should we first to a if (!virFileExists()) continue; type operation?<br>
<br>
> +        VIR_FREE(pf_subsystem_device_switch_id);<br>
> +        if (virFileReadAllQuiet(pf_subsystem_device_file, IFSWITCHIDSIZ,<br>
> +                                &pf_subsystem_device_switch_id) > 0) {<br>
> +            if (STRNEQ(pf_switch_id, pf_subsystem_device_switch_id))<br>
> +                continue;<br>
<br>
So if <= we're falling through to the next step, which I don't think you<br>
want.<br>
<br>
> +        }<br>
> +<br>
<br>
This one doesn't follow your pattern to add a<br>
VIR_FREE(pf_subsystem_device_port_name_file) beforehand within your<br>
while loop...<br>
<br>
> +        if (virAsprintf(&pf_subsystem_device_port_name_file,<br>
> +                        "%s/%s/phys_port_name", pf_subsystem_dir,<br>
> +                        dp->d_name) < 0)<br>
> +            goto cleanup;<br>
> +<br>
> +        VIR_FREE(vf_rep_ifname);<br>
> +        vf_rep_ifname = NULL;<br>
<br>
Should be unnecessary since virFree will do that for you<br>
<br>
Again more thought around !virFileExists()<br>
> +<br>
> +        if (virFileReadAllQuiet<br>
> +            (pf_subsystem_device_port_name_file, IFNAMSIZ,<br>
> +             &vf_rep_ifname) <= 0)<br>
> +            continue;<br>
> +<br>
<br>
Again the pattern of VIR_FREE(vf_num_str); beforehand<br>
<br>
> +        if (virAsprintf(&vf_num_str, "%d", vf) < 0)<br>
> +            goto cleanup;<br>
> +<br>
> +        /* phys_port_name may contain just VF number or string in format<br>
> +         * as pf'X'vf'Y' or vf'Y', where X and Y are PF and VF numbers.<br>
> +         * As at this point, we are already with correct PF, just need<br>
> +         * to verify VF number now.<br>
> +         */<br>
> +<br>
> +        /* vf_rep_ifname read from file may contain new line,replace with '\0'<br>
> +           for string comparison below */<br>
> +        i = strlen(vf_rep_ifname);<br>
> +        if (c_isspace(vf_rep_ifname[i-1])) {<br>
> +            vf_rep_ifname[i-1] = '\0';<br>
> +            i -= 1;<br>
> +        }<br>
> +<br>
> +        while (c_isdigit(vf_rep_ifname[i-1]))<br>
> +              i -= 1;<br>
> +<br>
> +        if ((ret = STREQ((vf_rep_ifname + i), vf_num_str))) {<br>
<br>
This changes ret < == > 0... don't believe that's what you really want.<br>
<br>
> +            if (VIR_STRDUP(*vf_ifname, dp->d_name) < 0)<br>
> +                goto cleanup;<br>
> +            ret = 0;<br>
> +            break;<br>
> +        }<br>
<br>
For the above last hunk... All if this because you're trying to<br>
determine if the passed "vf" number is equal to the number portion of<br>
the vf_rep_ifname?<br>
<br>
I believe virSkipSpaces and virParseNumber will help you be a whole lot<br>
cleaner!<br>
<br>
> +    }<br>
> +<br>
> + cleanup:<br>
> +    VIR_DIR_CLOSE(dirp);<br>
> +    VIR_FREE(pf_switch_id);<br>
> +    VIR_FREE(pf_switch_id_file);<br>
> +    VIR_FREE(pf_subsystem_dir);<br>
> +    VIR_FREE(pf_subsystem_device_file);<br>
> +    VIR_FREE(pf_subsystem_device_switch_id);<br>
> +    VIR_FREE(pf_subsystem_device_port_name_file);<br>
> +    VIR_FREE(vf_num_str);<br>
> +    VIR_FREE(vf_rep_ifname);<br>
> +    return ret;<br>
> +}<br>
> +<br>
> +<br>
> +/**<br>
> + * virNetdevHostdevGetVFRepIFName<br>
> + *<br>
> + * @hostdev: host device to check<br>
> + *<br>
> + * Returns VF string with VF representor name upon success else NULL<br>
> + */<br>
> +char *<br>
> +virNetdevHostdevGetVFRIfName(virDomainHostdevDefPtr hostdev)<br>
> +{<br>
> +    char *linkdev = NULL;<br>
> +    char *ifname = NULL;<br>
> +    char *vf_ifname = NULL;<br>
> +    int vf = -1;<br>
> +<br>
> +    if (virHostdevNetDevice(hostdev, -1, &linkdev, &vf) < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    if (virNetdevHostdevNetSysfsPath(linkdev, vf, &vf_ifname))> +        goto cleanup;<br>
<br>
Considering my comment above and changing the return values means this<br>
could change as well. At the very least actually checking < 0 for failure...<br>
<br>
To some degree since the caller only cares if the return is NULL or not<br>
and doesn't error when it's not, then all/any error generated will be<br>
lost.  So that means would could be a valid reason to cause a failure<br>
would be lost and the data just ignored.<br>
<br>
At the very least a virResetLastError would clear away the error<br>
<br>
> +<br>
> +    ignore_value(VIR_STRDUP(ifname, vf_ifname));<br>
> +<br>
> + cleanup:<br>
> +    VIR_FREE(linkdev);<br>
> +    VIR_FREE(vf_ifname);<br>
> +    return ifname;<br>
> +}<br>
> +<br>
> +<br>
> +/**<br>
> + * virNetdevHostdevCheckVFRepIFName<br>
> + *<br>
> + * @hostdev: host device to check<br>
> + * @ifname : VF representor name to verify<br>
> + *<br>
> + * Returns true on success, false on failure<br>
> + */<br>
> +bool<br>
> +virNetdevHostdevCheckVFRIfName(virDomainHostdevDefPtr hostdev,<br>
> +                               const char *ifname)<br>
> +{<br>
> +    char *linkdev = NULL;<br>
> +    char *vf_ifname = NULL;<br>
> +    int vf = -1;<br>
> +    bool ret = false;<br>
> +<br>
> +    if (virHostdevNetDevice(hostdev, -1, &linkdev, &vf) < 0)<br>
> +        goto cleanup;<br>
> +<br>
> +    if (virNetdevHostdevNetSysfsPath(linkdev, vf, &vf_ifname))<br>
> +        goto cleanup;<br>
> +<br>
> +    if (STREQ(ifname, vf_ifname))<br>
> +        ret = true;<br>
> +<br>
> + cleanup:<br>
> +    VIR_FREE(linkdev);<br>
> +    VIR_FREE(vf_ifname);<br>
> +    return ret;<br>
> +}<br>
> +<br>
> +<br>
> +/*-------------------- interface stats --------------------*/<br>
> +/* Copy of virNetDevTapInterfaceStats for linux */<br>
<br>
<br>
Before I read this comment after looking at the next patch and wondering<br>
what was different to virNetDevTapInterfaceStats, my first gut response<br>
follows.<br>
<br>
Now that I've dealt with that - rather than cut-n-paste-n-copy - you<br>
need to figure out a way to make use of the existing code. That means<br>
introducing an API that the __linux___ version of<br>
virNetDevTapInterfaceStats would call and this function would also call.<br>
Perhaps something along the lines of virNetDevGetProcNetDev that lives<br>
in src/util/virnetdev.c... One patch would extract it out and the next<br>
one would also use it for your hostdev path.<br>
<br>
FWIW: Still some of my feeings below could still apply to/for an<br>
improved processing of the file/data - especially w/r/t format of the<br>
file, headings, etc.  Since "something" already exists though, we can<br>
live with it I suppose, even though it's perhaps not optimal<br>
<br>
> +/**<br>
> + * virNetdevHostdevVFRepInterfaceStats:<br>
> + * @ifname: interface<br>
> + * @stats: where to store statistics<br>
> + * @swapped: whether to swap RX/TX fields<br>
> + *<br>
> + * Fetch RX/TX statistics for given named interface (@ifname) and<br>
> + * store them at @stats. The returned statistics are always from<br>
> + * domain POV. Because in some cases this means swapping RX/TX in<br>
> + * the stats and in others this means no swapping (consider TAP<br>
> + * vs macvtap) caller might choose if the returned stats should<br>
> + * be @swapped or not.<br>
> + *<br>
> + * Returns 0 on success, -1 otherwise (with error reported).<br>
> + */> +int<br>
> +virNetdevHostdevVFRIfStats(const char *ifname,<br>
> +                           virDomainInterfaceStatsPtr stats,<br>
> +                           bool swapped)<br>
> +{<br>
> +    int ifname_len;<br>
> +    FILE *fp;<br>
> +    char line[256], *colon;<br>
> +<br>
> +    fp = fopen("/proc/net/dev", "r");<br>
> +    if (!fp) {<br>
> +        virReportSystemError(errno, "%s",<br>
> +                             _("Could not open /proc/net/dev"));<br>
> +        return -1;<br>
> +    }<br>
> +<br>
> +    ifname_len = strlen(ifname);<br>
> +<br>
> +    while (fgets(line, sizeof(line), fp)) {<br>
> +        long long dummy;<br>
> +        long long rx_bytes;<br>
> +        long long rx_packets;<br>
> +        long long rx_errs;<br>
> +        long long rx_drop;<br>
> +        long long tx_bytes;<br>
> +        long long tx_packets;<br>
> +        long long tx_errs;<br>
> +        long long tx_drop;<br>
> +<br>
> +        /* The line looks like:<br>
> +         *   "   eth0:..."<br>
> +         * Split it at the colon.<br>
> +         */<br>
<br>
Tehnically there's a header row or two that you're missing from what I<br>
see...<br>
<br>
> +        colon = strchr(line, ':');<br>
<br>
Once you get beyond and verify the header, you may want to look into<br>
virStringSplit - it's pretty powerful and this is just ripe for all<br>
sorts of issues especially if the format of the output *ever* changes....<br>
<br>
In fact I'd go as far to say that checking/learning which column heading<br>
goes with which data element might be very useful thing to add here<br>
especially if it ever differs between distros or ever has changed or<br>
could change.<br>
<br>
Check out using virFileReadAll and other API's that read /proc files. If<br>
you can "map" your expected headers into the format you're reading and<br>
ensure that no future change would alter what you've magically sscanf'd<br>
below, then that future proofs yourself a bit. You could possibly also<br>
create some magic that would pull only the ones you care about based on<br>
the headers provided.<br>
<br>
There's "inventive ways" to use ARRAY_CARDINALITY (see<br>
virNetClientFindDefaultSshKey) that will help you make sure that the<br>
header doesn't change which skews your results.<br>
<br>
In any case, the folowing at the very least should follow<br>
virHostCPUGetStatsLinux or virHostMemGetStatsLinux in order to make sure<br>
headers match sscanf'd columns.<br>
<br>
<br>
> +        if (!colon) continue;<br>
> +        *colon = '\0';<br>
> +        if (colon-ifname_len >= line &&<br>
> +            STREQ(colon-ifname_len, ifname)) {<br>
> +            if (sscanf(colon+1,<br>
> +                       "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",<br>
> +                       &rx_bytes, &rx_packets, &rx_errs, &rx_drop,<br>
> +                       &dummy, &dummy, &dummy, &dummy,<br>
> +                       &tx_bytes, &tx_packets, &tx_errs, &tx_drop,<br>
> +                       &dummy, &dummy, &dummy, &dummy) != 16)<br>
> +                continue;<br>
> +<br>
> +            if (swapped) {<br>
> +                stats->rx_bytes = tx_bytes;<br>
> +                stats->rx_packets = tx_packets;<br>
> +                stats->rx_errs = tx_errs;<br>
> +                stats->rx_drop = tx_drop;<br>
> +                stats->tx_bytes = rx_bytes;<br>
> +                stats->tx_packets = rx_packets;<br>
> +                stats->tx_errs = rx_errs;<br>
> +                stats->tx_drop = rx_drop;<br>
> +            } else {<br>
> +                stats->rx_bytes = rx_bytes;<br>
> +                stats->rx_packets = rx_packets;<br>
> +                stats->rx_errs = rx_errs;<br>
> +                stats->rx_drop = rx_drop;<br>
> +                stats->tx_bytes = tx_bytes;<br>
> +                stats->tx_packets = tx_packets;<br>
> +                stats->tx_errs = tx_errs;<br>
> +                stats->tx_drop = tx_drop;<br>
> +            }<br>
> +<br>
> +            VIR_FORCE_FCLOSE(fp);<br>
> +            return 0;<br>
> +        }<br>
> +    }<br>
> +    VIR_FORCE_FCLOSE(fp);<br>
> +<br>
> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",<br>
> +                   _("/proc/net/dev: Interface not found"));<br>
<br>
Wouldn't this be more an empty /proc/net/dev file?  Is that a sign of a<br>
different problem?  We've already covered the missing file above.<br>
<br>
> +    return -1;<br>
> +}<br>
> +#else<br>
> +int<br>
> +virNetdevHostdevVFRIfStats(const char *ifname ATTRIBUTE_UNUSED,<br>
> +                           virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED,<br>
> +                           bool swapped ATTRIBUTE_UNUSED)<br>
> +{<br>
> +    virReportError(VIR_ERR_OPERATION_INVALID, "%s",<br>
> +                   _("interface stats not implemented on this platform"));<br>
> +    return -1;<br>
> +}<br>
> +<br>
> +<br>
> +static const char *unsupported = N_("not supported on non-linux platforms");<br>
> +<br>
> +<br>
> +static int<br>
<br>
static functions don't need to be in the #else<br>
<br>
> +virNetdevHostdevNetSysfsPath(char *pf_name ATTRIBUTE_UNUSED,<br>
> +                             int vf ATTRIBUTE_UNUSED,<br>
> +                             char **vf_ifname ATTRIBUTE_UNUSED)<br>
> +{<br>
> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));<br>
> +    return -1;<br>
> +}<br>
> +<br>
> +<br>
> +char *<br>
> +virNetdevHostdevGetVFRIfName(virDomainHostdevDefPtr hostdev ATTRIBUTE_UNUSED,<br>
> +                             char **ifname ATTRIBUTE_UNUSED)<br>
<br>
Parameters here are different than .h file.<br>
<br>
> +{<br>
> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));<br>
> +    return NULL;<br>
> +}<br>
> +<br>
> +<br>
> +static bool<br>
<br>
This one's not static...<br>
<br>
> +virNetdevHostdevCheckVFRIfName(virDomainHostdevDefPtr hostdev ATTRIBUTE_UNUSED,<br>
> +                               const char *ifname ATTRIBUTE_UNUSED)<br>
> +{<br>
> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));<br>
> +    return false;<br>
> +}<br>
<br>
Please place the order of functions in the #else section the same as in<br>
the #if section<br>
<br>
> +#endif<br>
> diff --git a/src/util/virnetdevhostdev.h b/src/util/virnetdevhostdev.h<br>
> new file mode 100644<br>
> index 000000000..3ea1804ff<br>
> --- /dev/null<br>
> +++ b/src/util/virnetdevhostdev.h<br>
> @@ -0,0 +1,35 @@<br>
> +/*<br>
> + * virnetdevhostdev.h: utilities to get/verify Switchdev VF Representor<br>
> + *<br>
> + *<br>
> + * This library is free software; you can redistribute it and/or<br>
> + * modify it under the terms of the GNU Lesser General Public<br>
> + * License as published by the Free Software Foundation; either<br>
> + * version 2.1 of the License, or (at your option) any later version.<br>
> + *<br>
> + * This library is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
> + * Lesser General Public License for more details.<br>
> + *<br>
> + * You should have received a copy of the GNU Lesser General Public<br>
> + * License along with this library.  If not, see<br>
> + * <<a href="http://www.gnu.org/licenses/" id="LPlnk989670" class="OWAAutoLink" previewremoved="true">http://www.gnu.org/licenses/</a>>.<br>
> + */<br>
> +<br>
> +#ifndef __VIR_NETDEV_HOSTDEV_H__<br>
> +#define __VIR_NETDEV_HOSTDEV_H__<br>
> +#include "virnetdevtap.h"<br>
<br>
cppi: src/util/virnetdevhostdev.h: line 21: not properly indented<br>
cppi: src/util/virnetdevhostdev.h: line 22: not properly indented<br>
<br>
IOW: "# define" and "# include"<br>
<br>
> +<br>
> +char *<br>
> +virNetdevHostdevGetVFRIfName(virDomainHostdevDefPtr hostdev)<br>
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;<br>
<br>
Add a blank like for readability<br>
<br>
> +bool<br>
> +virNetdevHostdevCheckVFRIfName(virDomainHostdevDefPtr hostdev,<br>
> +                              const char *ifname)<br>
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;<br>
<br>
Same here... Also keep the same function order as the .c file - it's<br>
just easier that way to compare .h and .c...<br>
<br>
> +int virNetdevHostdevVFRIfStats(const char *ifname,<br>
> +                               virDomainInterfaceStatsPtr stats,<br>
> +                               bool swapped)<br>
<br>
Why change format?<br>
<br>
s/b<br>
int<br>
virNetdevHostdev...<br>
<br>
<br>
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;<br>
> +#endif /* __VIR_NETDEV_HOSTDEV_H__ */<br>
> <br>
<br>
John<br>
</div>
</span></font></div>
</div>
</div>
</body>
</html>