0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/string.h>
0006 #include <linux/errno.h>
0007 #include <linux/types.h>
0008 #include <linux/netdevice.h>
0009 #include <linux/etherdevice.h>
0010 #include <linux/rtnetlink.h>
0011 #include <net/ip.h>
0012
0013 #include "vnic_vic.h"
0014 #include "enic_res.h"
0015 #include "enic.h"
0016 #include "enic_dev.h"
0017 #include "enic_pp.h"
0018
0019
0020
0021
0022
0023 int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
0024 {
0025 if (vf != PORT_SELF_VF) {
0026 #ifdef CONFIG_PCI_IOV
0027 if (enic_sriov_enabled(enic)) {
0028 if (vf < 0 || vf >= enic->num_vfs) {
0029 *err = -EINVAL;
0030 goto err_out;
0031 }
0032 } else {
0033 *err = -EOPNOTSUPP;
0034 goto err_out;
0035 }
0036 #else
0037 *err = -EOPNOTSUPP;
0038 goto err_out;
0039 #endif
0040 }
0041
0042 if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
0043 *err = -EOPNOTSUPP;
0044 goto err_out;
0045 }
0046
0047 *err = 0;
0048 return 1;
0049
0050 err_out:
0051 return 0;
0052 }
0053
0054 static int enic_set_port_profile(struct enic *enic, int vf)
0055 {
0056 struct net_device *netdev = enic->netdev;
0057 struct enic_port_profile *pp;
0058 struct vic_provinfo *vp;
0059 const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
0060 const __be16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
0061 const u8 *client_mac;
0062 char uuid_str[38];
0063 char client_mac_str[18];
0064 int err;
0065
0066 ENIC_PP_BY_INDEX(enic, vf, pp, &err);
0067 if (err)
0068 return err;
0069
0070 if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
0071 return -EINVAL;
0072
0073 vp = vic_provinfo_alloc(GFP_KERNEL, oui,
0074 VIC_PROVINFO_GENERIC_TYPE);
0075 if (!vp)
0076 return -ENOMEM;
0077
0078 VIC_PROVINFO_ADD_TLV(vp,
0079 VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
0080 strlen(pp->name) + 1, pp->name);
0081
0082 if (!is_zero_ether_addr(pp->mac_addr)) {
0083 client_mac = pp->mac_addr;
0084 } else if (vf == PORT_SELF_VF) {
0085 client_mac = netdev->dev_addr;
0086 } else {
0087 netdev_err(netdev, "Cannot find pp mac address "
0088 "for VF %d\n", vf);
0089 err = -EINVAL;
0090 goto add_tlv_failure;
0091 }
0092
0093 VIC_PROVINFO_ADD_TLV(vp,
0094 VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
0095 ETH_ALEN, client_mac);
0096
0097 snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac);
0098 VIC_PROVINFO_ADD_TLV(vp,
0099 VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
0100 sizeof(client_mac_str), client_mac_str);
0101
0102 if (pp->set & ENIC_SET_INSTANCE) {
0103 sprintf(uuid_str, "%pUB", pp->instance_uuid);
0104 VIC_PROVINFO_ADD_TLV(vp,
0105 VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
0106 sizeof(uuid_str), uuid_str);
0107 }
0108
0109 if (pp->set & ENIC_SET_HOST) {
0110 sprintf(uuid_str, "%pUB", pp->host_uuid);
0111 VIC_PROVINFO_ADD_TLV(vp,
0112 VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
0113 sizeof(uuid_str), uuid_str);
0114 }
0115
0116 VIC_PROVINFO_ADD_TLV(vp,
0117 VIC_GENERIC_PROV_TLV_OS_TYPE,
0118 sizeof(os_type), &os_type);
0119
0120 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
0121 vic_provinfo_size(vp));
0122 err = enic_dev_status_to_errno(err);
0123
0124 add_tlv_failure:
0125 vic_provinfo_free(vp);
0126
0127 return err;
0128 }
0129
0130 static int enic_unset_port_profile(struct enic *enic, int vf)
0131 {
0132 int err;
0133
0134 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
0135 if (err)
0136 return enic_dev_status_to_errno(err);
0137
0138 if (vf == PORT_SELF_VF)
0139 enic_reset_addr_lists(enic);
0140
0141 return 0;
0142 }
0143
0144 static int enic_are_pp_different(struct enic_port_profile *pp1,
0145 struct enic_port_profile *pp2)
0146 {
0147 return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid,
0148 pp2->instance_uuid, PORT_UUID_MAX) |
0149 !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) |
0150 !ether_addr_equal(pp1->mac_addr, pp2->mac_addr);
0151 }
0152
0153 static int enic_pp_preassociate(struct enic *enic, int vf,
0154 struct enic_port_profile *prev_pp, int *restore_pp);
0155 static int enic_pp_disassociate(struct enic *enic, int vf,
0156 struct enic_port_profile *prev_pp, int *restore_pp);
0157 static int enic_pp_preassociate_rr(struct enic *enic, int vf,
0158 struct enic_port_profile *prev_pp, int *restore_pp);
0159 static int enic_pp_associate(struct enic *enic, int vf,
0160 struct enic_port_profile *prev_pp, int *restore_pp);
0161
0162 static int (*enic_pp_handlers[])(struct enic *enic, int vf,
0163 struct enic_port_profile *prev_state,
0164 int *restore_pp) = {
0165 [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate,
0166 [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr,
0167 [PORT_REQUEST_ASSOCIATE] = enic_pp_associate,
0168 [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate,
0169 };
0170
0171 static const int enic_pp_handlers_count =
0172 ARRAY_SIZE(enic_pp_handlers);
0173
0174 static int enic_pp_preassociate(struct enic *enic, int vf,
0175 struct enic_port_profile *prev_pp, int *restore_pp)
0176 {
0177 return -EOPNOTSUPP;
0178 }
0179
0180 static int enic_pp_disassociate(struct enic *enic, int vf,
0181 struct enic_port_profile *prev_pp, int *restore_pp)
0182 {
0183 struct net_device *netdev = enic->netdev;
0184 struct enic_port_profile *pp;
0185 int err;
0186
0187 ENIC_PP_BY_INDEX(enic, vf, pp, &err);
0188 if (err)
0189 return err;
0190
0191
0192 if (!is_zero_ether_addr(pp->mac_addr))
0193 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
0194 pp->mac_addr);
0195 else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
0196 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
0197 netdev->dev_addr);
0198
0199 return enic_unset_port_profile(enic, vf);
0200 }
0201
0202 static int enic_pp_preassociate_rr(struct enic *enic, int vf,
0203 struct enic_port_profile *prev_pp, int *restore_pp)
0204 {
0205 struct enic_port_profile *pp;
0206 int err;
0207 int active = 0;
0208
0209 ENIC_PP_BY_INDEX(enic, vf, pp, &err);
0210 if (err)
0211 return err;
0212
0213 if (pp->request != PORT_REQUEST_ASSOCIATE) {
0214
0215
0216 err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
0217 prev_pp, restore_pp);
0218 if (err)
0219 return err;
0220
0221 *restore_pp = 0;
0222 }
0223
0224 *restore_pp = 0;
0225
0226 err = enic_set_port_profile(enic, vf);
0227 if (err)
0228 return err;
0229
0230
0231 if (pp->request != PORT_REQUEST_ASSOCIATE) {
0232
0233 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
0234 active);
0235 err = enic_dev_status_to_errno(err);
0236 }
0237
0238 return err;
0239 }
0240
0241 static int enic_pp_associate(struct enic *enic, int vf,
0242 struct enic_port_profile *prev_pp, int *restore_pp)
0243 {
0244 struct net_device *netdev = enic->netdev;
0245 struct enic_port_profile *pp;
0246 int err;
0247 int active = 1;
0248
0249 ENIC_PP_BY_INDEX(enic, vf, pp, &err);
0250 if (err)
0251 return err;
0252
0253
0254 if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
0255 (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
0256 enic_are_pp_different(prev_pp, pp))) {
0257 err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
0258 enic, vf, prev_pp, restore_pp);
0259 if (err)
0260 return err;
0261
0262 *restore_pp = 0;
0263 }
0264
0265 err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
0266 enic, vf, prev_pp, restore_pp);
0267 if (err)
0268 return err;
0269
0270 *restore_pp = 0;
0271
0272
0273 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
0274 err = enic_dev_status_to_errno(err);
0275 if (err)
0276 return err;
0277
0278
0279 if (!is_zero_ether_addr(pp->mac_addr))
0280 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
0281 pp->mac_addr);
0282 else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
0283 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
0284 netdev->dev_addr);
0285
0286 return 0;
0287 }
0288
0289 int enic_process_set_pp_request(struct enic *enic, int vf,
0290 struct enic_port_profile *prev_pp, int *restore_pp)
0291 {
0292 struct enic_port_profile *pp;
0293 int err;
0294
0295 ENIC_PP_BY_INDEX(enic, vf, pp, &err);
0296 if (err)
0297 return err;
0298
0299 if (pp->request >= enic_pp_handlers_count
0300 || !enic_pp_handlers[pp->request])
0301 return -EOPNOTSUPP;
0302
0303 return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
0304 }
0305
0306 int enic_process_get_pp_request(struct enic *enic, int vf,
0307 int request, u16 *response)
0308 {
0309 int err, status = ERR_SUCCESS;
0310
0311 switch (request) {
0312
0313 case PORT_REQUEST_PREASSOCIATE_RR:
0314 case PORT_REQUEST_ASSOCIATE:
0315 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
0316 vnic_dev_enable2_done, &status);
0317 break;
0318
0319 case PORT_REQUEST_DISASSOCIATE:
0320 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
0321 vnic_dev_deinit_done, &status);
0322 break;
0323
0324 default:
0325 return -EINVAL;
0326 }
0327
0328 if (err)
0329 status = err;
0330
0331 switch (status) {
0332 case ERR_SUCCESS:
0333 *response = PORT_PROFILE_RESPONSE_SUCCESS;
0334 break;
0335 case ERR_EINVAL:
0336 *response = PORT_PROFILE_RESPONSE_INVALID;
0337 break;
0338 case ERR_EBADSTATE:
0339 *response = PORT_PROFILE_RESPONSE_BADSTATE;
0340 break;
0341 case ERR_ENOMEM:
0342 *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
0343 break;
0344 case ERR_EINPROGRESS:
0345 *response = PORT_PROFILE_RESPONSE_INPROGRESS;
0346 break;
0347 default:
0348 *response = PORT_PROFILE_RESPONSE_ERROR;
0349 break;
0350 }
0351
0352 return 0;
0353 }