/drivers/net/enic/enic_pp.c
C | 264 lines | 196 code | 47 blank | 21 comment | 23 complexity | 31ba586424746a23fe5785ddfe48d119 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/* 2 * Copyright 2011 Cisco Systems, Inc. All rights reserved. 3 * 4 * This program is free software; you may redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; version 2 of the License. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15 * SOFTWARE. 16 * 17 */ 18 19#include <linux/kernel.h> 20#include <linux/string.h> 21#include <linux/errno.h> 22#include <linux/types.h> 23#include <linux/netdevice.h> 24#include <linux/etherdevice.h> 25#include <linux/rtnetlink.h> 26#include <net/ip.h> 27 28#include "vnic_vic.h" 29#include "enic_res.h" 30#include "enic.h" 31#include "enic_dev.h" 32 33static int enic_set_port_profile(struct enic *enic) 34{ 35 struct net_device *netdev = enic->netdev; 36 struct vic_provinfo *vp; 37 const u8 oui[3] = VIC_PROVINFO_CISCO_OUI; 38 const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX); 39 char uuid_str[38]; 40 char client_mac_str[18]; 41 u8 *client_mac; 42 int err; 43 44 if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) 45 return -EINVAL; 46 47 vp = vic_provinfo_alloc(GFP_KERNEL, oui, 48 VIC_PROVINFO_GENERIC_TYPE); 49 if (!vp) 50 return -ENOMEM; 51 52 VIC_PROVINFO_ADD_TLV(vp, 53 VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, 54 strlen(enic->pp.name) + 1, enic->pp.name); 55 56 if (!is_zero_ether_addr(enic->pp.mac_addr)) 57 client_mac = enic->pp.mac_addr; 58 else 59 client_mac = netdev->dev_addr; 60 61 VIC_PROVINFO_ADD_TLV(vp, 62 VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, 63 ETH_ALEN, client_mac); 64 65 snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac); 66 VIC_PROVINFO_ADD_TLV(vp, 67 VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, 68 sizeof(client_mac_str), client_mac_str); 69 70 if (enic->pp.set & ENIC_SET_INSTANCE) { 71 sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); 72 VIC_PROVINFO_ADD_TLV(vp, 73 VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, 74 sizeof(uuid_str), uuid_str); 75 } 76 77 if (enic->pp.set & ENIC_SET_HOST) { 78 sprintf(uuid_str, "%pUB", enic->pp.host_uuid); 79 VIC_PROVINFO_ADD_TLV(vp, 80 VIC_GENERIC_PROV_TLV_HOST_UUID_STR, 81 sizeof(uuid_str), uuid_str); 82 } 83 84 VIC_PROVINFO_ADD_TLV(vp, 85 VIC_GENERIC_PROV_TLV_OS_TYPE, 86 sizeof(os_type), &os_type); 87 88 err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp)); 89 90add_tlv_failure: 91 vic_provinfo_free(vp); 92 93 return err; 94} 95 96static int enic_unset_port_profile(struct enic *enic) 97{ 98 int err; 99 100 err = enic_vnic_dev_deinit(enic); 101 if (err) 102 return enic_dev_status_to_errno(err); 103 104 enic_reset_addr_lists(enic); 105 106 return 0; 107} 108 109static int enic_are_pp_different(struct enic_port_profile *pp1, 110 struct enic_port_profile *pp2) 111{ 112 return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid, 113 pp2->instance_uuid, PORT_UUID_MAX) | 114 !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) | 115 !!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN); 116} 117 118static int enic_pp_preassociate(struct enic *enic, 119 struct enic_port_profile *prev_pp, int *restore_pp); 120static int enic_pp_disassociate(struct enic *enic, 121 struct enic_port_profile *prev_pp, int *restore_pp); 122static int enic_pp_preassociate_rr(struct enic *enic, 123 struct enic_port_profile *prev_pp, int *restore_pp); 124static int enic_pp_associate(struct enic *enic, 125 struct enic_port_profile *prev_pp, int *restore_pp); 126 127static int (*enic_pp_handlers[])(struct enic *enic, 128 struct enic_port_profile *prev_state, int *restore_pp) = { 129 [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate, 130 [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr, 131 [PORT_REQUEST_ASSOCIATE] = enic_pp_associate, 132 [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate, 133}; 134 135static const int enic_pp_handlers_count = 136 sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers); 137 138static int enic_pp_preassociate(struct enic *enic, 139 struct enic_port_profile *prev_pp, int *restore_pp) 140{ 141 return -EOPNOTSUPP; 142} 143 144static int enic_pp_disassociate(struct enic *enic, 145 struct enic_port_profile *prev_pp, int *restore_pp) 146{ 147 return enic_unset_port_profile(enic); 148} 149 150static int enic_pp_preassociate_rr(struct enic *enic, 151 struct enic_port_profile *prev_pp, int *restore_pp) 152{ 153 int err; 154 int active = 0; 155 156 if (enic->pp.request != PORT_REQUEST_ASSOCIATE) { 157 /* If pre-associate is not part of an associate. 158 We always disassociate first */ 159 err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, 160 prev_pp, restore_pp); 161 if (err) 162 return err; 163 164 *restore_pp = 0; 165 } 166 167 *restore_pp = 0; 168 169 err = enic_set_port_profile(enic); 170 if (err) 171 return err; 172 173 /* If pre-associate is not part of an associate. */ 174 if (enic->pp.request != PORT_REQUEST_ASSOCIATE) 175 err = enic_dev_status_to_errno(enic_dev_enable2(enic, active)); 176 177 return err; 178} 179 180static int enic_pp_associate(struct enic *enic, 181 struct enic_port_profile *prev_pp, int *restore_pp) 182{ 183 int err; 184 int active = 1; 185 186 /* Check if a pre-associate was called before */ 187 if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR || 188 (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR && 189 enic_are_pp_different(prev_pp, &enic->pp))) { 190 err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE]( 191 enic, prev_pp, restore_pp); 192 if (err) 193 return err; 194 195 *restore_pp = 0; 196 } 197 198 err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR]( 199 enic, prev_pp, restore_pp); 200 if (err) 201 return err; 202 203 *restore_pp = 0; 204 205 return enic_dev_status_to_errno(enic_dev_enable2(enic, active)); 206} 207 208int enic_process_set_pp_request(struct enic *enic, 209 struct enic_port_profile *prev_pp, int *restore_pp) 210{ 211 if (enic->pp.request < enic_pp_handlers_count 212 && enic_pp_handlers[enic->pp.request]) 213 return enic_pp_handlers[enic->pp.request](enic, 214 prev_pp, restore_pp); 215 else 216 return -EOPNOTSUPP; 217} 218 219int enic_process_get_pp_request(struct enic *enic, int request, 220 u16 *response) 221{ 222 int err, status = ERR_SUCCESS; 223 224 switch (request) { 225 226 case PORT_REQUEST_PREASSOCIATE_RR: 227 case PORT_REQUEST_ASSOCIATE: 228 err = enic_dev_enable2_done(enic, &status); 229 break; 230 231 case PORT_REQUEST_DISASSOCIATE: 232 err = enic_dev_deinit_done(enic, &status); 233 break; 234 235 default: 236 return -EINVAL; 237 } 238 239 if (err) 240 status = err; 241 242 switch (status) { 243 case ERR_SUCCESS: 244 *response = PORT_PROFILE_RESPONSE_SUCCESS; 245 break; 246 case ERR_EINVAL: 247 *response = PORT_PROFILE_RESPONSE_INVALID; 248 break; 249 case ERR_EBADSTATE: 250 *response = PORT_PROFILE_RESPONSE_BADSTATE; 251 break; 252 case ERR_ENOMEM: 253 *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; 254 break; 255 case ERR_EINPROGRESS: 256 *response = PORT_PROFILE_RESPONSE_INPROGRESS; 257 break; 258 default: 259 *response = PORT_PROFILE_RESPONSE_ERROR; 260 break; 261 } 262 263 return 0; 264}