PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/open-iscsi-2.0-872-rc4-bnx2i/brcm_iscsi_uio/src/unix/nic_nl.c

#
C | 498 lines | 369 code | 78 blank | 51 comment | 75 complexity | 32f3bf7778fe29b028f3bdf02e8fd6a8 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, GPL-3.0
  1. /* nic_nl.c: NIC uIP NetLink user space stack
  2. *
  3. * Copyright (c) 2004-2010 Broadcom Corporation
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation.
  8. *
  9. * Written by: Benjamin Li (benli@broadcom.com)
  10. */
  11. #include <errno.h>
  12. #include <pthread.h>
  13. #include <signal.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <arpa/inet.h>
  19. #include <linux/limits.h>
  20. #include <netinet/if_ether.h>
  21. #include <netinet/in.h>
  22. #include <linux/netlink.h>
  23. #include <iscsi_if.h>
  24. #include <sys/ioctl.h>
  25. #include <sys/poll.h>
  26. #include <sys/types.h>
  27. #include <sys/user.h>
  28. #include <sys/socket.h>
  29. #include "uip_arp.h"
  30. #include "logger.h"
  31. #include "options.h"
  32. #include "uevent.h"
  33. #include "nic.h"
  34. #include "nic_nl.h"
  35. #include "nic_utils.h"
  36. /*******************************************************************************
  37. * Constants
  38. ******************************************************************************/
  39. #define PFX "NIC_NL "
  40. static void *nlm_recvbuf = NULL;
  41. static void *nlm_sendbuf = NULL;
  42. static struct sockaddr_nl src_addr;
  43. const static struct sockaddr_nl dest_addr = {
  44. .nl_family = AF_NETLINK,
  45. .nl_pid = 0, /* kernel */
  46. .nl_groups = 0, /* unicast */
  47. };
  48. #define POLL_NL 0
  49. #define POLL_MAX 1
  50. /* Netlink */
  51. int nl_sock = INVALID_FD;
  52. static int
  53. nl_read(int ctrl_fd, char *data, int size, int flags)
  54. {
  55. int rc;
  56. struct iovec iov;
  57. struct msghdr msg;
  58. iov.iov_base = data;
  59. iov.iov_len = size;
  60. memset(&src_addr, 0, sizeof(src_addr));
  61. src_addr.nl_family = AF_NETLINK;
  62. src_addr.nl_pid = getpid();
  63. src_addr.nl_groups = 1;
  64. memset(&msg, 0, sizeof(msg));
  65. msg.msg_name= (void*)&src_addr;
  66. msg.msg_namelen = sizeof(src_addr);
  67. msg.msg_iov = &iov;
  68. msg.msg_iovlen = 1;
  69. rc = recvmsg(ctrl_fd, &msg, flags);
  70. return rc;
  71. }
  72. static int
  73. nlpayload_read(int ctrl_fd, char *data, int count, int flags)
  74. {
  75. int rc;
  76. struct iovec iov;
  77. struct msghdr msg;
  78. iov.iov_base = nlm_recvbuf;
  79. iov.iov_len = NLMSG_SPACE(count);
  80. memset(iov.iov_base, 0, iov.iov_len);
  81. memset(&src_addr, 0, sizeof(src_addr));
  82. src_addr.nl_family = AF_NETLINK;
  83. src_addr.nl_pid = getpid();
  84. src_addr.nl_groups = 1;
  85. memset(&msg, 0, sizeof(msg));
  86. msg.msg_name= (void*)&src_addr;
  87. msg.msg_namelen = sizeof(src_addr);
  88. msg.msg_iov = &iov;
  89. msg.msg_iovlen = 1;
  90. rc = recvmsg(ctrl_fd, &msg, flags);
  91. memcpy(data, NLMSG_DATA(iov.iov_base), count);
  92. return rc;
  93. }
  94. static int
  95. kwritev(int fd, enum iscsi_uevent_e type, struct iovec *iovp, int count)
  96. {
  97. int i, rc;
  98. struct nlmsghdr *nlh;
  99. struct msghdr msg;
  100. struct iovec iov;
  101. int datalen = 0;
  102. for (i = 0; i < count; i++) {
  103. datalen += iovp[i].iov_len;
  104. }
  105. nlh = nlm_sendbuf;
  106. memset(nlh, 0, NLMSG_SPACE(datalen));
  107. nlh->nlmsg_len = NLMSG_SPACE(datalen);
  108. nlh->nlmsg_pid = getpid();
  109. nlh->nlmsg_flags = 0;
  110. nlh->nlmsg_type = type;
  111. datalen = 0;
  112. for (i = 0; i < count; i++) {
  113. memcpy(NLMSG_DATA(nlh) + datalen, iovp[i].iov_base,
  114. iovp[i].iov_len);
  115. datalen += iovp[i].iov_len;
  116. }
  117. iov.iov_base = (void*)nlh;
  118. iov.iov_len = nlh->nlmsg_len;
  119. memset(&msg, 0, sizeof(msg));
  120. msg.msg_name= (void*)&dest_addr;
  121. msg.msg_namelen = sizeof(dest_addr);
  122. msg.msg_iov = &iov;
  123. msg.msg_iovlen = 1;
  124. do {
  125. rc = sendmsg(fd, &msg, 0);
  126. if (rc == -ENOMEM) {
  127. LOG_ERR(PFX "sendmsg: alloc_skb() failed");
  128. sleep(1);
  129. } else if (rc < 0) {
  130. LOG_ERR(PFX "sendmsg: bug?: on %d %s[0x%x]",
  131. fd, strerror(errno), errno);
  132. sleep(1);
  133. }
  134. } while ((rc < 0) && (event_loop_stop == 0));
  135. return rc;
  136. }
  137. /*
  138. * __kipc_call() should never block. Therefore
  139. * Netlink's xmit logic is serialized. This means we do not allocate on
  140. * xmit path. Instead we reuse nlm_sendbuf buffer.
  141. *
  142. * Transport must assure non-blocking operations for:
  143. *
  144. * - session_create()
  145. * - conn_create()
  146. * - conn_bind()
  147. * _ set_param()
  148. * - conn_start()
  149. * - conn_stop()
  150. *
  151. * Its OK to block for cleanup for short period of time in operatations for:
  152. *
  153. * - conn_destroy()
  154. * - session_destroy()
  155. *
  156. * FIXME: interface needs to be extended to allow longer blocking on
  157. * cleanup. (Dima)
  158. */
  159. int
  160. __kipc_call(int fd, void *iov_base, int iov_len)
  161. {
  162. int rc;
  163. struct iovec iov;
  164. struct iscsi_uevent *ev = iov_base;
  165. enum iscsi_uevent_e type = ev->type;
  166. int wait_response;
  167. /* Sanity check */
  168. if(iov_base == NULL)
  169. return -EINVAL;
  170. iov.iov_base = iov_base;
  171. iov.iov_len = iov_len;
  172. rc = kwritev(fd, type, &iov, 1);
  173. wait_response = 0;
  174. do {
  175. rc = nlpayload_read(fd, (void*)ev, sizeof(*ev), MSG_PEEK);
  176. if (rc < 0) {
  177. LOG_ERR(PFX "Error reading resp to reply: %s[%d]",
  178. strerror(rc), rc);
  179. return rc;
  180. }
  181. if (ev->type != type) {
  182. LOG_DEBUG(PFX "expecting event %d, got %d, handling...",
  183. type, ev->type);
  184. if (ev->type == ISCSI_KEVENT_IF_ERROR) {
  185. if ((rc = nlpayload_read(fd, (void*)ev,
  186. sizeof(*ev), 0)) < 0) {
  187. return rc;
  188. }
  189. if (ev->iferror == -ENOSYS) {
  190. /* not fatal so let caller handle log */
  191. LOG_DEBUG(PFX "Recieved iferror %d: %s",
  192. ev->iferror,
  193. strerror(ev->iferror));
  194. } else if (ev->iferror < 0) {
  195. LOG_ERR("Received iferror %d: %s",
  196. ev->iferror,
  197. strerror(ev->iferror));
  198. } else {
  199. LOG_ERR("Received iferror %d",
  200. ev->iferror);
  201. }
  202. return ev->iferror;
  203. }
  204. } else if (ev->type == ISCSI_UEVENT_GET_STATS) {
  205. /* kget_stats() will read */
  206. return 0;
  207. } else {
  208. if ((rc = nlpayload_read(fd, (void*)ev,
  209. sizeof(*ev), 0)) < 0) {
  210. return rc;
  211. }
  212. break;
  213. }
  214. wait_response++;
  215. } while ((ev->type != type) &&
  216. (event_loop_stop == 0) &&
  217. (wait_response < MAX_COUNT_NIC_NL_RESP));
  218. return rc;
  219. }
  220. static int ctldev_handle()
  221. {
  222. nic_t *nic = NULL;
  223. int rc;
  224. size_t ev_size;
  225. struct iscsi_uevent *ev;
  226. char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
  227. struct nlmsghdr *nlh;
  228. char *data;
  229. uint8_t *payload;
  230. struct iscsi_path *path;
  231. char *msg_type_str;
  232. uint32_t host_no;
  233. int i;
  234. /* Take a quick peek at what how much uIP will need to read */
  235. if ((rc = nl_read(nl_sock, nlm_ev,
  236. NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) {
  237. LOG_ERR("can not read nlm_ev, error %d", rc);
  238. return rc;
  239. }
  240. nlh = (struct nlmsghdr *)nlm_ev;
  241. data = (char *) malloc(nlh->nlmsg_len);
  242. if(data == NULL) {
  243. LOG_ERR("Couldn't allocate %d bytes for Netlink iSCSI message\n",
  244. nlh->nlmsg_len);
  245. return -ENOMEM;
  246. }
  247. memset(data, 0, nlh->nlmsg_len);
  248. ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
  249. if ((rc = nl_read(nl_sock, data, (int) nlh->nlmsg_len, 0)) < 0) {
  250. LOG_ERR("can not read nlm_ev, error %d", rc);
  251. goto error;
  252. }
  253. ev = (struct iscsi_uevent *)NLMSG_DATA(data);
  254. switch (ev->type) {
  255. case ISCSI_KEVENT_PATH_REQ:
  256. msg_type_str = "path_req";
  257. if((ev_size - sizeof(ev)) != sizeof(*path))
  258. LOG_WARN("Didn't get iscsi_path size(%d) expected %d",
  259. ev_size - sizeof(ev), sizeof(*path));
  260. host_no = ev->r.req_path.host_no;
  261. break;
  262. case ISCSI_KEVENT_IF_DOWN:
  263. msg_type_str = "if_down";
  264. host_no = ev->r.notify_if_down.host_no;
  265. break;
  266. default:
  267. /* We don't care about other iSCSI Netlink messages */
  268. LOG_DEBUG(PFX "Received ev->type: 0x%x", ev->type);
  269. rc = 0;
  270. goto error;
  271. }
  272. /* This is a message that drivers should be interested in */
  273. LOG_INFO("Received: '%s': host_no: %d", msg_type_str, host_no);
  274. rc = from_host_no_find_associated_eth_device(host_no, &nic);
  275. if(rc != 0) {
  276. LOG_ERR(PFX "Dropping msg, couldn't find nic with host no:%d\n",
  277. host_no);
  278. goto error;
  279. }
  280. payload = (uint8_t *) ((uint8_t *)ev) + sizeof(*ev);
  281. path = (struct iscsi_path *)payload;
  282. if (ev->type == ISCSI_KEVENT_PATH_REQ) {
  283. struct timespec sleep_req, sleep_rem;
  284. nic_interface_t *nic_iface;
  285. uint16_t ip_type;
  286. sleep_req.tv_sec = 0;
  287. sleep_req.tv_nsec = 250000000;
  288. if (path->ip_addr_len == 4)
  289. ip_type = AF_INET;
  290. else if (path->ip_addr_len == 16)
  291. ip_type = AF_INET6;
  292. else
  293. ip_type = 0;
  294. nic_iface = nic_find_nic_iface_protocol(nic, path->vlan_id,
  295. ip_type);
  296. if (nic_iface == NULL) {
  297. LOG_WARN(PFX "%s: Couldn't find nic_iface "
  298. "vlan: %d ip_addr_len",
  299. nic->log_name,
  300. path->vlan_id, path->ip_addr_len);
  301. goto error;
  302. }
  303. /* Ensure that the NIC is RUNNING */
  304. rc = -EIO;
  305. for (i=0; i<10; i++) {
  306. if(((nic->state & NIC_RUNNING) == NIC_RUNNING) &&
  307. (nic_iface->state & NIC_IFACE_RUNNING)) {
  308. rc = 0;
  309. break;
  310. }
  311. nanosleep(&sleep_req, &sleep_rem);
  312. }
  313. if (rc !=0) {
  314. LOG_WARN(PFX "%s: is not running so can't issue "
  315. "neigh req, cmd: 0x%x state: 0x%x",
  316. nic->log_name, ev->type, nic->state);
  317. goto error;
  318. }
  319. }
  320. if(nic->ops) {
  321. switch (ev->type) {
  322. case ISCSI_KEVENT_PATH_REQ:
  323. /* pass the request up to the user space
  324. * library driver */
  325. if(nic->ops->handle_iscsi_path_req) {
  326. nic->ops->handle_iscsi_path_req(nic,
  327. nl_sock, ev,
  328. path, ev_size);
  329. }
  330. break;
  331. case ISCSI_KEVENT_IF_DOWN:
  332. nic_remove(nic, 0);
  333. break;
  334. }
  335. }
  336. rc = 0;
  337. error:
  338. free(data);
  339. return rc;
  340. }
  341. /**
  342. * nic_nl_open() - This is called when opening/creating the Netlink listening
  343. * thread
  344. * @param dev - CNIC UIO device to create a NetLink listener on
  345. * @return 0 on success, <0 on failure
  346. */
  347. int nic_nl_open()
  348. {
  349. int rc;
  350. struct pollfd poll_array[POLL_MAX];
  351. memset(poll_array, 0, sizeof(poll_array));
  352. nlm_sendbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
  353. if (!nlm_sendbuf) {
  354. LOG_ERR(PFX "can't allocate nlm_sendbuf");
  355. rc = -ENOMEM;
  356. goto error;
  357. }
  358. nlm_recvbuf = calloc(1, NLM_BUF_DEFAULT_MAX);
  359. if (!nlm_recvbuf) {
  360. LOG_ERR(PFX "can't allocate nlm_recvbuf");
  361. rc = -ENOMEM;
  362. goto error;
  363. }
  364. nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ISCSI);
  365. if (nl_sock < 0) {
  366. LOG_ERR(PFX "can not create NETLINK_ISCSI socket");
  367. rc = -ENOMEM;
  368. goto error;
  369. }
  370. memset(&src_addr, 0, sizeof(src_addr));
  371. src_addr.nl_family = AF_NETLINK;
  372. src_addr.nl_pid = getpid();
  373. src_addr.nl_groups = ISCSI_NL_GRP_UIP;
  374. while ((!event_loop_stop) && (bnx2i_loaded == 0)) {
  375. rc = bind(nl_sock,
  376. (struct sockaddr *)&src_addr, sizeof(src_addr));
  377. if (rc == 0)
  378. break;
  379. LOG_ERR(PFX "waiting binding to NETLINK_ISCSI socket");
  380. pthread_mutex_lock(&bnx2i_module_loaded_mutex);
  381. pthread_cond_wait(&bnx2i_module_loaded_cond,
  382. &bnx2i_module_loaded_mutex);
  383. pthread_mutex_unlock(&bnx2i_module_loaded_mutex);
  384. sleep(1);
  385. }
  386. if(event_loop_stop) {
  387. rc = -EINVAL;
  388. goto error;
  389. }
  390. LOG_INFO(PFX "Netlink to CNIC on pid %d is ready", src_addr.nl_pid);
  391. poll_array[POLL_NL].fd = nl_sock;
  392. poll_array[POLL_NL].events = POLLIN;
  393. while (!event_loop_stop) {
  394. int res = poll(poll_array, POLL_MAX, NL_POLL_RESOLUTION);
  395. if (res > 0) {
  396. if (poll_array[POLL_NL].revents)
  397. ctldev_handle();
  398. } else if (res < 0) {
  399. if (errno == EINTR) {
  400. LOG_DEBUG(PFX "event_loop interrupted");
  401. } else {
  402. LOG_ERR(PFX "got poll() error (%d), errno (%d), "
  403. "exiting", res, errno);
  404. break;
  405. }
  406. }
  407. }
  408. LOG_INFO(PFX "Netlink thread exit'ing");
  409. rc = 0;
  410. error:
  411. if(nlm_sendbuf) {
  412. free(nlm_sendbuf);
  413. nlm_sendbuf = NULL;
  414. }
  415. if(nlm_recvbuf) {
  416. free(nlm_recvbuf);
  417. nlm_recvbuf = NULL;
  418. }
  419. return 0;
  420. }