Re: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering support for passthru mode

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

 





On 10/31/11 10:39 AM, "Rose, Gregory V" <gregory.v.rose@xxxxxxxxx> wrote:

>> -----Original Message-----
>> From: Roopa Prabhu [mailto:roprabhu@xxxxxxxxx]
>> Sent: Monday, October 31, 2011 10:09 AM
>> To: Rose, Gregory V; netdev@xxxxxxxxxxxxxxx
>> Cc: sri@xxxxxxxxxx; dragos.tatulea@xxxxxxxxx; kvm@xxxxxxxxxxxxxxx;
>> arnd@xxxxxxxx; mst@xxxxxxxxxx; davem@xxxxxxxxxxxxx; mchan@xxxxxxxxxxxx;
>> dwang2@xxxxxxxxx; shemminger@xxxxxxxxxx; eric.dumazet@xxxxxxxxx;
>> kaber@xxxxxxxxx; benve@xxxxxxxxx
>> Subject: Re: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address
>> filtering support for passthru mode
>> 
>> 
>> 
>> 
>> On 10/31/11 9:38 AM, "Rose, Gregory V" <gregory.v.rose@xxxxxxxxx> wrote:
>> 
>>>> -----Original Message-----
>>>> From: netdev-owner@xxxxxxxxxxxxxxx [mailto:netdev-
>> owner@xxxxxxxxxxxxxxx]
>>>> On Behalf Of Roopa Prabhu
>>>> Sent: Friday, October 28, 2011 7:34 PM
>>>> To: netdev@xxxxxxxxxxxxxxx
>>>> Cc: sri@xxxxxxxxxx; dragos.tatulea@xxxxxxxxx; kvm@xxxxxxxxxxxxxxx;
>>>> arnd@xxxxxxxx; mst@xxxxxxxxxx; davem@xxxxxxxxxxxxx; Rose, Gregory V;
>>>> mchan@xxxxxxxxxxxx; dwang2@xxxxxxxxx; shemminger@xxxxxxxxxx;
>>>> eric.dumazet@xxxxxxxxx; kaber@xxxxxxxxx; benve@xxxxxxxxx
>>>> Subject: [net-next-2.6 PATCH 0/6 RFC v3] macvlan: MAC Address filtering
>>>> support for passthru mode
>>>> 
>>>> v2 -> v3
>>>> - Moved set and get filter ops from rtnl_link_ops to netdev_ops
>>>> - Support for SRIOV VFs.
>>>> [Note: The get filters msg might get too big for SRIOV vfs.
>>>>         But this patch follows existing sriov vf get code and
>>>> accomodate filters for all VF's in a PF.
>>>>         And for the SRIOV case I have only tested the fact that the VF
>>>> arguments are getting delivered to rtnetlink correctly. The rest of
>>>> the code follows existing sriov vf handling code so it should work
>>>> just fine]
>>>> - Fixed all op and netlink attribute names to start with IFLA_RX_FILTER
>>>> - Changed macvlan filter ops to call corresponding lowerdev op if
>> lowerdev
>>>>   supports it for passthru mode. Else it falls back on macvlan handling
>>>> the
>>>>   filters locally as in v1 and v2
>>>> 
>>>> v1 -> v2
>>>> - Instead of TUNSETTXFILTER introduced rtnetlink interface for the same
>>>> 
>>> 
>>> [snip...]
>>> 
>>>> 
>>>> This patch series implements the following
>>>> 01/6 rtnetlink: Netlink interface for setting MAC and VLAN filters
>>>> 02/6 netdev: Add netdev_ops to set and get MAC/VLAN rx filters
>>>> 03/6 rtnetlink: Add support to set MAC/VLAN filters
>>>> 04/6 rtnetlink: Add support to get MAC/VLAN filters
>>>> 05/6 macvlan: Add support to set MAC/VLAN filter netdev ops
>>>> 06/6 macvlan: Add support to get MAC/VLAN filter netdev ops
>>>> 
>>>> Please comment. Thanks.
>>> 
>>> After some preliminary review this looks pretty good to me in so far as
>> adding
>>> the necessary hooks to do what I need to do.  I appreciate your effort
>> on
>>> this.
>>> 
>>> I'm sort of a hands-on type of person so I need to apply this patch to a
>>> private git tree and then take it for a test drive (so to speak).  If I have
>>> further comments I'll get back to you.
>>> 
>> Sounds good.
>> 
>>> Did you have any plans for modifying any user space tools such as 'ip' to
>>> use
>>> this interface?
>>> 
>> 
>> Yes, I have an iproute2 sample patch for setting and displaying the filters
>> which I have been using to test this interface. I can send the patch to you
>> after some cleanup if you think it will be useful for you to try out this
>> interface.
>> 
>> Thanks Greg.
> 
> Yes, please do.
> 
> Thanks,
> 
> - Greg
> 
Greg, here is the patch. I rebased it with tip-of-tree iproute2 git. Thanks.

    iproute2: support for MAC/VLAN filter
    
    This patch is not complete. Its a bit hackish right now.
    I implemented this patch to only test the kernel interface
    without usability in mind.
    
    Limitations:
    - Havent checked corner cases for sriov vfs
    - usage msg needs to be fixed. Its ugly right now
    - vf = -1 for direct assignment of filters on a vf or any network
interface
    - functions could be broken down, var names changed etc
    - show part definately needs to change. It does not
    follow the convention right now
    - it has some redundant code which can be removed and simplified
    
    I will work on this patch some more and resubmit this patch
    after the kernel patch gets accepted.

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 304c44f..ffd03e1 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -137,6 +137,8 @@ enum {
     IFLA_AF_SPEC,
     IFLA_GROUP,        /* Group the device belongs to */
     IFLA_NET_NS_FD,
+    IFLA_VF_RX_FILTERS,
+    IFLA_RX_FILTER,
     __IFLA_MAX
 };
 
@@ -264,6 +266,8 @@ enum macvlan_mode {
 
 /* SR-IOV virtual function management section */
 
+#define SELF_VF        -1
+
 enum {
     IFLA_VF_INFO_UNSPEC,
     IFLA_VF_INFO,
@@ -378,4 +382,63 @@ struct ifla_port_vsi {
     __u8 pad[3];
 };
 
+/* VF rx filters management section
+ *
+ *    Nested layout of set/get msg is:
+ *
+ *    [IFLA_VF_RX_FILTERS]
+ *        [IFLA_VF_RX_FILTER]
+ *            [IFLA_RX_FILTER_*], ...
+ *        [IFLA_VF_RX_FILTER]
+ *            [IFLA_RX_FILTER_*], ...
+ *        ...
+ *    [IFLA_RX_FILTER]
+ *        [IFLA_RX_FILTER_*], ...
+ */
+enum {
+    IFLA_VF_RX_FILTER_UNSPEC,
+    IFLA_VF_RX_FILTER,            /* nest */
+    __IFLA_VF_RX_FILTER_MAX,
+};
+
+#define IFLA_VF_RX_FILTER_MAX (__IFLA_VF_RX_FILTER_MAX - 1)
+
+enum {
+    IFLA_RX_FILTER_UNSPEC,
+    IFLA_RX_FILTER_VF,        /* __u32 */
+    IFLA_RX_FILTER_ADDR,
+    IFLA_RX_FILTER_VLAN,
+    __IFLA_RX_FILTER_MAX,
+};
+#define IFLA_RX_FILTER_MAX (__IFLA_RX_FILTER_MAX - 1)
+
+enum {
+    IFLA_RX_FILTER_ADDR_UNSPEC,
+    IFLA_RX_FILTER_ADDR_FLAGS,
+    IFLA_RX_FILTER_ADDR_UC_LIST,
+    IFLA_RX_FILTER_ADDR_MC_LIST,
+    __IFLA_RX_FILTER_ADDR_MAX,
+};
+#define IFLA_RX_FILTER_ADDR_MAX (__IFLA_RX_FILTER_ADDR_MAX - 1)
+
+#define RX_FILTER_FLAGS (IFF_UP | IFF_BROADCAST | IFF_MULTICAST | \
+                IFF_PROMISC | IFF_ALLMULTI)
+
+enum {
+    IFLA_ADDR_LIST_UNSPEC,
+    IFLA_ADDR_LIST_ENTRY,
+    __IFLA_ADDR_LIST_MAX,
+};
+#define IFLA_ADDR_LIST_MAX (__IFLA_ADDR_LIST_MAX - 1)
+
+enum {
+    IFLA_RX_FILTER_VLAN_UNSPEC,
+    IFLA_RX_FILTER_VLAN_BITMAP,
+    __IFLA_RX_FILTER_VLAN_MAX,
+};
+#define IFLA_RX_FILTER_VLAN_MAX (__IFLA_RX_FILTER_VLAN_MAX - 1)
+
+#define VLAN_BITMAP_SPLIT_MAX 8
+#define VLAN_BITMAP_SIZE    (VLAN_N_VID/VLAN_BITMAP_SPLIT_MAX)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 85f05a2..4154b07 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -192,6 +192,120 @@ static void print_linktype(FILE *fp, struct rtattr
*tb)
     }
 }
 
+static void print_vlan_bitmap(FILE *fp, struct rtattr *vlan_bitmap)
+{
+    unsigned long active_vlans[4096/64];
+    int i = 0, j = 0;
+    int first = 1;
+
+    memcpy(active_vlans, RTA_DATA(vlan_bitmap), sizeof(active_vlans));
+
+    for (i = 0 ; i < 64; i++) {
+        for (j = 0; j  < 64; j++) {
+            if (((active_vlans[i] >> j) & 1UL) == 1 ) {
+                if (!first)
+                    fprintf(fp, ",");
+                else
+                    first = 0;
+                  
+                fprintf(fp, "%d", j + 64 * i);
+            }
+        }
+    }
+}
+
+static void print_rx_filter(FILE *fp, struct rtattr *tb)
+{
+    struct rtattr *rx_filter[IFLA_RX_FILTER_MAX+1];
+    int first;
+
+    parse_rtattr_nested(rx_filter, IFLA_RX_FILTER_MAX, tb);
+
+    fprintf(fp, "rx_filter ");
+    if (rx_filter[IFLA_RX_FILTER_VF])
+        fprintf(fp, "vf:%d ",
+        *(unsigned int *)RTA_DATA(rx_filter[IFLA_RX_FILTER_VF]));
+
+    if (rx_filter[IFLA_RX_FILTER_ADDR]) {
+        struct rtattr *rx_addr_filter[IFLA_RX_FILTER_ADDR_MAX+1];
+        unsigned int flags;
+
+        parse_rtattr_nested(rx_addr_filter, IFLA_RX_FILTER_ADDR_MAX,
+                rx_filter[IFLA_RX_FILTER_ADDR]);
+
+        if (rx_addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]) {
+            flags = *(unsigned int *)RTA_DATA(
+                rx_addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]);
+            fprintf(fp, "flags IFF_UP=%s, "
+                "IFF_BROADCAST=%s, "
+                "IFF_MULTICAST=%s, IFF_PROMISC=%s, "
+                "IFF_ALLMULTI=%s ",
+                ((flags & IFF_UP) ? "on" : "off"),
+                ((flags & IFF_BROADCAST) ? "on" : "off"),
+                ((flags & IFF_MULTICAST) ? "on" : "off"),
+                ((flags & IFF_PROMISC) ? "on" : "off"),
+                ((flags & IFF_ALLMULTI) ? "on" : "off"));
+        }
+
+        if (rx_addr_filter[IFLA_RX_FILTER_ADDR_UC_LIST]) {
+            struct rtattr *i;
+            struct rtattr *uclist =
rx_addr_filter[IFLA_RX_FILTER_ADDR_UC_LIST];
+            int rem = RTA_PAYLOAD(uclist);
+            SPRINT_BUF(b1);
+            first = 1;
+            fprintf(fp, " uc ");
+            for (i = RTA_DATA(uclist); RTA_OK(i, rem);
+                i = RTA_NEXT(i, rem)) {
+                if (!first)
+                    fprintf(fp, ",");
+                else
+                    first = 0;
+                fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(i),
+                    RTA_PAYLOAD(i), 0, b1, sizeof(b1)));
+            }
+        }
+
+        if (rx_addr_filter[IFLA_RX_FILTER_ADDR_MC_LIST]) {
+            struct rtattr *i;
+            struct rtattr *mclist =
rx_addr_filter[IFLA_RX_FILTER_ADDR_MC_LIST];
+            SPRINT_BUF(b1);
+            int rem = RTA_PAYLOAD(mclist);
+
+            first = 1;
+            fprintf(fp, " mc ");
+            for (i = RTA_DATA(mclist); RTA_OK(i, rem);
+                i = RTA_NEXT(i, rem)) {
+                if (!first)
+                    fprintf(fp, ",");
+                else
+                    first = 0;
+                fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(i),
+                    RTA_PAYLOAD(i), 0, b1, sizeof(b1)));
+            }
+        }
+    }    
+
+    if (rx_filter[IFLA_RX_FILTER_VLAN]) {
+        struct rtattr *rx_vlan_filter[IFLA_RX_FILTER_VLAN_MAX+1];
+
+        fprintf(fp, " vlans ");
+        parse_rtattr_nested(rx_vlan_filter, IFLA_RX_FILTER_VLAN_MAX,
+                rx_filter[IFLA_RX_FILTER_VLAN]);
+        print_vlan_bitmap(fp,
+                rx_vlan_filter[IFLA_RX_FILTER_VLAN_BITMAP]);
+    }
+    fprintf(fp, "\n");
+}
+
+static void print_vf_rx_filters(FILE *fp, struct rtattr *tb)
+{
+    struct rtattr *i, *vf_filters = tb;
+    int rem = RTA_PAYLOAD(vf_filters);
+
+    for (i = RTA_DATA(vf_filters); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+        print_rx_filter(fp, i);
+}
+
 static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
 {
     struct ifla_vf_mac *vf_mac;
@@ -319,6 +433,16 @@ int print_linkinfo(const struct sockaddr_nl *who,
     if (do_link && tb[IFLA_LINKINFO] && show_details)
         print_linktype(fp, tb[IFLA_LINKINFO]);
 
+    if (do_link && tb[IFLA_RX_FILTER] ) {
+        fprintf(fp, "\n\t");
+        print_rx_filter(fp, tb[IFLA_RX_FILTER]);
+    }
+
+    if (do_link && tb[IFLA_VF_RX_FILTERS] ) {
+        fprintf(fp, "\n\t");
+        print_vf_rx_filters(fp, tb[IFLA_VF_RX_FILTERS]);
+    }
+
     if (do_link && tb[IFLA_IFALIAS])
         fprintf(fp,"\n    alias %s",
             (const char *) RTA_DATA(tb[IFLA_IFALIAS]));
diff --git a/ip/iplink.c b/ip/iplink.c
index 35e6dc6..42897fb 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -71,7 +71,8 @@ void iplink_usage(void)
     fprintf(stderr, "              [ alias NAME ]\n");
     fprintf(stderr, "                      [ vf NUM [ mac LLADDR ]\n");
     fprintf(stderr, "                   [ vlan VLANID [ qos VLAN-QOS ]
]\n");
-    fprintf(stderr, "                   [ rate TXRATE ] ] \n");
+    fprintf(stderr, "                   [ rate TXRATE ] \n");
+    fprintf(stderr, "                                [ rx_filter [flags
FILTER_FLAGS uc UC_LIST mc MC_LIST] [vlan VLANID_LIST]]\n");
     fprintf(stderr, "              [ master DEVICE ]\n");
     fprintf(stderr, "              [ nomaster ]\n");
     fprintf(stderr, "       ip link show [ DEVICE | group GROUP ]\n");
@@ -79,6 +80,10 @@ void iplink_usage(void)
     if (iplink_have_newlink()) {
         fprintf(stderr, "\n");
         fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb |
macvlan | can | bridge }\n");
+        fprintf(stderr, "FILTER_FLAGS := ifup,\n");
+        fprintf(stderr, "UC_LIST := <coma_separated_list_of_unicast
addrs>\n");
+        fprintf(stderr, "MC_LIST := <coma_separated_list_of_multicast
addrs>\n");
+        fprintf(stderr, "VLANID_LIST :=
<coma_separated_list_of_vlanids>\n");
     }
     exit(-1);
 }
@@ -179,55 +184,259 @@ struct iplink_req {
     char            buf[1024];
 };
 
-int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+int
+parse_comma_separated_list(char *argv, int *num_entries, char ***array)
+{
+    char *str = strdup(argv), *tok = NULL;
+    int n = 0;
+    
+    if (!str)
+        return -1;
+
+    for (tok = strtok(str, ","); tok;
+        tok = strtok(NULL, ","), ++n);
+    free(str);
+
+    *array = (char **)malloc(n * sizeof(char *));
+    
+    str = strdup(argv);
+    n = 0;
+    for (tok = strtok(str, ","); tok; tok = strtok(NULL, ","), ++n)
+        (*array)[n] = strdup(tok);
+
+    *num_entries = n;
+
+    return 0;
+}
+
+int iplink_parse_rx_filter(int vf, int *argcp, char ***argvp,
                struct iplink_req *req)
 {
+    int argc = *argcp;
+    char **argv = *argvp;
+    char **mc_list = NULL, **uc_list = NULL, **flags_list = NULL;
+    char **vlan_list = NULL;
+    int i, len;
+    int mc_list_count = 0, uc_list_count = 0, flags_list_count = 0;
+    int vlan_list_count = 0;
+    __u8 mac[32];
+
+    while (NEXT_ARG_OK()) {
+        NEXT_ARG();
+        if (matches(*argv, "rx_filter") == 0) {
+            /* Skip: Hack */
+        }
+        else if (matches(*argv, "flags") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &flags_list_count, &flags_list);
+            }
+        }
+        else if (matches(*argv, "uc") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &uc_list_count, &uc_list);
+            }
+        } else if (matches(*argv, "mc") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &mc_list_count, &mc_list);
+            }
+        } else if (matches(*argv, "vlan") == 0) {
+            if (NEXT_ARG_OK()) {
+                NEXT_ARG();
+                parse_comma_separated_list(*argv,
+                    &vlan_list_count, &vlan_list);
+            }
+        } else {
+            /* rewind arg */
+            PREV_ARG();
+            break;
+        }
+    }
+
+    if (argc == *argcp)
+        incomplete_command();
+
+    if (flags_list || uc_list || mc_list || vlan_list) {
+        struct rtattr *nest_rx_filter = NULL;
+        struct rtattr *nest_vf_filters = NULL;
+
+        if (vf != SELF_VF)
+            nest_vf_filters = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_VF_RX_FILTERS);
+
+
+        if (vf != SELF_VF) {
+            nest_rx_filter = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_VF_RX_FILTER);
+            addattr_l(&req->n, sizeof(*req), IFLA_RX_FILTER_VF,
+                (uint32_t *)&vf, sizeof(uint32_t));
+        }
+        else {
+            nest_rx_filter = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_RX_FILTER);
+        }
+
+        if (flags_list || uc_list || mc_list) {
+            struct rtattr *nest_addr_filter = NULL;
+
+            nest_addr_filter = addattr_nest(&req->n, sizeof(*req),
+                        IFLA_RX_FILTER_ADDR);
+
+            if (flags_list) {
+                unsigned int flags = 0;
+
+                for (i = 0; i < flags_list_count; i++) {
+                    if (!strcmp(flags_list[i], "promisc"))
+                        flags |= IFF_PROMISC;
+                    else if (!strcmp(flags_list[i],
+                        "allmulti"))
+                        flags |= IFF_ALLMULTI;
+                    else if (!strcmp(flags_list[i],
+                        "multicast"))
+                        flags |= IFF_MULTICAST;
+                    else if (!strcmp(flags_list[i],
+                        "broadcast"))
+                        flags |= IFF_BROADCAST;
+                    else if (!strcmp(flags_list[i], "ifup"))
+                        flags |= IFF_UP;
+                }
+        
+                //printf("DEBUG: %s: flags = %x\n",
+                //    __FUNCTION__, flags);
+
+                addattr32(&req->n, sizeof(*req),
+                    IFLA_RX_FILTER_ADDR_FLAGS, flags);
+            }
+    
+            if (uc_list) {
+                struct rtattr *nest_uc_list = NULL;
+
+                nest_uc_list = addattr_nest(&req->n,
+                        sizeof(*req),
+                        IFLA_RX_FILTER_ADDR_UC_LIST);
+                for (i = 0; i < uc_list_count; i++) {
+                    if (!strcmp(uc_list[i], "null"))
+                        continue;
+                    //printf("DEBUG: uc[%d] = %s\n", i, uc_list[i]);
+                    len = ll_addr_a2n((char *)mac, 32,
+                            uc_list[i]);
+                    if (len < 0)
+                         invarg("Invalid \"mac\" value\n", mac);
+                    addattr_l(&req->n, sizeof(*req),
+                        IFLA_ADDR_LIST_ENTRY, mac, 32);
+                }
+                addattr_nest_end(&req->n, nest_uc_list);
+            }
+
+            if (mc_list) {
+                struct rtattr *nest_mc_list = NULL;
+
+                nest_mc_list = addattr_nest(&req->n,
+                        sizeof(*req),
+                        IFLA_RX_FILTER_ADDR_MC_LIST);
+                for (i = 0; i < mc_list_count; i++) {
+                    if (!strcmp(mc_list[i], "null"))
+                        continue;
+                    //printf("DEBUG: mc[%d] = %s\n", i, mc_list[i]);
+                    len = ll_addr_a2n((char *)mac, 32,
+                            mc_list[i]);
+                    if (len < 0)
+                         invarg("Invalid \"mac\" value\n", mac);
+                    addattr_l(&req->n, sizeof(*req),
+                        IFLA_ADDR_LIST_ENTRY, mac, 32);
+                }
+                addattr_nest_end(&req->n, nest_mc_list);
+            }
+            addattr_nest_end(&req->n, nest_addr_filter);
+        }
+
+        if (vlan_list) {
+            struct rtattr *nest_vlans = NULL;
+            unsigned long arg_vlans[4096/64];
+
+            memset(arg_vlans, 0, 512);
+            for (i = 0; i < vlan_list_count; i++)
+                arg_vlans[atoi(vlan_list[i])/64] |=
+                    1UL << (atoi(vlan_list[i])%64);
+
+            nest_vlans = addattr_nest(&req->n, sizeof(*req),
+                    IFLA_RX_FILTER_VLAN);
+            addattr_l(&req->n, sizeof(*req),
+                IFLA_RX_FILTER_VLAN_BITMAP,
+                arg_vlans, sizeof(arg_vlans));
+            addattr_nest_end(&req->n, nest_vlans);
+        }
+
+        addattr_nest_end(&req->n, nest_rx_filter);
+        if (nest_vf_filters)
+            addattr_nest_end(&req->n, nest_vf_filters);
+
+        if (flags_list) {
+            for (i = 0; i < flags_list_count; i++)
+                free(flags_list[i]);
+            free(flags_list);
+        }
+        if (uc_list) {
+            for (i = 0; i < uc_list_count; i++)
+                free(uc_list[i]);
+            free(uc_list);
+        }
+        if (mc_list) {
+            for (i = 0; i < mc_list_count; i++)
+                free(mc_list[i]);
+            free(mc_list);
+        }
+    }
+
+    *argcp = argc;
+    *argvp = argv;
+
+    return 0;
+}
+
+int iplink_parse_vf(int vf, int *argcp, char ***argvp,
+             struct iplink_req *req)
+{
     int len, argc = *argcp;
     char **argv = *argvp;
+    struct rtattr *vflist;
     struct rtattr *vfinfo;
-
-    vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+    char *mac = NULL;
+    char *vlan = NULL;
+    char *qos = NULL;
+    char *rate = NULL;
+    struct ifla_vf_mac ivm = { .vf = vf, };
+    struct ifla_vf_vlan ivv = { .vf = vf, .qos = 0, };
+    struct ifla_vf_tx_rate ivt = { .vf = vf, };
 
     while (NEXT_ARG_OK()) {
         NEXT_ARG();
-        if (matches(*argv, "mac") == 0) {
-            struct ifla_vf_mac ivm;
+        if (matches(*argv, "rx_filter") == 0) {
+            iplink_parse_rx_filter(vf, &argc, &argv, req);
+        } else if (matches(*argv, "mac") == 0) {
             NEXT_ARG();
-            ivm.vf = vf;
-            len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
-            if (len < 0)
-                return -1;
-            addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm,
sizeof(ivm));
+            mac = *argv;
         } else if (matches(*argv, "vlan") == 0) {
-            struct ifla_vf_vlan ivv;
             NEXT_ARG();
-            if (get_unsigned(&ivv.vlan, *argv, 0)) {
-                invarg("Invalid \"vlan\" value\n", *argv);
-            }
-            ivv.vf = vf;
-            ivv.qos = 0;
+            vlan = *argv;
             if (NEXT_ARG_OK()) {
                 NEXT_ARG();
                 if (matches(*argv, "qos") == 0) {
                     NEXT_ARG();
-                    if (get_unsigned(&ivv.qos, *argv, 0)) {
-                        invarg("Invalid \"qos\" value\n", *argv);
-                    }
+                    qos = *argv;
                 } else {
                     /* rewind arg */
                     PREV_ARG();
                 }
             }
-            addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv,
sizeof(ivv));
         } else if (matches(*argv, "rate") == 0) {
-            struct ifla_vf_tx_rate ivt;
             NEXT_ARG();
-            if (get_unsigned(&ivt.rate, *argv, 0)) {
-                invarg("Invalid \"rate\" value\n", *argv);
-            }
-            ivt.vf = vf;
-            addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt,
sizeof(ivt));
-        
+            rate = *argv;
         } else {
             /* rewind arg */
             PREV_ARG();
@@ -238,14 +447,46 @@ int iplink_parse_vf(int vf, int *argcp, char ***argvp,
     if (argc == *argcp)
         incomplete_command();
 
-    addattr_nest_end(&req->n, vfinfo);
+    if (mac || vlan || rate) {
+
+        vflist = addattr_nest(&req->n, sizeof(*req), IFLA_VFINFO_LIST);
+        vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+
+        if (mac) {
+            len = ll_addr_a2n((char *)ivm.mac, 32, mac);
+            if (len < 0)
+                invarg("Invalid \"mac\" value\n", mac);
+            addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
+                &ivm, sizeof(ivm));
+        }
+
+        if (vlan) {
+            if (get_unsigned(&ivv.vlan, vlan, 0))
+                invarg("Invalid \"vlan\" value\n", vlan);
+            if (qos) {
+                if (get_unsigned(&ivv.qos, qos, 0))
+                    invarg("Invalid \"qos\" value\n", qos);
+            }
+            addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN,
+                &ivv, sizeof(ivv));
+        }
+
+        if (rate) {
+            if (get_unsigned(&ivt.rate, rate, 0))
+                invarg("Invalid \"rate\" value\n", rate);
+            addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE,
+                &ivt, sizeof(ivt));
+        }
+
+        addattr_nest_end(&req->n, vfinfo);
+        addattr_nest_end(&req->n, vflist);
+    }
 
     *argcp = argc;
     *argvp = argv;
     return 0;
 }
 
-
 int iplink_parse(int argc, char **argv, struct iplink_req *req,
         char **name, char **type, char **link, char **dev, int *group)
 {
@@ -362,12 +603,9 @@ int iplink_parse(int argc, char **argv, struct
iplink_req *req,
             if (get_integer(&vf,  *argv, 0)) {
                 invarg("Invalid \"vf\" value\n", *argv);
             }
-            vflist = addattr_nest(&req->n, sizeof(*req),
-                          IFLA_VFINFO_LIST);
             len = iplink_parse_vf(vf, &argc, &argv, req);
             if (len < 0)
                 return -1;
-            addattr_nest_end(&req->n, vflist);
         } else if (matches(*argv, "master") == 0) {
             int ifindex;
             NEXT_ARG();

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux