Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright 2011 Cisco Systems, Inc.  All rights reserved.
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  * Checks validity of vf index that came in
0021  * port profile request
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     /* Deregister mac addresses */
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         /* If pre-associate is not part of an associate.
0215         We always disassociate first */
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     /* If pre-associate is not part of an associate. */
0231     if (pp->request != PORT_REQUEST_ASSOCIATE) {
0232         /* Enable device as standby */
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     /* Check if a pre-associate was called before */
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     /* Enable device as active */
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     /* Register mac address */
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 }