Add support to configure SR-IOV VF minimum and maximum Tx rate through ip tool
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>
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 76f4782..8138e86 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -245,6 +245,7 @@
{
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 @@
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 @@
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 @@
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;