]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
iproute2: add VF_PORT support
authorRoopa Prabhu <roprabhu@cisco.com>
Tue, 9 Nov 2010 14:47:52 +0000 (14:47 +0000)
committerStephen Hemminger <stephen.hemminger@vyatta.com>
Thu, 13 Jan 2011 22:50:46 +0000 (14:50 -0800)
Resubmitting Scott Feldmans original patch with below changes

- Fix port profile strlen which was off by 1
- Added function to convert IFLA_PORT_RESPONSE codes to string

Add support for IFLA_VF_PORTS.  VF port netlink msg layout is

        [IFLA_NUM_VF]
        [IFLA_VF_PORTS]
                [IFLA_VF_PORT]
                        [IFLA_PORT_*], ...
                [IFLA_VF_PORT]
                        [IFLA_PORT_*], ...
                ...
        [IFLA_PORT_SELF]
                [IFLA_PORT_*], ...

The iproute2 cmd line for link set is now:

Usage: ip link add link DEV [ name ] NAME
                   [ txqueuelen PACKETS ]
                   [ address LLADDR ]
                   [ broadcast LLADDR ]
                   [ mtu MTU ]
                   type TYPE [ ARGS ]
       ip link delete DEV type TYPE [ ARGS ]

       ip link set DEVICE [ { up | down } ]
                          [ arp { on | off } ]
                          [ dynamic { on | off } ]
                          [ multicast { on | off } ]
                          [ allmulticast { on | off } ]
                          [ promisc { on | off } ]
                          [ trailers { on | off } ]
                          [ txqueuelen PACKETS ]
                          [ name NEWNAME ]
                          [ address LLADDR ]
                          [ broadcast LLADDR ]
                          [ mtu MTU ]
                          [ netns PID ]
                          [ alias NAME ]
                          [ port MODE { PROFILE | VSI } ]
                          [ vf NUM [ mac LLADDR ]
                                   [ vlan VLANID [ qos VLAN-QOS ] ]
                                   [ rate TXRATE ]
                                   [ port MODE { PROFILE | VSI } ] ]
       ip link show [ DEVICE ]

TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }
MODE := { assoc | preassoc | preassocrr | disassoc }
PROFILE := profile PROFILE
           [ instance UUID ]
           [ host UUID ]
VSI := vsi mgr MGRID type VTID ver VER
       [ instance UUID ]

Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
ip/ipaddress.c
ip/iplink.c

index a775ecd38c4443517fe95d555b929d788e91cb1a..0283a04ebc7c9b1be4fa38f1f6137cd4f71fa4f0 100644 (file)
@@ -186,6 +186,114 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
        }
 }
 
+static const char *vf_port_response_n2a(__u16 response)
+{
+       switch (response) {
+       case PORT_VDP_RESPONSE_SUCCESS:
+               return "SUCCESS";
+       case PORT_VDP_RESPONSE_INVALID_FORMAT:
+               return "INVALID FORMAT";
+       case PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES:
+               return "INSUFFICIENT RESOURCES";
+       case PORT_VDP_RESPONSE_UNUSED_VTID:
+               return "UNUSED VTID";
+       case PORT_VDP_RESPONSE_VTID_VIOLATION:
+               return "VTID VIOLATION";
+       case PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION:
+               return "VTID VERSION VIOLATION";
+       case PORT_VDP_RESPONSE_OUT_OF_SYNC:
+               return "OUT-OF-SYNC";
+       case PORT_PROFILE_RESPONSE_SUCCESS:
+               return "SUCCESS";
+       case PORT_PROFILE_RESPONSE_INPROGRESS:
+               return "IN-PROGRESS";
+       case PORT_PROFILE_RESPONSE_INVALID:
+               return "INVALID";
+       case PORT_PROFILE_RESPONSE_BADSTATE:
+               return "BAD STATE";
+       case PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES:
+               return "INSUFFICIENT RESOURCES";
+       case PORT_PROFILE_RESPONSE_ERROR:
+               return "ERROR";
+       default:
+               return "UNKNOWN RESPONSE";
+       }
+}
+
+static void print_port(FILE *fp, struct rtattr *port[])
+{
+       struct ifla_port_vsi *vsi;
+#define uuid_fmt "%02X%02X%02X%02X-%02X%02X-%02X%02X-" \
+       "%02X%02X-%02X%02X%02X%02X%02X%02X"
+       unsigned char *uuid;
+       __u8 request;
+       __u16 response;
+
+       if (port[IFLA_PORT_VF])
+               fprintf(fp, "\n    vf %d port",
+                       *(__u32 *)RTA_DATA(port[IFLA_PORT_VF]));
+       else
+               fprintf(fp, "\n    port");
+
+       if (port[IFLA_PORT_REQUEST]) {
+               request = *(__u8 *)RTA_DATA(port[IFLA_PORT_REQUEST]);
+               fprintf(fp, " %s",
+                       request == PORT_REQUEST_PREASSOCIATE ? "preassoc" :
+                       request == PORT_REQUEST_PREASSOCIATE_RR ? "preassocrr" :
+                       request == PORT_REQUEST_ASSOCIATE ? "assoc" :
+                       request == PORT_REQUEST_DISASSOCIATE ? "disassoc" :
+                       "unknown request");
+       }
+
+       if (port[IFLA_PORT_PROFILE])
+               fprintf(fp, " profile \"%s\"",
+                       (char *)RTA_DATA(port[IFLA_PORT_PROFILE]));
+
+       if (port[IFLA_PORT_VSI_TYPE]) {
+               vsi = RTA_DATA(port[IFLA_PORT_VSI_TYPE]);
+               fprintf(fp, " vsi mgr %d type 0x%02x%02x%02x ver %d",
+                       vsi->vsi_mgr_id, vsi->vsi_type_id[0],
+                       vsi->vsi_type_id[1], vsi->vsi_type_id[2],
+                       vsi->vsi_type_version);
+       }
+
+       if (port[IFLA_PORT_RESPONSE]) {
+               response = *(__u16 *)RTA_DATA(port[IFLA_PORT_RESPONSE]);
+               fprintf(fp, " status: %s", vf_port_response_n2a(response));
+       }
+
+       if (port[IFLA_PORT_INSTANCE_UUID]) {
+               uuid = RTA_DATA(port[IFLA_PORT_INSTANCE_UUID]);
+               fprintf(fp, "\n        instance "uuid_fmt,
+                       uuid[0],  uuid[1],  uuid[2],  uuid[3],
+                       uuid[4],  uuid[5],  uuid[6],  uuid[7],
+                       uuid[8],  uuid[9],  uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+       }
+
+       if (port[IFLA_PORT_HOST_UUID]) {
+               uuid = RTA_DATA(port[IFLA_PORT_HOST_UUID]);
+               fprintf(fp, "\n            host "uuid_fmt,
+                       uuid[0],  uuid[1],  uuid[2],  uuid[3],
+                       uuid[4],  uuid[5],  uuid[6],  uuid[7],
+                       uuid[8],  uuid[9],  uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+       }
+}
+
+static void print_vfport(FILE *fp, struct rtattr *vfport)
+{
+       struct rtattr *port[IFLA_PORT_MAX+1];
+
+       if (vfport->rta_type != IFLA_VF_PORT) {
+               fprintf(stderr, "BUG: rta type is %d\n", vfport->rta_type);
+               return;
+       }
+
+       parse_rtattr_nested(port, IFLA_PORT_MAX, vfport);
+       print_port(fp, port);
+}
+
 static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
 {
        struct ifla_vf_mac *vf_mac;
@@ -420,6 +528,20 @@ int print_linkinfo(const struct sockaddr_nl *who,
                        print_vfinfo(fp, i);
        }
 
+       if (do_link && tb[IFLA_PORT_SELF]) {
+               struct rtattr *port[IFLA_PORT_MAX+1];
+               parse_rtattr_nested(port, IFLA_PORT_MAX, tb[IFLA_PORT_SELF]);
+               print_port(fp, port);
+       }
+
+       if (do_link && tb[IFLA_VF_PORTS] && tb[IFLA_NUM_VF]) {
+               struct rtattr *i, *vfports = tb[IFLA_VF_PORTS];
+               int rem = RTA_PAYLOAD(vfports);
+               for (i = RTA_DATA(vfports); RTA_OK(i, rem);
+                       i = RTA_NEXT(i, rem))
+                       print_vfport(fp, i);
+       }
+
        fprintf(fp, "\n");
        fflush(fp);
        return 0;
index cb2c4f5e3367f460bc33adfbb664e0046a2e9e78..961a3efd6740d3db107dd719169e3b148e0f0e6e 100644 (file)
@@ -68,14 +68,22 @@ void iplink_usage(void)
        fprintf(stderr, "                         [ mtu MTU ]\n");
        fprintf(stderr, "                         [ netns PID ]\n");
        fprintf(stderr, "                         [ alias NAME ]\n");
+       fprintf(stderr, "                         [ port MODE { PROFILE | VSI } ]\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, "                                  [ port MODE { PROFILE | VSI } ] ]\n");
        fprintf(stderr, "       ip link show [ DEVICE ]\n");
 
        if (iplink_have_newlink()) {
                fprintf(stderr, "\n");
                fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }\n");
+               fprintf(stderr, "MODE := { assoc | preassoc | preassocrr | disassoc }\n");
+               fprintf(stderr, "PROFILE := profile PROFILE\n");
+               fprintf(stderr, "           [ instance UUID ]\n");
+               fprintf(stderr, "           [ host UUID ]\n");
+               fprintf(stderr, "VSI := vsi mgr MGRID type VTID ver VER\n");
+               fprintf(stderr, "       [ instance UUID ]\n");
        }
        exit(-1);
 }
@@ -176,55 +184,170 @@ struct iplink_req {
        char                    buf[1024];
 };
 
-int iplink_parse_vf(int vf, int *argcp, char ***argvp,
-                          struct iplink_req *req)
+void iplink_parse_port(int vf, int *argcp, char ***argvp,
+                      struct iplink_req *req)
+{
+       int argc = *argcp;
+       char **argv = *argvp;
+       struct rtattr *nest, *nest_inner = NULL;
+       struct ifla_port_vsi port_vsi;
+       char *port_profile = NULL;
+       char *instance_uuid = NULL;
+       char *host_uuid = NULL;
+       unsigned char uuid[16];
+       char *uuid_fmt = "%02X%02X%02X%02X-%02X%02X-%02X%02X-"
+               "%02X%02X-%02X%02X%02X%02X%02X%02X";
+       int parsed;
+       int manager_id = -1;
+       int type_id = -1;
+       int type_id_version = -1;
+       int request = -1;
+       int vsi = 0;
+
+       if (NEXT_ARG_OK()) {
+               NEXT_ARG();
+               if (matches(*argv, "assoc") == 0)
+                       request = PORT_REQUEST_ASSOCIATE;
+               else if (matches(*argv, "preassoc") == 0)
+                       request = PORT_REQUEST_PREASSOCIATE;
+               else if (matches(*argv, "preassocrr") == 0)
+                       request = PORT_REQUEST_PREASSOCIATE_RR;
+               else if (matches(*argv, "disassoc") == 0)
+                       request = PORT_REQUEST_DISASSOCIATE;
+       }
+
+       while (NEXT_ARG_OK()) {
+               NEXT_ARG();
+               if (matches(*argv, "vsi") == 0) {
+                       vsi = 1;
+               } else if (matches(*argv, "mgr") == 0) {
+                       NEXT_ARG();
+                       if (get_integer(&manager_id, *argv, 0))
+                               invarg("Invalid \"mgr\" value\n", *argv);
+               } else if (matches(*argv, "type") == 0) {
+                       NEXT_ARG();
+                       if (get_integer(&type_id, *argv, 0))
+                               invarg("Invalid \"type\" value\n", *argv);
+               } else if (matches(*argv, "ver") == 0) {
+                       NEXT_ARG();
+                       if (get_integer(&type_id_version, *argv, 0))
+                               invarg("Invalid \"ver\" value\n", *argv);
+               } else if (matches(*argv, "profile") == 0) {
+                       NEXT_ARG();
+                       port_profile = *argv;
+               } else if (matches(*argv, "instance") == 0) {
+                       NEXT_ARG();
+                       instance_uuid = *argv;
+               } else if (matches(*argv, "host") == 0) {
+                       NEXT_ARG();
+                       host_uuid = *argv;
+               } else {
+                       /* rewind arg */
+                       PREV_ARG();
+                       break;
+               }
+       }
+
+       if (argc == *argcp)
+               incomplete_command();
+
+       if (vf == PORT_SELF_VF) {
+               nest = addattr_nest(&req->n, sizeof(*req), IFLA_PORT_SELF);
+       } else {
+               nest = addattr_nest(&req->n, sizeof(*req), IFLA_VF_PORTS);
+               nest_inner = addattr_nest(&req->n, sizeof(*req), IFLA_VF_PORT);
+               addattr_l(&req->n, sizeof(*req), IFLA_PORT_VF,
+                       (uint32_t *)&vf, sizeof(uint32_t));
+       }
+
+       if (port_profile)
+               addattr_l(&req->n, sizeof(*req), IFLA_PORT_PROFILE,
+                       port_profile, strlen(port_profile) + 1);
+
+       if (instance_uuid) {
+               parsed = sscanf(instance_uuid, uuid_fmt,
+                       &uuid[0],  &uuid[1],  &uuid[2],  &uuid[3],
+                       &uuid[4],  &uuid[5],  &uuid[6],  &uuid[7],
+                       &uuid[8],  &uuid[9],  &uuid[10], &uuid[11],
+                       &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
+               if (parsed != sizeof(uuid))
+                       invarg("Invalid \"uuid\" value\n", instance_uuid);
+               addattr_l(&req->n, sizeof(*req), IFLA_PORT_INSTANCE_UUID,
+                       uuid, sizeof(uuid));
+
+       }
+
+       if (host_uuid) {
+               parsed = sscanf(host_uuid, uuid_fmt,
+                       &uuid[0],  &uuid[1],  &uuid[2],  &uuid[3],
+                       &uuid[4],  &uuid[5],  &uuid[6],  &uuid[7],
+                       &uuid[8],  &uuid[9],  &uuid[10], &uuid[11],
+                       &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
+               if (parsed != sizeof(uuid))
+                       invarg("Invalid \"uuid\" value\n", host_uuid);
+               addattr_l(&req->n, sizeof(*req), IFLA_PORT_HOST_UUID,
+                       uuid, sizeof(uuid));
+
+       }
+
+       if (vsi) {
+               port_vsi.vsi_mgr_id = manager_id;
+               memcpy(&port_vsi.vsi_type_id, &type_id,
+                       sizeof(port_vsi.vsi_type_id));
+               port_vsi.vsi_type_version = type_id_version;
+               addattr_l(&req->n, sizeof(*req), IFLA_PORT_VSI_TYPE,
+                       &port_vsi, sizeof(port_vsi));
+       }
+
+       addattr_l(&req->n, sizeof(*req), IFLA_PORT_REQUEST,
+               &request, 1);
+
+       if (nest_inner)
+               addattr_nest_end(&req->n, nest_inner);
+       addattr_nest_end(&req->n, nest);
+
+       *argcp = argc;
+       *argvp = argv;
+}
+
+void 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, "port") == 0) {
+                       iplink_parse_port(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();
@@ -235,11 +358,43 @@ 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;
 }
 
 
@@ -349,18 +504,14 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                req->i.ifi_flags |= IFF_NOARP;
                        } else
                                return on_off("noarp");
+               } else if (strcmp(*argv, "port") == 0) {
+                       iplink_parse_port(vf, &argc, &argv, req);
                } else if (strcmp(*argv, "vf") == 0) {
-                       struct rtattr *vflist;
                        NEXT_ARG();
                        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);
+                       iplink_parse_vf(vf, &argc, &argv, req);
 #ifdef IFF_DYNAMIC
                } else if (matches(*argv, "dynamic") == 0) {
                        NEXT_ARG();