]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
Add support to configure SR-IOV VF minimum and maximum Tx rate through ip tool
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Thu, 22 May 2014 13:59:37 +0000 (09:59 -0400)
committerStephen Hemminger <stephen@networkplumber.org>
Mon, 9 Jun 2014 19:51:57 +0000 (12:51 -0700)
o "min_tx_rate" option has been added for minimum Tx rate. Hence, for
  consistent naming, "max_tx_rate" option has been introduced for maximum
  Tx rate.

o Change in v2: "rate" can be used along with "max_tx_rate".
  When both are specified, "max_tx_rate" should override.

o Change in v3:
  * IFLA_VF_RATE: When IFLA_VF_RATE is used, and user has given only one of
    min_tx_rate or max_tx_rate, reading of previous rate limits is done in
    userspace instead of in kernel space before ndo_set_vf_rate.

  * IFLA_VF_TX_RATE: When IFLA_VF_TX_RATE is used, min_tx_rate is always read
    in kernel space. This takes care of below scenarios:
    (1) when old tool sends "rate" but kernel is new (expects min and max)
    (2) when new tool sends only "rate" but kernel is old (expects only "rate")

o Change in v4 as suggested by Stephen Hemminger:
  * As per iproute policy, input and output formats should match. Changing display
    of max_tx_rate and min_tx_rate options accordingly.
./ip/ip link show p3p1
8: p3p1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
        link/ether 00:0e:1e:16:ce:40 brd ff:ff:ff:ff:ff:ff
        vf 0 MAC 2a:18:8f:4d:3d:d4, tx rate 700 (Mbps), max_tx_rate 700Mbps, min_tx_rate 200Mbps
        vf 1 MAC 72:dc:ba:f9:df:fd

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
ip/ip_common.h
ip/ipaddress.c
ip/iplink.c
man/man8/ip-link.8.in

index 698dc7aa611497ae5141f5f1d49e2fd0f1caec70..ac1e4c195e00de60617bc89451a28529ede4153f 100644 (file)
@@ -17,6 +17,7 @@ extern int iproute_monitor(int argc, char **argv);
 extern void iplink_usage(void) __attribute__((noreturn));
 extern void iproute_reset_filter(void);
 extern void ipmroute_reset_filter(void);
+void ipaddr_get_vf_rate(int, int *, int *, int);
 extern void ipaddr_reset_filter(int);
 extern void ipneigh_reset_filter(void);
 extern void ipntable_reset_filter(void);
index 76f478230ffeceec9817bf3fe3c8eff36a1cd206..8138e8626c8792d642568dcd4b7a15026c1a69bd 100644 (file)
@@ -245,6 +245,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
 {
        struct ifla_vf_mac *vf_mac;
        struct ifla_vf_vlan *vf_vlan;
+       struct ifla_vf_rate *vf_rate;
        struct ifla_vf_tx_rate *vf_tx_rate;
        struct ifla_vf_spoofchk *vf_spoofchk;
        struct ifla_vf_link_state *vf_linkstate;
@@ -262,6 +263,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
        vf_mac = RTA_DATA(vf[IFLA_VF_MAC]);
        vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
        vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]);
+       vf_rate = RTA_DATA(vf[IFLA_VF_RATE]);
 
        /* Check if the spoof checking vf info type is supported by
         * this kernel.
@@ -297,6 +299,10 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
                fprintf(fp, ", qos %d", vf_vlan->qos);
        if (vf_tx_rate->rate)
                fprintf(fp, ", tx rate %d (Mbps)", vf_tx_rate->rate);
+       if (vf_rate->max_tx_rate)
+               fprintf(fp, ", max_tx_rate %dMbps", vf_rate->max_tx_rate);
+       if (vf_rate->min_tx_rate)
+               fprintf(fp, ", min_tx_rate %dMbps", vf_rate->min_tx_rate);
        if (vf_spoofchk && vf_spoofchk->setting != -1) {
                if (vf_spoofchk->setting)
                        fprintf(fp, ", spoof checking on");
@@ -1278,6 +1284,63 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
        return 0;
 }
 
+static void
+ipaddr_loop_each_vf(struct rtattr *tb[], int vfnum, int *min, int *max)
+{
+       struct rtattr *vflist = tb[IFLA_VFINFO_LIST];
+       struct rtattr *i, *vf[IFLA_VF_MAX+1];
+       struct ifla_vf_rate *vf_rate;
+       int rem;
+
+       rem = RTA_PAYLOAD(vflist);
+
+       for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+               parse_rtattr_nested(vf, IFLA_VF_MAX, i);
+               vf_rate = RTA_DATA(vf[IFLA_VF_RATE]);
+               if (vf_rate->vf == vfnum) {
+                       *min = vf_rate->min_tx_rate;
+                       *max = vf_rate->max_tx_rate;
+                       return;
+               }
+       }
+       fprintf(stderr, "Cannot find VF %d\n", vfnum);
+       exit(1);
+}
+
+void ipaddr_get_vf_rate(int vfnum, int *min, int *max, int idx)
+{
+       struct nlmsg_chain linfo = { NULL, NULL};
+       struct rtattr *tb[IFLA_MAX+1];
+       struct ifinfomsg *ifi;
+       struct nlmsg_list *l;
+       struct nlmsghdr *n;
+       int len;
+
+       if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETLINK) < 0) {
+               perror("Cannot send dump request");
+               exit(1);
+       }
+       if (rtnl_dump_filter(&rth, store_nlmsg, &linfo) < 0) {
+               fprintf(stderr, "Dump terminated\n");
+               exit(1);
+       }
+       for (l = linfo.head; l; l = l->next) {
+               n = &l->h;
+               ifi = NLMSG_DATA(n);
+
+               len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
+               if (len < 0 || idx && idx != ifi->ifi_index)
+                       continue;
+
+               parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+
+               if ((tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF])) {
+                       ipaddr_loop_each_vf(tb, vfnum, min, max);
+                       return;
+               }
+       }
+}
+
 int ipaddr_list_link(int argc, char **argv)
 {
        preferred_family = AF_PACKET;
index c94261ac5e694d0e8bfc11b15d17f596c6e51317..0d020efc1faedc12fb455a16004348077fe72bfb 100644 (file)
@@ -215,14 +215,38 @@ struct iplink_req {
 };
 
 static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
-                          struct iplink_req *req)
+                          struct iplink_req *req, int dev_index)
 {
+       char new_rate_api = 0, count = 0, override_legacy_rate = 0;
+       struct ifla_vf_rate tivt;
        int len, argc = *argcp;
        char **argv = *argvp;
        struct rtattr *vfinfo;
 
+       tivt.min_tx_rate = -1;
+       tivt.max_tx_rate = -1;
+
        vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
 
+       while (NEXT_ARG_OK()) {
+               NEXT_ARG();
+               count++;
+               if (!matches(*argv, "max_tx_rate")) {
+                       /* new API in use */
+                       new_rate_api = 1;
+                       /* override legacy rate */
+                       override_legacy_rate = 1;
+               } else if (!matches(*argv, "min_tx_rate")) {
+                       /* new API in use */
+                       new_rate_api = 1;
+               }
+       }
+
+       while (count--) {
+               /* rewind arg */
+               PREV_ARG();
+       }
+
        while (NEXT_ARG_OK()) {
                NEXT_ARG();
                if (matches(*argv, "mac") == 0) {
@@ -261,7 +285,25 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                                invarg("Invalid \"rate\" value\n", *argv);
                        }
                        ivt.vf = vf;
-                       addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
+                       if (!new_rate_api)
+                               addattr_l(&req->n, sizeof(*req),
+                                         IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
+                       else if (!override_legacy_rate)
+                               tivt.max_tx_rate = ivt.rate;
+
+               } else if (matches(*argv, "max_tx_rate") == 0) {
+                       NEXT_ARG();
+                       if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
+                               invarg("Invalid \"max tx rate\" value\n",
+                                      *argv);
+                       tivt.vf = vf;
+
+               } else if (matches(*argv, "min_tx_rate") == 0) {
+                       NEXT_ARG();
+                       if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
+                               invarg("Invalid \"min tx rate\" value\n",
+                                      *argv);
+                       tivt.vf = vf;
 
                } else if (matches(*argv, "spoofchk") == 0) {
                        struct ifla_vf_spoofchk ivs;
@@ -295,6 +337,19 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                }
        }
 
+       if (new_rate_api) {
+               int tmin, tmax;
+               if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
+                       ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
+                       if (tivt.min_tx_rate == -1)
+                               tivt.min_tx_rate = tmin;
+                       if (tivt.max_tx_rate == -1)
+                               tivt.max_tx_rate = tmax;
+               }
+               addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
+                         sizeof(tivt));
+       }
+
        if (argc == *argcp)
                incomplete_command();
 
@@ -316,6 +371,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
        int vf = -1;
        int numtxqueues = -1;
        int numrxqueues = -1;
+       int dev_index;
 
        *group = -1;
        ret = argc;
@@ -428,7 +484,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        }
                        vflist = addattr_nest(&req->n, sizeof(*req),
                                              IFLA_VFINFO_LIST);
-                       len = iplink_parse_vf(vf, &argc, &argv, req);
+                       len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
                        if (len < 0)
                                return -1;
                        addattr_nest_end(&req->n, vflist);
@@ -510,6 +566,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        if (*dev)
                                duparg2("dev", *argv);
                        *dev = *argv;
+                       dev_index = ll_name_to_index(*dev);
                }
                argc--; argv++;
        }
index e126046952fe641f322e373b4bde5e6797c37f30..f89785c518d93cdad2cbfe4ffcd241c14651975a 100644 (file)
@@ -124,6 +124,10 @@ ip-link \- network device configuration
 .IR VLAN-QOS " ] ] ["
 .B rate
 .IR TXRATE " ] ["
+.B max_tx_rate
+.IR TXRATE " ] ["
+.B min_tx_rate
+.IR TXRATE " ] ["
 .B spoofchk { on | off } ] [
 .B state { auto | enable | disable}
 ] |
@@ -566,8 +570,24 @@ as 0 disables VLAN tagging and filtering for the VF.
 
 .sp
 .BI rate " TXRATE"
-- change the allowed transmit bandwidth, in Mbps, for the specified VF.
-Setting this parameter to 0 disables rate limiting. The
+-- change the allowed transmit bandwidth, in Mbps, for the specified VF.
+Setting this parameter to 0 disables rate limiting.
+.B vf
+parameter must be specified.
+Please use new API
+.B "max_tx_rate"
+option instead.
+
+.sp
+.BI max_tx_rate " TXRATE"
+- change the allowed maximum transmit bandwidth, in Mbps, for the specified VF.
+.B vf
+parameter must be specified.
+
+.sp
+.BI min_tx_rate " TXRATE"
+- change the allowed minimum transmit bandwidth, in Mbps, for the specified VF.
+Minimum TXRATE should be always <= Maximum TXRATE.
 .B vf
 parameter must be specified.