enic_pp.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. #include <linux/kernel.h>
  19. #include <linux/string.h>
  20. #include <linux/errno.h>
  21. #include <linux/types.h>
  22. #include <linux/netdevice.h>
  23. #include <linux/etherdevice.h>
  24. #include <linux/rtnetlink.h>
  25. #include <net/ip.h>
  26. #include "vnic_vic.h"
  27. #include "enic_res.h"
  28. #include "enic.h"
  29. #include "enic_dev.h"
  30. #include "enic_pp.h"
  31. /*
  32. * Checks validity of vf index that came in
  33. * port profile request
  34. */
  35. int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
  36. {
  37. if (vf != PORT_SELF_VF) {
  38. #ifdef CONFIG_PCI_IOV
  39. if (enic_sriov_enabled(enic)) {
  40. if (vf < 0 || vf >= enic->num_vfs) {
  41. *err = -EINVAL;
  42. goto err_out;
  43. }
  44. } else {
  45. *err = -EOPNOTSUPP;
  46. goto err_out;
  47. }
  48. #else
  49. *err = -EOPNOTSUPP;
  50. goto err_out;
  51. #endif
  52. }
  53. if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
  54. *err = -EOPNOTSUPP;
  55. goto err_out;
  56. }
  57. *err = 0;
  58. return 1;
  59. err_out:
  60. return 0;
  61. }
  62. static int enic_set_port_profile(struct enic *enic, int vf)
  63. {
  64. struct net_device *netdev = enic->netdev;
  65. struct enic_port_profile *pp;
  66. struct vic_provinfo *vp;
  67. const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
  68. const __be16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
  69. char uuid_str[38];
  70. char client_mac_str[18];
  71. u8 *client_mac;
  72. int err;
  73. ENIC_PP_BY_INDEX(enic, vf, pp, &err);
  74. if (err)
  75. return err;
  76. if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
  77. return -EINVAL;
  78. vp = vic_provinfo_alloc(GFP_KERNEL, oui,
  79. VIC_PROVINFO_GENERIC_TYPE);
  80. if (!vp)
  81. return -ENOMEM;
  82. VIC_PROVINFO_ADD_TLV(vp,
  83. VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
  84. strlen(pp->name) + 1, pp->name);
  85. if (!is_zero_ether_addr(pp->mac_addr)) {
  86. client_mac = pp->mac_addr;
  87. } else if (vf == PORT_SELF_VF) {
  88. client_mac = netdev->dev_addr;
  89. } else {
  90. netdev_err(netdev, "Cannot find pp mac address "
  91. "for VF %d\n", vf);
  92. err = -EINVAL;
  93. goto add_tlv_failure;
  94. }
  95. VIC_PROVINFO_ADD_TLV(vp,
  96. VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
  97. ETH_ALEN, client_mac);
  98. snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac);
  99. VIC_PROVINFO_ADD_TLV(vp,
  100. VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
  101. sizeof(client_mac_str), client_mac_str);
  102. if (pp->set & ENIC_SET_INSTANCE) {
  103. sprintf(uuid_str, "%pUB", pp->instance_uuid);
  104. VIC_PROVINFO_ADD_TLV(vp,
  105. VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
  106. sizeof(uuid_str), uuid_str);
  107. }
  108. if (pp->set & ENIC_SET_HOST) {
  109. sprintf(uuid_str, "%pUB", pp->host_uuid);
  110. VIC_PROVINFO_ADD_TLV(vp,
  111. VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
  112. sizeof(uuid_str), uuid_str);
  113. }
  114. VIC_PROVINFO_ADD_TLV(vp,
  115. VIC_GENERIC_PROV_TLV_OS_TYPE,
  116. sizeof(os_type), &os_type);
  117. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
  118. vic_provinfo_size(vp));
  119. err = enic_dev_status_to_errno(err);
  120. add_tlv_failure:
  121. vic_provinfo_free(vp);
  122. return err;
  123. }
  124. static int enic_unset_port_profile(struct enic *enic, int vf)
  125. {
  126. int err;
  127. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
  128. if (err)
  129. return enic_dev_status_to_errno(err);
  130. if (vf == PORT_SELF_VF)
  131. enic_reset_addr_lists(enic);
  132. return 0;
  133. }
  134. static int enic_are_pp_different(struct enic_port_profile *pp1,
  135. struct enic_port_profile *pp2)
  136. {
  137. return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid,
  138. pp2->instance_uuid, PORT_UUID_MAX) |
  139. !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) |
  140. !ether_addr_equal(pp1->mac_addr, pp2->mac_addr);
  141. }
  142. static int enic_pp_preassociate(struct enic *enic, int vf,
  143. struct enic_port_profile *prev_pp, int *restore_pp);
  144. static int enic_pp_disassociate(struct enic *enic, int vf,
  145. struct enic_port_profile *prev_pp, int *restore_pp);
  146. static int enic_pp_preassociate_rr(struct enic *enic, int vf,
  147. struct enic_port_profile *prev_pp, int *restore_pp);
  148. static int enic_pp_associate(struct enic *enic, int vf,
  149. struct enic_port_profile *prev_pp, int *restore_pp);
  150. static int (*enic_pp_handlers[])(struct enic *enic, int vf,
  151. struct enic_port_profile *prev_state,
  152. int *restore_pp) = {
  153. [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate,
  154. [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr,
  155. [PORT_REQUEST_ASSOCIATE] = enic_pp_associate,
  156. [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate,
  157. };
  158. static const int enic_pp_handlers_count =
  159. ARRAY_SIZE(enic_pp_handlers);
  160. static int enic_pp_preassociate(struct enic *enic, int vf,
  161. struct enic_port_profile *prev_pp, int *restore_pp)
  162. {
  163. return -EOPNOTSUPP;
  164. }
  165. static int enic_pp_disassociate(struct enic *enic, int vf,
  166. struct enic_port_profile *prev_pp, int *restore_pp)
  167. {
  168. struct net_device *netdev = enic->netdev;
  169. struct enic_port_profile *pp;
  170. int err;
  171. ENIC_PP_BY_INDEX(enic, vf, pp, &err);
  172. if (err)
  173. return err;
  174. /* Deregister mac addresses */
  175. if (!is_zero_ether_addr(pp->mac_addr))
  176. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
  177. pp->mac_addr);
  178. else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
  179. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
  180. netdev->dev_addr);
  181. return enic_unset_port_profile(enic, vf);
  182. }
  183. static int enic_pp_preassociate_rr(struct enic *enic, int vf,
  184. struct enic_port_profile *prev_pp, int *restore_pp)
  185. {
  186. struct enic_port_profile *pp;
  187. int err;
  188. int active = 0;
  189. ENIC_PP_BY_INDEX(enic, vf, pp, &err);
  190. if (err)
  191. return err;
  192. if (pp->request != PORT_REQUEST_ASSOCIATE) {
  193. /* If pre-associate is not part of an associate.
  194. We always disassociate first */
  195. err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
  196. prev_pp, restore_pp);
  197. if (err)
  198. return err;
  199. *restore_pp = 0;
  200. }
  201. *restore_pp = 0;
  202. err = enic_set_port_profile(enic, vf);
  203. if (err)
  204. return err;
  205. /* If pre-associate is not part of an associate. */
  206. if (pp->request != PORT_REQUEST_ASSOCIATE) {
  207. /* Enable device as standby */
  208. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
  209. active);
  210. err = enic_dev_status_to_errno(err);
  211. }
  212. return err;
  213. }
  214. static int enic_pp_associate(struct enic *enic, int vf,
  215. struct enic_port_profile *prev_pp, int *restore_pp)
  216. {
  217. struct net_device *netdev = enic->netdev;
  218. struct enic_port_profile *pp;
  219. int err;
  220. int active = 1;
  221. ENIC_PP_BY_INDEX(enic, vf, pp, &err);
  222. if (err)
  223. return err;
  224. /* Check if a pre-associate was called before */
  225. if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
  226. (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
  227. enic_are_pp_different(prev_pp, pp))) {
  228. err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
  229. enic, vf, prev_pp, restore_pp);
  230. if (err)
  231. return err;
  232. *restore_pp = 0;
  233. }
  234. err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
  235. enic, vf, prev_pp, restore_pp);
  236. if (err)
  237. return err;
  238. *restore_pp = 0;
  239. /* Enable device as active */
  240. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
  241. err = enic_dev_status_to_errno(err);
  242. if (err)
  243. return err;
  244. /* Register mac address */
  245. if (!is_zero_ether_addr(pp->mac_addr))
  246. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
  247. pp->mac_addr);
  248. else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
  249. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
  250. netdev->dev_addr);
  251. return 0;
  252. }
  253. int enic_process_set_pp_request(struct enic *enic, int vf,
  254. struct enic_port_profile *prev_pp, int *restore_pp)
  255. {
  256. struct enic_port_profile *pp;
  257. int err;
  258. ENIC_PP_BY_INDEX(enic, vf, pp, &err);
  259. if (err)
  260. return err;
  261. if (pp->request >= enic_pp_handlers_count
  262. || !enic_pp_handlers[pp->request])
  263. return -EOPNOTSUPP;
  264. return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
  265. }
  266. int enic_process_get_pp_request(struct enic *enic, int vf,
  267. int request, u16 *response)
  268. {
  269. int err, status = ERR_SUCCESS;
  270. switch (request) {
  271. case PORT_REQUEST_PREASSOCIATE_RR:
  272. case PORT_REQUEST_ASSOCIATE:
  273. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
  274. vnic_dev_enable2_done, &status);
  275. break;
  276. case PORT_REQUEST_DISASSOCIATE:
  277. ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
  278. vnic_dev_deinit_done, &status);
  279. break;
  280. default:
  281. return -EINVAL;
  282. }
  283. if (err)
  284. status = err;
  285. switch (status) {
  286. case ERR_SUCCESS:
  287. *response = PORT_PROFILE_RESPONSE_SUCCESS;
  288. break;
  289. case ERR_EINVAL:
  290. *response = PORT_PROFILE_RESPONSE_INVALID;
  291. break;
  292. case ERR_EBADSTATE:
  293. *response = PORT_PROFILE_RESPONSE_BADSTATE;
  294. break;
  295. case ERR_ENOMEM:
  296. *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
  297. break;
  298. case ERR_EINPROGRESS:
  299. *response = PORT_PROFILE_RESPONSE_INPROGRESS;
  300. break;
  301. default:
  302. *response = PORT_PROFILE_RESPONSE_ERROR;
  303. break;
  304. }
  305. return 0;
  306. }