1 /* 2 * QEMU paravirtual RDMA - rdmacm-mux implementation 3 * 4 * Copyright (C) 2018 Oracle 5 * Copyright (C) 2018 Red Hat Inc 6 * 7 * Authors: 8 * Yuval Shaia <yuval.shaia@oracle.com> 9 * Marcel Apfelbaum <marcel@redhat.com> 10 * 11 * This work is licensed under the terms of the GNU GPL, version 2 or later. 12 * See the COPYING file in the top-level directory. 13 * 14 */ 15 16 #include "qemu/osdep.h" 17 #include "sys/poll.h" 18 #include "sys/ioctl.h" 19 #include "pthread.h" 20 #include "syslog.h" 21 22 #include "infiniband/verbs.h" 23 #include "infiniband/umad.h" 24 #include "infiniband/umad_types.h" 25 #include "infiniband/umad_sa.h" 26 #include "infiniband/umad_cm.h" 27 28 #include "rdmacm-mux.h" 29 30 #define SCALE_US 1000 31 #define COMMID_TTL 2 /* How many SCALE_US a context of MAD session is saved */ 32 #define SLEEP_SECS 5 /* This is used both in poll() and thread */ 33 #define SERVER_LISTEN_BACKLOG 10 34 #define MAX_CLIENTS 4096 35 #define MAD_RMPP_VERSION 0 36 #define MAD_METHOD_MASK0 0x8 37 38 #define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof(long))) 39 40 #define CM_REQ_DGID_POS 80 41 #define CM_SIDR_REQ_DGID_POS 44 42 43 /* The below can be override by command line parameter */ 44 #define UNIX_SOCKET_PATH "/var/run/rdmacm-mux" 45 /* Has format %s-%s-%d" <path>-<rdma-dev--name>-<port> */ 46 #define SOCKET_PATH_MAX (PATH_MAX - NAME_MAX - sizeof(int) - 2) 47 #define RDMA_PORT_NUM 1 48 49 typedef struct RdmaCmServerArgs { 50 char unix_socket_path[PATH_MAX]; 51 char rdma_dev_name[NAME_MAX]; 52 int rdma_port_num; 53 } RdmaCMServerArgs; 54 55 typedef struct CommId2FdEntry { 56 int fd; 57 int ttl; /* Initialized to 2, decrement each timeout, entry delete when 0 */ 58 __be64 gid_ifid; 59 } CommId2FdEntry; 60 61 typedef struct RdmaCmUMadAgent { 62 int port_id; 63 int agent_id; 64 GHashTable *gid2fd; /* Used to find fd of a given gid */ 65 GHashTable *commid2fd; /* Used to find fd on of a given comm_id */ 66 } RdmaCmUMadAgent; 67 68 typedef struct RdmaCmServer { 69 bool run; 70 RdmaCMServerArgs args; 71 struct pollfd fds[MAX_CLIENTS]; 72 int nfds; 73 RdmaCmUMadAgent umad_agent; 74 pthread_t umad_recv_thread; 75 pthread_rwlock_t lock; 76 } RdmaCMServer; 77 78 static RdmaCMServer server = {0}; 79 80 static void usage(const char *progname) 81 { 82 printf("Usage: %s [OPTION]...\n" 83 "Start a RDMA-CM multiplexer\n" 84 "\n" 85 "\t-h Show this help\n" 86 "\t-d rdma-device-name Name of RDMA device to register with\n" 87 "\t-s unix-socket-path Path to unix socket to listen on (default %s)\n" 88 "\t-p rdma-device-port Port number of RDMA device to register with (default %d)\n", 89 progname, UNIX_SOCKET_PATH, RDMA_PORT_NUM); 90 } 91 92 static void help(const char *progname) 93 { 94 fprintf(stderr, "Try '%s -h' for more information.\n", progname); 95 } 96 97 static void parse_args(int argc, char *argv[]) 98 { 99 int c; 100 char unix_socket_path[SOCKET_PATH_MAX]; 101 102 strcpy(server.args.rdma_dev_name, ""); 103 strcpy(unix_socket_path, UNIX_SOCKET_PATH); 104 server.args.rdma_port_num = RDMA_PORT_NUM; 105 106 while ((c = getopt(argc, argv, "hs:d:p:")) != -1) { 107 switch (c) { 108 case 'h': 109 usage(argv[0]); 110 exit(0); 111 112 case 'd': 113 strncpy(server.args.rdma_dev_name, optarg, NAME_MAX - 1); 114 break; 115 116 case 's': 117 /* This is temporary, final name will build below */ 118 strncpy(unix_socket_path, optarg, SOCKET_PATH_MAX); 119 break; 120 121 case 'p': 122 server.args.rdma_port_num = atoi(optarg); 123 break; 124 125 default: 126 help(argv[0]); 127 exit(1); 128 } 129 } 130 131 if (!strcmp(server.args.rdma_dev_name, "")) { 132 fprintf(stderr, "Missing RDMA device name\n"); 133 help(argv[0]); 134 exit(1); 135 } 136 137 /* Build unique unix-socket file name */ 138 snprintf(server.args.unix_socket_path, PATH_MAX, "%s-%s-%d", 139 unix_socket_path, server.args.rdma_dev_name, 140 server.args.rdma_port_num); 141 142 syslog(LOG_INFO, "unix_socket_path=%s", server.args.unix_socket_path); 143 syslog(LOG_INFO, "rdma-device-name=%s", server.args.rdma_dev_name); 144 syslog(LOG_INFO, "rdma-device-port=%d", server.args.rdma_port_num); 145 } 146 147 static void hash_tbl_alloc(void) 148 { 149 150 server.umad_agent.gid2fd = g_hash_table_new_full(g_int64_hash, 151 g_int64_equal, 152 g_free, g_free); 153 server.umad_agent.commid2fd = g_hash_table_new_full(g_int_hash, 154 g_int_equal, 155 g_free, g_free); 156 } 157 158 static void hash_tbl_free(void) 159 { 160 if (server.umad_agent.commid2fd) { 161 g_hash_table_destroy(server.umad_agent.commid2fd); 162 } 163 if (server.umad_agent.gid2fd) { 164 g_hash_table_destroy(server.umad_agent.gid2fd); 165 } 166 } 167 168 169 static int _hash_tbl_search_fd_by_ifid(__be64 *gid_ifid) 170 { 171 int *fd; 172 173 fd = g_hash_table_lookup(server.umad_agent.gid2fd, gid_ifid); 174 if (!fd) { 175 /* Let's try IPv4 */ 176 *gid_ifid |= 0x00000000ffff0000; 177 fd = g_hash_table_lookup(server.umad_agent.gid2fd, gid_ifid); 178 } 179 180 return fd ? *fd : 0; 181 } 182 183 static int hash_tbl_search_fd_by_ifid(int *fd, __be64 *gid_ifid) 184 { 185 pthread_rwlock_rdlock(&server.lock); 186 *fd = _hash_tbl_search_fd_by_ifid(gid_ifid); 187 pthread_rwlock_unlock(&server.lock); 188 189 if (!fd) { 190 syslog(LOG_WARNING, "Can't find matching for ifid 0x%llx\n", *gid_ifid); 191 return -ENOENT; 192 } 193 194 return 0; 195 } 196 197 static int hash_tbl_search_fd_by_comm_id(uint32_t comm_id, int *fd, 198 __be64 *gid_idid) 199 { 200 CommId2FdEntry *fde; 201 202 pthread_rwlock_rdlock(&server.lock); 203 fde = g_hash_table_lookup(server.umad_agent.commid2fd, &comm_id); 204 pthread_rwlock_unlock(&server.lock); 205 206 if (!fde) { 207 syslog(LOG_WARNING, "Can't find matching for comm_id 0x%x\n", comm_id); 208 return -ENOENT; 209 } 210 211 *fd = fde->fd; 212 *gid_idid = fde->gid_ifid; 213 214 return 0; 215 } 216 217 static RdmaCmMuxErrCode add_fd_ifid_pair(int fd, __be64 gid_ifid) 218 { 219 int fd1; 220 221 pthread_rwlock_wrlock(&server.lock); 222 223 fd1 = _hash_tbl_search_fd_by_ifid(&gid_ifid); 224 if (fd1) { /* record already exist - an error */ 225 pthread_rwlock_unlock(&server.lock); 226 return fd == fd1 ? RDMACM_MUX_ERR_CODE_EEXIST : 227 RDMACM_MUX_ERR_CODE_EACCES; 228 } 229 230 g_hash_table_insert(server.umad_agent.gid2fd, g_memdup(&gid_ifid, 231 sizeof(gid_ifid)), g_memdup(&fd, sizeof(fd))); 232 233 pthread_rwlock_unlock(&server.lock); 234 235 syslog(LOG_INFO, "0x%lx registered on socket %d", 236 be64toh((uint64_t)gid_ifid), fd); 237 238 return RDMACM_MUX_ERR_CODE_OK; 239 } 240 241 static RdmaCmMuxErrCode delete_fd_ifid_pair(int fd, __be64 gid_ifid) 242 { 243 int fd1; 244 245 pthread_rwlock_wrlock(&server.lock); 246 247 fd1 = _hash_tbl_search_fd_by_ifid(&gid_ifid); 248 if (!fd1) { /* record not exist - an error */ 249 pthread_rwlock_unlock(&server.lock); 250 return RDMACM_MUX_ERR_CODE_ENOTFOUND; 251 } 252 253 g_hash_table_remove(server.umad_agent.gid2fd, g_memdup(&gid_ifid, 254 sizeof(gid_ifid))); 255 pthread_rwlock_unlock(&server.lock); 256 257 syslog(LOG_INFO, "0x%lx unregistered on socket %d", 258 be64toh((uint64_t)gid_ifid), fd); 259 260 return RDMACM_MUX_ERR_CODE_OK; 261 } 262 263 static void hash_tbl_save_fd_comm_id_pair(int fd, uint32_t comm_id, 264 uint64_t gid_ifid) 265 { 266 CommId2FdEntry fde = {fd, COMMID_TTL, gid_ifid}; 267 268 pthread_rwlock_wrlock(&server.lock); 269 g_hash_table_insert(server.umad_agent.commid2fd, 270 g_memdup(&comm_id, sizeof(comm_id)), 271 g_memdup(&fde, sizeof(fde))); 272 pthread_rwlock_unlock(&server.lock); 273 } 274 275 static gboolean remove_old_comm_ids(gpointer key, gpointer value, 276 gpointer user_data) 277 { 278 CommId2FdEntry *fde = (CommId2FdEntry *)value; 279 280 return !fde->ttl--; 281 } 282 283 static gboolean remove_entry_from_gid2fd(gpointer key, gpointer value, 284 gpointer user_data) 285 { 286 if (*(int *)value == *(int *)user_data) { 287 syslog(LOG_INFO, "0x%lx unregistered on socket %d", 288 be64toh(*(uint64_t *)key), *(int *)value); 289 return true; 290 } 291 292 return false; 293 } 294 295 static void hash_tbl_remove_fd_ifid_pair(int fd) 296 { 297 pthread_rwlock_wrlock(&server.lock); 298 g_hash_table_foreach_remove(server.umad_agent.gid2fd, 299 remove_entry_from_gid2fd, (gpointer)&fd); 300 pthread_rwlock_unlock(&server.lock); 301 } 302 303 static int get_fd(const char *mad, int *fd, __be64 *gid_ifid) 304 { 305 struct umad_hdr *hdr = (struct umad_hdr *)mad; 306 char *data = (char *)hdr + sizeof(*hdr); 307 int32_t comm_id = 0; 308 uint16_t attr_id = be16toh(hdr->attr_id); 309 int rc = 0; 310 311 switch (attr_id) { 312 case UMAD_CM_ATTR_REQ: 313 memcpy(gid_ifid, data + CM_REQ_DGID_POS, sizeof(*gid_ifid)); 314 rc = hash_tbl_search_fd_by_ifid(fd, gid_ifid); 315 break; 316 317 case UMAD_CM_ATTR_SIDR_REQ: 318 memcpy(gid_ifid, data + CM_SIDR_REQ_DGID_POS, sizeof(*gid_ifid)); 319 rc = hash_tbl_search_fd_by_ifid(fd, gid_ifid); 320 break; 321 322 case UMAD_CM_ATTR_REP: 323 /* Fall through */ 324 case UMAD_CM_ATTR_REJ: 325 /* Fall through */ 326 case UMAD_CM_ATTR_DREQ: 327 /* Fall through */ 328 case UMAD_CM_ATTR_DREP: 329 /* Fall through */ 330 case UMAD_CM_ATTR_RTU: 331 data += sizeof(comm_id); 332 /* Fall through */ 333 case UMAD_CM_ATTR_SIDR_REP: 334 memcpy(&comm_id, data, sizeof(comm_id)); 335 if (comm_id) { 336 rc = hash_tbl_search_fd_by_comm_id(comm_id, fd, gid_ifid); 337 } 338 break; 339 340 default: 341 rc = -EINVAL; 342 syslog(LOG_WARNING, "Unsupported attr_id 0x%x\n", attr_id); 343 } 344 345 syslog(LOG_DEBUG, "mad_to_vm: %d 0x%x 0x%x\n", *fd, attr_id, comm_id); 346 347 return rc; 348 } 349 350 static void *umad_recv_thread_func(void *args) 351 { 352 int rc; 353 RdmaCmMuxMsg msg = {}; 354 int fd = -2; 355 356 msg.hdr.msg_type = RDMACM_MUX_MSG_TYPE_REQ; 357 msg.hdr.op_code = RDMACM_MUX_OP_CODE_MAD; 358 359 while (server.run) { 360 do { 361 msg.umad_len = sizeof(msg.umad.mad); 362 rc = umad_recv(server.umad_agent.port_id, &msg.umad, &msg.umad_len, 363 SLEEP_SECS * SCALE_US); 364 if ((rc == -EIO) || (rc == -EINVAL)) { 365 syslog(LOG_CRIT, "Fatal error while trying to read MAD"); 366 } 367 368 if (rc == -ETIMEDOUT) { 369 g_hash_table_foreach_remove(server.umad_agent.commid2fd, 370 remove_old_comm_ids, NULL); 371 } 372 } while (rc && server.run); 373 374 if (server.run) { 375 rc = get_fd(msg.umad.mad, &fd, &msg.hdr.sgid.global.interface_id); 376 if (rc) { 377 continue; 378 } 379 380 send(fd, &msg, sizeof(msg), 0); 381 } 382 } 383 384 return NULL; 385 } 386 387 static int read_and_process(int fd) 388 { 389 int rc; 390 RdmaCmMuxMsg msg = {}; 391 struct umad_hdr *hdr; 392 uint32_t *comm_id = 0; 393 uint16_t attr_id; 394 395 rc = recv(fd, &msg, sizeof(msg), 0); 396 syslog(LOG_DEBUG, "Socket %d, recv %d\n", fd, rc); 397 398 if (rc < 0 && errno != EWOULDBLOCK) { 399 syslog(LOG_ERR, "Fail to read from socket %d\n", fd); 400 return -EIO; 401 } 402 403 if (!rc) { 404 syslog(LOG_ERR, "Fail to read from socket %d\n", fd); 405 return -EPIPE; 406 } 407 408 if (msg.hdr.msg_type != RDMACM_MUX_MSG_TYPE_REQ) { 409 syslog(LOG_WARNING, "Got non-request message (%d) from socket %d\n", 410 msg.hdr.msg_type, fd); 411 return -EPERM; 412 } 413 414 switch (msg.hdr.op_code) { 415 case RDMACM_MUX_OP_CODE_REG: 416 rc = add_fd_ifid_pair(fd, msg.hdr.sgid.global.interface_id); 417 break; 418 419 case RDMACM_MUX_OP_CODE_UNREG: 420 rc = delete_fd_ifid_pair(fd, msg.hdr.sgid.global.interface_id); 421 break; 422 423 case RDMACM_MUX_OP_CODE_MAD: 424 /* If this is REQ or REP then store the pair comm_id,fd to be later 425 * used for other messages where gid is unknown */ 426 hdr = (struct umad_hdr *)msg.umad.mad; 427 attr_id = be16toh(hdr->attr_id); 428 if ((attr_id == UMAD_CM_ATTR_REQ) || (attr_id == UMAD_CM_ATTR_DREQ) || 429 (attr_id == UMAD_CM_ATTR_SIDR_REQ) || 430 (attr_id == UMAD_CM_ATTR_REP) || (attr_id == UMAD_CM_ATTR_DREP)) { 431 comm_id = (uint32_t *)(msg.umad.mad + sizeof(*hdr)); 432 hash_tbl_save_fd_comm_id_pair(fd, *comm_id, 433 msg.hdr.sgid.global.interface_id); 434 } 435 436 syslog(LOG_DEBUG, "vm_to_mad: %d 0x%x 0x%x\n", fd, attr_id, 437 comm_id ? *comm_id : 0); 438 rc = umad_send(server.umad_agent.port_id, server.umad_agent.agent_id, 439 &msg.umad, msg.umad_len, 1, 0); 440 if (rc) { 441 syslog(LOG_ERR, 442 "Fail to send MAD message (0x%x) from socket %d, err=%d", 443 attr_id, fd, rc); 444 } 445 break; 446 447 default: 448 syslog(LOG_ERR, "Got invalid op_code (%d) from socket %d", 449 msg.hdr.msg_type, fd); 450 rc = RDMACM_MUX_ERR_CODE_EINVAL; 451 } 452 453 msg.hdr.msg_type = RDMACM_MUX_MSG_TYPE_RESP; 454 msg.hdr.err_code = rc; 455 rc = send(fd, &msg, sizeof(msg), 0); 456 457 return rc == sizeof(msg) ? 0 : -EPIPE; 458 } 459 460 static int accept_all(void) 461 { 462 int fd, rc = 0;; 463 464 pthread_rwlock_wrlock(&server.lock); 465 466 do { 467 if ((server.nfds + 1) > MAX_CLIENTS) { 468 syslog(LOG_WARNING, "Too many clients (%d)", server.nfds); 469 rc = -EIO; 470 goto out; 471 } 472 473 fd = accept(server.fds[0].fd, NULL, NULL); 474 if (fd < 0) { 475 if (errno != EWOULDBLOCK) { 476 syslog(LOG_WARNING, "accept() failed"); 477 rc = -EIO; 478 goto out; 479 } 480 break; 481 } 482 483 syslog(LOG_INFO, "Client connected on socket %d\n", fd); 484 server.fds[server.nfds].fd = fd; 485 server.fds[server.nfds].events = POLLIN; 486 server.nfds++; 487 } while (fd != -1); 488 489 out: 490 pthread_rwlock_unlock(&server.lock); 491 return rc; 492 } 493 494 static void compress_fds(void) 495 { 496 int i, j; 497 int closed = 0; 498 499 pthread_rwlock_wrlock(&server.lock); 500 501 for (i = 1; i < server.nfds; i++) { 502 if (!server.fds[i].fd) { 503 closed++; 504 for (j = i; j < server.nfds - 1; j++) { 505 server.fds[j] = server.fds[j + 1]; 506 } 507 } 508 } 509 510 server.nfds -= closed; 511 512 pthread_rwlock_unlock(&server.lock); 513 } 514 515 static void close_fd(int idx) 516 { 517 close(server.fds[idx].fd); 518 syslog(LOG_INFO, "Socket %d closed\n", server.fds[idx].fd); 519 hash_tbl_remove_fd_ifid_pair(server.fds[idx].fd); 520 server.fds[idx].fd = 0; 521 } 522 523 static void run(void) 524 { 525 int rc, nfds, i; 526 bool compress = false; 527 528 syslog(LOG_INFO, "Service started"); 529 530 while (server.run) { 531 rc = poll(server.fds, server.nfds, SLEEP_SECS * SCALE_US); 532 if (rc < 0) { 533 if (errno != EINTR) { 534 syslog(LOG_WARNING, "poll() failed"); 535 } 536 continue; 537 } 538 539 if (rc == 0) { 540 continue; 541 } 542 543 nfds = server.nfds; 544 for (i = 0; i < nfds; i++) { 545 syslog(LOG_DEBUG, "pollfd[%d]: revents 0x%x, events 0x%x\n", i, 546 server.fds[i].revents, server.fds[i].events); 547 if (server.fds[i].revents == 0) { 548 continue; 549 } 550 551 if (server.fds[i].revents != POLLIN) { 552 if (i == 0) { 553 syslog(LOG_NOTICE, "Unexpected poll() event (0x%x)\n", 554 server.fds[i].revents); 555 } else { 556 close_fd(i); 557 compress = true; 558 } 559 continue; 560 } 561 562 if (i == 0) { 563 rc = accept_all(); 564 if (rc) { 565 continue; 566 } 567 } else { 568 rc = read_and_process(server.fds[i].fd); 569 if (rc) { 570 close_fd(i); 571 compress = true; 572 } 573 } 574 } 575 576 if (compress) { 577 compress = false; 578 compress_fds(); 579 } 580 } 581 } 582 583 static void fini_listener(void) 584 { 585 int i; 586 587 if (server.fds[0].fd <= 0) { 588 return; 589 } 590 591 for (i = server.nfds - 1; i >= 0; i--) { 592 if (server.fds[i].fd) { 593 close(server.fds[i].fd); 594 } 595 } 596 597 unlink(server.args.unix_socket_path); 598 } 599 600 static void fini_umad(void) 601 { 602 if (server.umad_agent.agent_id) { 603 umad_unregister(server.umad_agent.port_id, server.umad_agent.agent_id); 604 } 605 606 if (server.umad_agent.port_id) { 607 umad_close_port(server.umad_agent.port_id); 608 } 609 610 hash_tbl_free(); 611 } 612 613 static void fini(void) 614 { 615 if (server.umad_recv_thread) { 616 pthread_join(server.umad_recv_thread, NULL); 617 server.umad_recv_thread = 0; 618 } 619 fini_umad(); 620 fini_listener(); 621 pthread_rwlock_destroy(&server.lock); 622 623 syslog(LOG_INFO, "Service going down"); 624 } 625 626 static int init_listener(void) 627 { 628 struct sockaddr_un sun; 629 int rc, on = 1; 630 631 server.fds[0].fd = socket(AF_UNIX, SOCK_STREAM, 0); 632 if (server.fds[0].fd < 0) { 633 syslog(LOG_ALERT, "socket() failed"); 634 return -EIO; 635 } 636 637 rc = setsockopt(server.fds[0].fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 638 sizeof(on)); 639 if (rc < 0) { 640 syslog(LOG_ALERT, "setsockopt() failed"); 641 rc = -EIO; 642 goto err; 643 } 644 645 rc = ioctl(server.fds[0].fd, FIONBIO, (char *)&on); 646 if (rc < 0) { 647 syslog(LOG_ALERT, "ioctl() failed"); 648 rc = -EIO; 649 goto err; 650 } 651 652 if (strlen(server.args.unix_socket_path) >= sizeof(sun.sun_path)) { 653 syslog(LOG_ALERT, 654 "Invalid unix_socket_path, size must be less than %ld\n", 655 sizeof(sun.sun_path)); 656 rc = -EINVAL; 657 goto err; 658 } 659 660 sun.sun_family = AF_UNIX; 661 rc = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", 662 server.args.unix_socket_path); 663 if (rc < 0 || rc >= sizeof(sun.sun_path)) { 664 syslog(LOG_ALERT, "Could not copy unix socket path\n"); 665 rc = -EINVAL; 666 goto err; 667 } 668 669 rc = bind(server.fds[0].fd, (struct sockaddr *)&sun, sizeof(sun)); 670 if (rc < 0) { 671 syslog(LOG_ALERT, "bind() failed"); 672 rc = -EIO; 673 goto err; 674 } 675 676 rc = listen(server.fds[0].fd, SERVER_LISTEN_BACKLOG); 677 if (rc < 0) { 678 syslog(LOG_ALERT, "listen() failed"); 679 rc = -EIO; 680 goto err; 681 } 682 683 server.fds[0].events = POLLIN; 684 server.nfds = 1; 685 server.run = true; 686 687 return 0; 688 689 err: 690 close(server.fds[0].fd); 691 return rc; 692 } 693 694 static int init_umad(void) 695 { 696 long method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK]; 697 698 server.umad_agent.port_id = umad_open_port(server.args.rdma_dev_name, 699 server.args.rdma_port_num); 700 701 if (server.umad_agent.port_id < 0) { 702 syslog(LOG_WARNING, "umad_open_port() failed"); 703 return -EIO; 704 } 705 706 memset(&method_mask, 0, sizeof(method_mask)); 707 method_mask[0] = MAD_METHOD_MASK0; 708 server.umad_agent.agent_id = umad_register(server.umad_agent.port_id, 709 UMAD_CLASS_CM, 710 UMAD_SA_CLASS_VERSION, 711 MAD_RMPP_VERSION, method_mask); 712 if (server.umad_agent.agent_id < 0) { 713 syslog(LOG_WARNING, "umad_register() failed"); 714 return -EIO; 715 } 716 717 hash_tbl_alloc(); 718 719 return 0; 720 } 721 722 static void signal_handler(int sig, siginfo_t *siginfo, void *context) 723 { 724 static bool warned; 725 726 /* Prevent stop if clients are connected */ 727 if (server.nfds != 1) { 728 if (!warned) { 729 syslog(LOG_WARNING, 730 "Can't stop while active client exist, resend SIGINT to overid"); 731 warned = true; 732 return; 733 } 734 } 735 736 if (sig == SIGINT) { 737 server.run = false; 738 fini(); 739 } 740 741 exit(0); 742 } 743 744 static int init(void) 745 { 746 int rc; 747 struct sigaction sig = {}; 748 749 rc = init_listener(); 750 if (rc) { 751 return rc; 752 } 753 754 rc = init_umad(); 755 if (rc) { 756 return rc; 757 } 758 759 pthread_rwlock_init(&server.lock, 0); 760 761 rc = pthread_create(&server.umad_recv_thread, NULL, umad_recv_thread_func, 762 NULL); 763 if (rc) { 764 syslog(LOG_ERR, "Fail to create UMAD receiver thread (%d)\n", rc); 765 return rc; 766 } 767 768 sig.sa_sigaction = &signal_handler; 769 sig.sa_flags = SA_SIGINFO; 770 rc = sigaction(SIGINT, &sig, NULL); 771 if (rc < 0) { 772 syslog(LOG_ERR, "Fail to install SIGINT handler (%d)\n", errno); 773 return rc; 774 } 775 776 return 0; 777 } 778 779 int main(int argc, char *argv[]) 780 { 781 int rc; 782 783 memset(&server, 0, sizeof(server)); 784 785 parse_args(argc, argv); 786 787 rc = init(); 788 if (rc) { 789 syslog(LOG_ERR, "Fail to initialize server (%d)\n", rc); 790 rc = -EAGAIN; 791 goto out; 792 } 793 794 run(); 795 796 out: 797 fini(); 798 799 return rc; 800 } 801