diff options
| author | Scott Feldman <scofeldm@cisco.com> | 2010-06-01 04:59:33 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-06-02 05:26:40 -0400 |
| commit | 08f382ebb8a9efb898840aa74cf55148c7a98af6 (patch) | |
| tree | 2486b90342f17a8f5a1bf8feb1a219143b83da48 | |
| parent | f048fa9c8686119c3858a463cab6121dced7c0bf (diff) | |
enic: bug fix: make the set/get netlink VF_PORT support symmetrical
To make get/set netlink VF_PORT truly symmetrical, we need to keep track
of what items are set and only return those items on get. Previously, the
driver wasn't differentiating between a set of attr with a NULL string,
for example, and not setting the attr at all. We only want to return
the NULL string if the attr was actually set with a NULL string. Otherwise,
don't return the attr.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/enic/enic.h | 7 | ||||
| -rw-r--r-- | drivers/net/enic/enic_main.c | 200 |
2 files changed, 104 insertions, 103 deletions
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 85f2a2e7030a..45e86d1e5b1b 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h | |||
| @@ -74,7 +74,14 @@ struct enic_msix_entry { | |||
| 74 | void *devid; | 74 | void *devid; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | #define ENIC_SET_APPLIED (1 << 0) | ||
| 78 | #define ENIC_SET_REQUEST (1 << 1) | ||
| 79 | #define ENIC_SET_NAME (1 << 2) | ||
| 80 | #define ENIC_SET_INSTANCE (1 << 3) | ||
| 81 | #define ENIC_SET_HOST (1 << 4) | ||
| 82 | |||
| 77 | struct enic_port_profile { | 83 | struct enic_port_profile { |
| 84 | u32 set; | ||
| 78 | u8 request; | 85 | u8 request; |
| 79 | char name[PORT_PROFILE_MAX]; | 86 | char name[PORT_PROFILE_MAX]; |
| 80 | u8 instance_uuid[PORT_UUID_MAX]; | 87 | u8 instance_uuid[PORT_UUID_MAX]; |
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 6586b5c7e4b6..bc7d6b96de3d 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c | |||
| @@ -1029,8 +1029,7 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error) | |||
| 1029 | return err; | 1029 | return err; |
| 1030 | } | 1030 | } |
| 1031 | 1031 | ||
| 1032 | static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, | 1032 | static int enic_set_port_profile(struct enic *enic, u8 *mac) |
| 1033 | char *name, u8 *instance_uuid, u8 *host_uuid) | ||
| 1034 | { | 1033 | { |
| 1035 | struct vic_provinfo *vp; | 1034 | struct vic_provinfo *vp; |
| 1036 | u8 oui[3] = VIC_PROVINFO_CISCO_OUI; | 1035 | u8 oui[3] = VIC_PROVINFO_CISCO_OUI; |
| @@ -1040,97 +1039,112 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, | |||
| 1040 | "%02X%02X-%02X%02X%02X%02X%0X%02X"; | 1039 | "%02X%02X-%02X%02X%02X%02X%0X%02X"; |
| 1041 | int err; | 1040 | int err; |
| 1042 | 1041 | ||
| 1043 | if (!name) | 1042 | err = enic_vnic_dev_deinit(enic); |
| 1044 | return -EINVAL; | 1043 | if (err) |
| 1044 | return err; | ||
| 1045 | 1045 | ||
| 1046 | if (!is_valid_ether_addr(mac)) | 1046 | switch (enic->pp.request) { |
| 1047 | return -EADDRNOTAVAIL; | ||
| 1048 | 1047 | ||
| 1049 | vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE); | 1048 | case PORT_REQUEST_ASSOCIATE: |
| 1050 | if (!vp) | ||
| 1051 | return -ENOMEM; | ||
| 1052 | 1049 | ||
| 1053 | vic_provinfo_add_tlv(vp, | 1050 | if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) |
| 1054 | VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR, | 1051 | return -EINVAL; |
| 1055 | strlen(name) + 1, name); | ||
| 1056 | |||
| 1057 | vic_provinfo_add_tlv(vp, | ||
| 1058 | VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR, | ||
| 1059 | ETH_ALEN, mac); | ||
| 1060 | |||
| 1061 | if (instance_uuid) { | ||
| 1062 | uuid = instance_uuid; | ||
| 1063 | sprintf(uuid_str, uuid_fmt, | ||
| 1064 | uuid[0], uuid[1], uuid[2], uuid[3], | ||
| 1065 | uuid[4], uuid[5], uuid[6], uuid[7], | ||
| 1066 | uuid[8], uuid[9], uuid[10], uuid[11], | ||
| 1067 | uuid[12], uuid[13], uuid[14], uuid[15]); | ||
| 1068 | vic_provinfo_add_tlv(vp, | ||
| 1069 | VIC_LINUX_PROV_TLV_CLIENT_UUID_STR, | ||
| 1070 | sizeof(uuid_str), uuid_str); | ||
| 1071 | } | ||
| 1072 | 1052 | ||
| 1073 | if (host_uuid) { | 1053 | if (!is_valid_ether_addr(mac)) |
| 1074 | uuid = host_uuid; | 1054 | return -EADDRNOTAVAIL; |
| 1075 | sprintf(uuid_str, uuid_fmt, | ||
| 1076 | uuid[0], uuid[1], uuid[2], uuid[3], | ||
| 1077 | uuid[4], uuid[5], uuid[6], uuid[7], | ||
| 1078 | uuid[8], uuid[9], uuid[10], uuid[11], | ||
| 1079 | uuid[12], uuid[13], uuid[14], uuid[15]); | ||
| 1080 | vic_provinfo_add_tlv(vp, | ||
| 1081 | VIC_LINUX_PROV_TLV_HOST_UUID_STR, | ||
| 1082 | sizeof(uuid_str), uuid_str); | ||
| 1083 | } | ||
| 1084 | 1055 | ||
| 1085 | err = enic_vnic_dev_deinit(enic); | 1056 | vp = vic_provinfo_alloc(GFP_KERNEL, oui, |
| 1086 | if (err) | 1057 | VIC_PROVINFO_LINUX_TYPE); |
| 1087 | goto err_out; | 1058 | if (!vp) |
| 1059 | return -ENOMEM; | ||
| 1088 | 1060 | ||
| 1089 | memset(&enic->pp, 0, sizeof(enic->pp)); | 1061 | vic_provinfo_add_tlv(vp, |
| 1062 | VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR, | ||
| 1063 | strlen(enic->pp.name) + 1, enic->pp.name); | ||
| 1090 | 1064 | ||
| 1091 | err = enic_dev_init_prov(enic, vp); | 1065 | vic_provinfo_add_tlv(vp, |
| 1092 | if (err) | 1066 | VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR, |
| 1093 | goto err_out; | 1067 | ETH_ALEN, mac); |
| 1068 | |||
| 1069 | if (enic->pp.set & ENIC_SET_INSTANCE) { | ||
| 1070 | uuid = enic->pp.instance_uuid; | ||
| 1071 | sprintf(uuid_str, uuid_fmt, | ||
| 1072 | uuid[0], uuid[1], uuid[2], uuid[3], | ||
| 1073 | uuid[4], uuid[5], uuid[6], uuid[7], | ||
| 1074 | uuid[8], uuid[9], uuid[10], uuid[11], | ||
| 1075 | uuid[12], uuid[13], uuid[14], uuid[15]); | ||
| 1076 | vic_provinfo_add_tlv(vp, | ||
| 1077 | VIC_LINUX_PROV_TLV_CLIENT_UUID_STR, | ||
| 1078 | sizeof(uuid_str), uuid_str); | ||
| 1079 | } | ||
| 1094 | 1080 | ||
| 1095 | enic->pp.request = request; | 1081 | if (enic->pp.set & ENIC_SET_HOST) { |
| 1096 | memcpy(enic->pp.name, name, PORT_PROFILE_MAX); | 1082 | uuid = enic->pp.host_uuid; |
| 1097 | if (instance_uuid) | 1083 | sprintf(uuid_str, uuid_fmt, |
| 1098 | memcpy(enic->pp.instance_uuid, | 1084 | uuid[0], uuid[1], uuid[2], uuid[3], |
| 1099 | instance_uuid, PORT_UUID_MAX); | 1085 | uuid[4], uuid[5], uuid[6], uuid[7], |
| 1100 | if (host_uuid) | 1086 | uuid[8], uuid[9], uuid[10], uuid[11], |
| 1101 | memcpy(enic->pp.host_uuid, | 1087 | uuid[12], uuid[13], uuid[14], uuid[15]); |
| 1102 | host_uuid, PORT_UUID_MAX); | 1088 | vic_provinfo_add_tlv(vp, |
| 1089 | VIC_LINUX_PROV_TLV_HOST_UUID_STR, | ||
| 1090 | sizeof(uuid_str), uuid_str); | ||
| 1091 | } | ||
| 1103 | 1092 | ||
| 1104 | err_out: | 1093 | err = enic_dev_init_prov(enic, vp); |
| 1105 | vic_provinfo_free(vp); | 1094 | vic_provinfo_free(vp); |
| 1095 | if (err) | ||
| 1096 | return err; | ||
| 1097 | break; | ||
| 1106 | 1098 | ||
| 1107 | return err; | 1099 | case PORT_REQUEST_DISASSOCIATE: |
| 1108 | } | 1100 | break; |
| 1109 | 1101 | ||
| 1110 | static int enic_unset_port_profile(struct enic *enic) | 1102 | default: |
| 1111 | { | 1103 | return -EINVAL; |
| 1112 | memset(&enic->pp, 0, sizeof(enic->pp)); | 1104 | } |
| 1113 | return enic_vnic_dev_deinit(enic); | 1105 | |
| 1106 | enic->pp.set |= ENIC_SET_APPLIED; | ||
| 1107 | return 0; | ||
| 1114 | } | 1108 | } |
| 1115 | 1109 | ||
| 1116 | static int enic_set_vf_port(struct net_device *netdev, int vf, | 1110 | static int enic_set_vf_port(struct net_device *netdev, int vf, |
| 1117 | struct nlattr *port[]) | 1111 | struct nlattr *port[]) |
| 1118 | { | 1112 | { |
| 1119 | struct enic *enic = netdev_priv(netdev); | 1113 | struct enic *enic = netdev_priv(netdev); |
| 1120 | char *name = NULL; | 1114 | |
| 1121 | u8 *instance_uuid = NULL; | 1115 | memset(&enic->pp, 0, sizeof(enic->pp)); |
| 1122 | u8 *host_uuid = NULL; | 1116 | |
| 1123 | u8 request = PORT_REQUEST_DISASSOCIATE; | 1117 | if (port[IFLA_PORT_REQUEST]) { |
| 1118 | enic->pp.set |= ENIC_SET_REQUEST; | ||
| 1119 | enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | if (port[IFLA_PORT_PROFILE]) { | ||
| 1123 | enic->pp.set |= ENIC_SET_NAME; | ||
| 1124 | memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), | ||
| 1125 | PORT_PROFILE_MAX); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | if (port[IFLA_PORT_INSTANCE_UUID]) { | ||
| 1129 | enic->pp.set |= ENIC_SET_INSTANCE; | ||
| 1130 | memcpy(enic->pp.instance_uuid, | ||
| 1131 | nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | if (port[IFLA_PORT_HOST_UUID]) { | ||
| 1135 | enic->pp.set |= ENIC_SET_HOST; | ||
| 1136 | memcpy(enic->pp.host_uuid, | ||
| 1137 | nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); | ||
| 1138 | } | ||
| 1124 | 1139 | ||
| 1125 | /* don't support VFs, yet */ | 1140 | /* don't support VFs, yet */ |
| 1126 | if (vf != PORT_SELF_VF) | 1141 | if (vf != PORT_SELF_VF) |
| 1127 | return -EOPNOTSUPP; | 1142 | return -EOPNOTSUPP; |
| 1128 | 1143 | ||
| 1129 | if (port[IFLA_PORT_REQUEST]) | 1144 | if (!(enic->pp.set & ENIC_SET_REQUEST)) |
| 1130 | request = nla_get_u8(port[IFLA_PORT_REQUEST]); | 1145 | return -EOPNOTSUPP; |
| 1131 | 1146 | ||
| 1132 | switch (request) { | 1147 | if (enic->pp.request == PORT_REQUEST_ASSOCIATE) { |
| 1133 | case PORT_REQUEST_ASSOCIATE: | ||
| 1134 | 1148 | ||
| 1135 | /* If the interface mac addr hasn't been assigned, | 1149 | /* If the interface mac addr hasn't been assigned, |
| 1136 | * assign a random mac addr before setting port- | 1150 | * assign a random mac addr before setting port- |
| @@ -1139,30 +1153,9 @@ static int enic_set_vf_port(struct net_device *netdev, int vf, | |||
| 1139 | 1153 | ||
| 1140 | if (is_zero_ether_addr(netdev->dev_addr)) | 1154 | if (is_zero_ether_addr(netdev->dev_addr)) |
| 1141 | random_ether_addr(netdev->dev_addr); | 1155 | random_ether_addr(netdev->dev_addr); |
| 1142 | |||
| 1143 | if (port[IFLA_PORT_PROFILE]) | ||
| 1144 | name = nla_data(port[IFLA_PORT_PROFILE]); | ||
| 1145 | |||
| 1146 | if (port[IFLA_PORT_INSTANCE_UUID]) | ||
| 1147 | instance_uuid = | ||
| 1148 | nla_data(port[IFLA_PORT_INSTANCE_UUID]); | ||
| 1149 | |||
| 1150 | if (port[IFLA_PORT_HOST_UUID]) | ||
| 1151 | host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]); | ||
| 1152 | |||
| 1153 | return enic_set_port_profile(enic, request, | ||
| 1154 | netdev->dev_addr, name, | ||
| 1155 | instance_uuid, host_uuid); | ||
| 1156 | |||
| 1157 | case PORT_REQUEST_DISASSOCIATE: | ||
| 1158 | |||
| 1159 | return enic_unset_port_profile(enic); | ||
| 1160 | |||
| 1161 | default: | ||
| 1162 | break; | ||
| 1163 | } | 1156 | } |
| 1164 | 1157 | ||
| 1165 | return -EOPNOTSUPP; | 1158 | return enic_set_port_profile(enic, netdev->dev_addr); |
| 1166 | } | 1159 | } |
| 1167 | 1160 | ||
| 1168 | static int enic_get_vf_port(struct net_device *netdev, int vf, | 1161 | static int enic_get_vf_port(struct net_device *netdev, int vf, |
| @@ -1172,14 +1165,12 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, | |||
| 1172 | int err, error, done; | 1165 | int err, error, done; |
| 1173 | u16 response = PORT_PROFILE_RESPONSE_SUCCESS; | 1166 | u16 response = PORT_PROFILE_RESPONSE_SUCCESS; |
| 1174 | 1167 | ||
| 1175 | /* don't support VFs, yet */ | 1168 | if (!(enic->pp.set & ENIC_SET_APPLIED)) |
| 1176 | if (vf != PORT_SELF_VF) | 1169 | return -ENODATA; |
| 1177 | return -EOPNOTSUPP; | ||
| 1178 | 1170 | ||
| 1179 | err = enic_dev_init_done(enic, &done, &error); | 1171 | err = enic_dev_init_done(enic, &done, &error); |
| 1180 | |||
| 1181 | if (err) | 1172 | if (err) |
| 1182 | return err; | 1173 | error = err; |
| 1183 | 1174 | ||
| 1184 | switch (error) { | 1175 | switch (error) { |
| 1185 | case ERR_SUCCESS: | 1176 | case ERR_SUCCESS: |
| @@ -1202,12 +1193,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, | |||
| 1202 | 1193 | ||
| 1203 | NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); | 1194 | NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); |
| 1204 | NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); | 1195 | NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); |
| 1205 | NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX, | 1196 | if (enic->pp.set & ENIC_SET_NAME) |
| 1206 | enic->pp.name); | 1197 | NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX, |
| 1207 | NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, | 1198 | enic->pp.name); |
| 1208 | enic->pp.instance_uuid); | 1199 | if (enic->pp.set & ENIC_SET_INSTANCE) |
| 1209 | NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX, | 1200 | NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, |
| 1210 | enic->pp.host_uuid); | 1201 | enic->pp.instance_uuid); |
| 1202 | if (enic->pp.set & ENIC_SET_HOST) | ||
| 1203 | NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX, | ||
| 1204 | enic->pp.host_uuid); | ||
| 1211 | 1205 | ||
| 1212 | return 0; | 1206 | return 0; |
| 1213 | 1207 | ||
