]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
ip link: Add support to configure SR-IOV VF to vlan protocol 802.1ad (VST QinQ)
authorMoshe Shemesh <moshe@mellanox.com>
Wed, 28 Sep 2016 07:58:59 +0000 (10:58 +0300)
committerStephen Hemminger <stephen@networkplumber.org>
Mon, 10 Oct 2016 02:17:15 +0000 (19:17 -0700)
Introduce a new API that exposes a list of vlans per VF (IFLA_VF_VLAN_LIST),
giving the ability for user-space application to specify it for the VF as
an option to support 802.1ad (VST QinQ).

We introduce struct vf_vlan_info, which extends struct vf_vlan and adds
an optional VF VLAN proto parameter.
Default VLAN-protocol is 802.1Q.

Add IFLA_VF_VLAN_LIST in addition to IFLA_VF_VLAN to keep backward
compatibility with older kernel versions.

Suitable ip link tool command examples:
 - Set vf vlan protocol 802.1ad (S-TAG)
ip link set eth0 vf 1 vlan 100 proto 802.1ad
 - Set vf vlan S-TAG and vlan C-TAG (VST QinQ)
ip link set eth0 vf 1 vlan 100 proto 802.1ad vlan 30 proto 802.1Q
 - Set vf to VST (802.1Q) mode
ip link set eth0 vf 1 vlan 100 proto 802.1Q
 - Or by omitting the new parameter (backward compatible)
ip link set eth0 vf 1 vlan 100

Signed-off-by: Moshe Shemesh <moshe@mellanox.com>
Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
ip/ipaddress.c
ip/iplink.c
man/man8/ip-link.8.in

index 3614837622e653836ed50615e5c13d98ddee6ab7..7f05258f434536d055308426798ce3b81b20afac 100644 (file)
@@ -321,7 +321,6 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats);
 static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
 {
        struct ifla_vf_mac *vf_mac;
-       struct ifla_vf_vlan *vf_vlan;
        struct ifla_vf_tx_rate *vf_tx_rate;
        struct ifla_vf_spoofchk *vf_spoofchk;
        struct ifla_vf_link_state *vf_linkstate;
@@ -338,7 +337,6 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
        parse_rtattr_nested(vf, IFLA_VF_MAX, 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]);
 
        /* Check if the spoof checking vf info type is supported by
@@ -369,10 +367,35 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
        fprintf(fp, "%s    vf %d MAC %s", _SL_, vf_mac->vf,
                ll_addr_n2a((unsigned char *)&vf_mac->mac,
                            ETH_ALEN, 0, b1, sizeof(b1)));
-       if (vf_vlan->vlan)
-               fprintf(fp, ", vlan %d", vf_vlan->vlan);
-       if (vf_vlan->qos)
-               fprintf(fp, ", qos %d", vf_vlan->qos);
+       if (vf[IFLA_VF_VLAN_LIST]) {
+               struct rtattr *i, *vfvlanlist = vf[IFLA_VF_VLAN_LIST];
+               int rem = RTA_PAYLOAD(vfvlanlist);
+
+               for (i = RTA_DATA(vfvlanlist);
+                     RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+                       struct ifla_vf_vlan_info *vf_vlan_info =
+                                       RTA_DATA(i);
+                       SPRINT_BUF(b2);
+
+                       if (vf_vlan_info->vlan)
+                               fprintf(fp, ", vlan %d", vf_vlan_info->vlan);
+                       if (vf_vlan_info->qos)
+                               fprintf(fp, ", qos %d", vf_vlan_info->qos);
+                       if (vf_vlan_info->vlan_proto &&
+                           vf_vlan_info->vlan_proto != htons(ETH_P_8021Q))
+                               fprintf(fp, ", vlan protocol %s",
+                                       ll_proto_n2a(vf_vlan_info->vlan_proto,
+                                                    b2, sizeof(b2)));
+
+               }
+       } else {
+               struct ifla_vf_vlan *vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
+
+               if (vf_vlan->vlan)
+                       fprintf(fp, ", vlan %d", vf_vlan->vlan);
+               if (vf_vlan->qos)
+                       fprintf(fp, ", qos %d", vf_vlan->qos);
+       }
        if (vf_tx_rate->rate)
                fprintf(fp, ", tx rate %d (Mbps)", vf_tx_rate->rate);
 
index dec8268a0dbb4489a1b6775c660fa1fd60c2ce06..cbfc9f3342b0187f82c447dc9905036cf2cbc0b6 100644 (file)
@@ -76,7 +76,7 @@ void iplink_usage(void)
        fprintf(stderr, "                         [ link-netnsid ID ]\n");
        fprintf(stderr, "                         [ alias NAME ]\n");
        fprintf(stderr, "                         [ vf NUM [ mac LLADDR ]\n");
-       fprintf(stderr, "                                  [ vlan VLANID [ qos VLAN-QOS ] ]\n");
+       fprintf(stderr, "                                  [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n");
 
        fprintf(stderr, "                                  [ rate TXRATE ]\n");
        fprintf(stderr, "                                  [ max_tx_rate TXRATE ]\n");
@@ -255,6 +255,60 @@ static int nl_get_ll_addr_len(unsigned int dev_index)
        return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
 }
 
+static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
+                                     struct ifla_vf_vlan_info *ivvip)
+{
+       int argc = *argcp;
+       char **argv = *argvp;
+
+       NEXT_ARG();
+       if (get_unsigned(&ivvip->vlan, *argv, 0))
+               invarg("Invalid \"vlan\" value\n", *argv);
+
+       ivvip->vf = vf;
+       ivvip->qos = 0;
+       ivvip->vlan_proto = htons(ETH_P_8021Q);
+       if (NEXT_ARG_OK()) {
+               NEXT_ARG();
+               if (matches(*argv, "qos") == 0) {
+                       NEXT_ARG();
+                       if (get_unsigned(&ivvip->qos, *argv, 0))
+                               invarg("Invalid \"qos\" value\n", *argv);
+               } else {
+                       /* rewind arg */
+                       PREV_ARG();
+               }
+       }
+       if (NEXT_ARG_OK()) {
+               NEXT_ARG();
+               if (matches(*argv, "proto") == 0) {
+                       NEXT_ARG();
+                       if (ll_proto_a2n(&ivvip->vlan_proto, *argv))
+                               invarg("protocol is invalid\n", *argv);
+                       if (ivvip->vlan_proto != htons(ETH_P_8021AD) &&
+                           ivvip->vlan_proto != htons(ETH_P_8021Q)) {
+                               SPRINT_BUF(b1);
+                               SPRINT_BUF(b2);
+                               char msg[64 + sizeof(b1) + sizeof(b2)];
+
+                               sprintf(msg, "Invalid \"vlan protocol\""
+                                       " value - supported %s, %s\n",
+                                       ll_proto_n2a(htons(ETH_P_8021Q),
+                                            b1, sizeof(b1)),
+                                       ll_proto_n2a(htons(ETH_P_8021AD),
+                                            b2, sizeof(b2)));
+                               invarg(msg, *argv);
+                       }
+               } else {
+                       /* rewind arg */
+                       PREV_ARG();
+               }
+       }
+
+       *argcp = argc;
+       *argvp = argv;
+}
+
 static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                           struct iplink_req *req, int dev_index)
 {
@@ -308,27 +362,41 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                        addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
                                  &ivm, sizeof(ivm));
                } else if (matches(*argv, "vlan") == 0) {
-                       struct ifla_vf_vlan ivv;
+                       struct ifla_vf_vlan_info ivvi;
 
-                       NEXT_ARG();
-                       if (get_unsigned(&ivv.vlan, *argv, 0))
-                               invarg("Invalid \"vlan\" value\n", *argv);
+                       iplink_parse_vf_vlan_info(vf, &argc, &argv, &ivvi);
+                       /* support the old interface in case of older kernel*/
+                       if (ivvi.vlan_proto == htons(ETH_P_8021Q)) {
+                               struct ifla_vf_vlan ivv;
 
-                       ivv.vf = vf;
-                       ivv.qos = 0;
-                       if (NEXT_ARG_OK()) {
-                               NEXT_ARG();
-                               if (matches(*argv, "qos") == 0) {
+                               ivv.vf = ivvi.vf;
+                               ivv.vlan = ivvi.vlan;
+                               ivv.qos = ivvi.qos;
+                               addattr_l(&req->n, sizeof(*req),
+                                         IFLA_VF_VLAN, &ivv, sizeof(ivv));
+                       } else {
+                               struct rtattr *vfvlanlist;
+
+                               vfvlanlist = addattr_nest(&req->n, sizeof(*req),
+                                                         IFLA_VF_VLAN_LIST);
+                               addattr_l(&req->n, sizeof(*req),
+                                         IFLA_VF_VLAN_INFO, &ivvi,
+                                         sizeof(ivvi));
+
+                               while (NEXT_ARG_OK()) {
                                        NEXT_ARG();
-                                       if (get_unsigned(&ivv.qos, *argv, 0))
-                                               invarg("Invalid \"qos\" value\n", *argv);
-                               } else {
-                                       /* rewind arg */
-                                       PREV_ARG();
+                                       if (matches(*argv, "vlan") != 0) {
+                                               PREV_ARG();
+                                               break;
+                                       }
+                                       iplink_parse_vf_vlan_info(vf, &argc,
+                                                                 &argv, &ivvi);
+                                       addattr_l(&req->n, sizeof(*req),
+                                                 IFLA_VF_VLAN_INFO, &ivvi,
+                                                 sizeof(ivvi));
                                }
+                               addattr_nest_end(&req->n, vfvlanlist);
                        }
-                       addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN,
-                                 &ivv, sizeof(ivv));
                } else if (matches(*argv, "rate") == 0) {
                        struct ifla_vf_tx_rate ivt;
 
index ffc4160a1b6e736e9daa7a442109cfb15be307ce..4dfa43fc14f5099a6b7c4f947ae1dab0d2837d90 100644 (file)
@@ -102,10 +102,7 @@ ip-link \- network device configuration
 .IR LLADDR " ]"
 .br
 .in +9
-.RB "[ " vlan
-.IR VLANID " [ "
-.B qos
-.IR VLAN-QOS " ] ]"
+.RI "[ " VFVLAN-LIST " ]"
 .br
 .RB "[ " rate
 .IR TXRATE " ]"
@@ -191,6 +188,18 @@ ip-link \- network device configuration
 .IR ETYPE " := [ " TYPE " |"
 .BR bridge_slave " | " bond_slave " ]"
 
+.ti -8
+.IR VFVLAN-LIST " := [ "  VFVLAN-LIST " ] " VFVLAN
+
+.ti -8
+.IR VFVLAN " := "
+.RB "[ " vlan
+.IR VLANID " [ "
+.B qos
+.IR VLAN-QOS " ] ["
+.B proto
+.IR VLAN-PROTO " ] ]"
+
 .SH "DESCRIPTION"
 .SS ip link add - add virtual link
 
@@ -1237,6 +1246,19 @@ and
 .B qos
 as 0 disables VLAN tagging and filtering for the VF.
 
+.sp
+.BI proto " VLAN-PROTO"
+- assign VLAN PROTOCOL for the VLAN tag, either 802.1Q or 802.1ad.
+Setting to 802.1ad, all traffic sent from the VF will be tagged with VLAN S-Tag.
+Incoming traffic will have VLAN S-Tags stripped before being passed to the VF.
+Setting to 802.1ad also enables an option to concatenate another VLAN tag, so both
+S-TAG and C-TAG will be inserted/stripped for outgoing/incoming traffic, respectively.
+If not specified, the value is assumed to be 802.1Q. Both the
+.B vf
+and
+.B vlan
+parameters must be specified.
+
 .sp
 .BI rate " TXRATE"
 -- change the allowed transmit bandwidth, in Mbps, for the specified VF.