ctl_ha.c revision 288789
1184610Salfred/*- 2184610Salfred * Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org> 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer, 10184610Salfred * without modification, immediately at the beginning of the file. 11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer in the 13184610Salfred * documentation and/or other materials provided with the distribution. 14184610Salfred * 15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16184610Salfred * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17184610Salfred * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18184610Salfred * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19184610Salfred * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20184610Salfred * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21184610Salfred * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22184610Salfred * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23184610Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24184610Salfred * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27194230Sthompsa#include <sys/cdefs.h> 28194230Sthompsa__FBSDID("$FreeBSD: stable/10/sys/cam/ctl/ctl_ha.c 288789 2015-10-05 10:53:13Z mav $"); 29184610Salfred 30184610Salfred#include <sys/param.h> 31228056Shselasky#include <sys/systm.h> 32228056Shselasky#include <sys/kernel.h> 33228056Shselasky#include <sys/kthread.h> 34228056Shselasky#include <sys/types.h> 35228056Shselasky#include <sys/limits.h> 36228056Shselasky#include <sys/lock.h> 37228056Shselasky#include <sys/module.h> 38228056Shselasky#include <sys/mutex.h> 39228056Shselasky#include <sys/condvar.h> 40228056Shselasky#include <sys/malloc.h> 41228056Shselasky#include <sys/mbuf.h> 42228056Shselasky#include <sys/proc.h> 43228056Shselasky#include <sys/conf.h> 44228056Shselasky#include <sys/queue.h> 45228056Shselasky#include <sys/sysctl.h> 46228056Shselasky#include <sys/socket.h> 47228056Shselasky#include <sys/socketvar.h> 48228056Shselasky#include <sys/uio.h> 49228056Shselasky#include <netinet/in.h> 50228056Shselasky#include <netinet/tcp.h> 51228056Shselasky#include <vm/uma.h> 52228056Shselasky 53228056Shselasky#include <cam/cam.h> 54228056Shselasky#include <cam/scsi/scsi_all.h> 55228056Shselasky#include <cam/scsi/scsi_da.h> 56228056Shselasky#include <cam/ctl/ctl_io.h> 57228056Shselasky#include <cam/ctl/ctl.h> 58228056Shselasky#include <cam/ctl/ctl_frontend.h> 59228056Shselasky#include <cam/ctl/ctl_util.h> 60228056Shselasky#include <cam/ctl/ctl_backend.h> 61228056Shselasky#include <cam/ctl/ctl_ioctl.h> 62228056Shselasky#include <cam/ctl/ctl_ha.h> 63228056Shselasky#include <cam/ctl/ctl_private.h> 64228056Shselasky#include <cam/ctl/ctl_debug.h> 65228056Shselasky#include <cam/ctl/ctl_error.h> 66228056Shselasky 67228056Shselasky#if (__FreeBSD_version < 1100000) 68228056Shselaskystruct mbufq { 69228056Shselasky struct mbuf *head; 70228056Shselasky struct mbuf *tail; 71228056Shselasky}; 72228056Shselasky 73228056Shselaskystatic void 74228056Shselaskymbufq_init(struct mbufq *q, int limit) 75228056Shselasky{ 76228056Shselasky 77228056Shselasky q->head = q->tail = NULL; 78228056Shselasky} 79228056Shselasky 80228056Shselaskystatic void 81228056Shselaskymbufq_drain(struct mbufq *q) 82228056Shselasky{ 83228056Shselasky struct mbuf *m; 84228056Shselasky 85228056Shselasky while ((m = q->head) != NULL) { 86228056Shselasky q->head = m->m_nextpkt; 87228056Shselasky m_freem(m); 88228056Shselasky } 89228056Shselasky q->tail = NULL; 90228056Shselasky} 91228056Shselasky 92228056Shselaskystatic struct mbuf * 93228056Shselaskymbufq_dequeue(struct mbufq *q) 94228056Shselasky{ 95228056Shselasky struct mbuf *m; 96228056Shselasky 97228056Shselasky m = q->head; 98228056Shselasky if (m) { 99228056Shselasky if (q->tail == m) 100228056Shselasky q->tail = NULL; 101228056Shselasky q->head = m->m_nextpkt; 102228056Shselasky m->m_nextpkt = NULL; 103228056Shselasky } 104228056Shselasky return (m); 105228056Shselasky} 106228056Shselasky 107228056Shselaskystatic void 108228056Shselaskymbufq_enqueue(struct mbufq *q, struct mbuf *m) 109228056Shselasky{ 110228056Shselasky 111228056Shselasky m->m_nextpkt = NULL; 112228056Shselasky if (q->tail) 113228056Shselasky q->tail->m_nextpkt = m; 114228056Shselasky else 115228056Shselasky q->head = m; 116228056Shselasky q->tail = m; 117228056Shselasky} 118228056Shselasky 119228056Shselaskystatic u_int 120228056Shselaskysbavail(struct sockbuf *sb) 121228056Shselasky{ 122228056Shselasky return (sb->sb_cc); 123228056Shselasky} 124228056Shselasky 125228056Shselasky#if (__FreeBSD_version < 1000000) 126228056Shselasky#define mtodo(m, o) ((void *)(((m)->m_data) + (o))) 127228056Shselasky#endif 128228056Shselasky#endif 129228056Shselasky 130228056Shselaskystruct ha_msg_wire { 131228056Shselasky uint32_t channel; 132228056Shselasky uint32_t length; 133228056Shselasky}; 134228056Shselasky 135228056Shselaskystruct ha_dt_msg_wire { 136228056Shselasky ctl_ha_dt_cmd command; 137228056Shselasky uint32_t size; 138228056Shselasky uint8_t *local; 139228056Shselasky uint8_t *remote; 140228056Shselasky}; 141228056Shselasky 142228056Shselaskystruct ha_softc { 143228056Shselasky struct ctl_softc *ha_ctl_softc; 144228056Shselasky ctl_evt_handler ha_handler[CTL_HA_CHAN_MAX]; 145184610Salfred char ha_peer[128]; 146184610Salfred struct sockaddr_in ha_peer_in; 147184610Salfred struct socket *ha_lso; 148192984Sthompsa struct socket *ha_so; 149192984Sthompsa struct mbufq ha_sendq; 150192984Sthompsa struct mbuf *ha_sending; 151184610Salfred struct mtx ha_lock; 152184610Salfred int ha_connect; 153190180Sthompsa int ha_listen; 154192984Sthompsa int ha_connected; 155190180Sthompsa int ha_receiving; 156192984Sthompsa int ha_wakeup; 157190180Sthompsa int ha_disconnect; 158184610Salfred int ha_shutdown; 159184610Salfred eventhandler_tag ha_shutdown_eh; 160184610Salfred TAILQ_HEAD(, ctl_ha_dt_req) ha_dts; 161184610Salfred} ha_softc; 162184610Salfred 163192984Sthompsaextern struct ctl_softc *control_softc; 164192984Sthompsa 165190180Sthompsastatic void 166192984Sthompsactl_ha_conn_wake(struct ha_softc *softc) 167190180Sthompsa{ 168192984Sthompsa 169192984Sthompsa mtx_lock(&softc->ha_lock); 170184610Salfred softc->ha_wakeup = 1; 171184610Salfred mtx_unlock(&softc->ha_lock); 172192984Sthompsa wakeup(&softc->ha_wakeup); 173184610Salfred} 174187173Sthompsa 175190180Sthompsastatic int 176192984Sthompsactl_ha_lupcall(struct socket *so, void *arg, int waitflag) 177192984Sthompsa{ 178190180Sthompsa struct ha_softc *softc = arg; 179192984Sthompsa 180192984Sthompsa ctl_ha_conn_wake(softc); 181192984Sthompsa return (SU_OK); 182192984Sthompsa} 183184610Salfred 184193074Sthompsastatic int 185193074Sthompsactl_ha_rupcall(struct socket *so, void *arg, int waitflag) 186190181Sthompsa{ 187193045Sthompsa struct ha_softc *softc = arg; 188193045Sthompsa 189193045Sthompsa wakeup(&softc->ha_receiving); 190184610Salfred return (SU_OK); 191184610Salfred} 192190181Sthompsa 193184610Salfredstatic int 194184610Salfredctl_ha_supcall(struct socket *so, void *arg, int waitflag) 195184610Salfred{ 196184610Salfred struct ha_softc *softc = arg; 197184610Salfred 198184610Salfred ctl_ha_conn_wake(softc); 199184610Salfred return (SU_OK); 200192984Sthompsa} 201192984Sthompsa 202192984Sthompsastatic void 203192984Sthompsactl_ha_evt(struct ha_softc *softc, ctl_ha_channel ch, ctl_ha_event evt, 204184610Salfred int param) 205192984Sthompsa{ 206184610Salfred int i; 207192984Sthompsa 208192984Sthompsa if (ch < CTL_HA_CHAN_MAX) { 209192984Sthompsa if (softc->ha_handler[ch]) 210192984Sthompsa softc->ha_handler[ch](ch, evt, param); 211184610Salfred return; 212193045Sthompsa } 213184610Salfred for (i = 0; i < CTL_HA_CHAN_MAX; i++) { 214193074Sthompsa if (softc->ha_handler[i]) 215193045Sthompsa softc->ha_handler[i](i, evt, param); 216193045Sthompsa } 217184610Salfred} 218213435Shselasky 219184610Salfredstatic void 220184610Salfredctl_ha_close(struct ha_softc *softc) 221192500Sthompsa{ 222184610Salfred struct socket *so = softc->ha_so; 223193045Sthompsa int report = 0; 224184610Salfred 225184610Salfred if (softc->ha_connected || softc->ha_disconnect) { 226184610Salfred softc->ha_connected = 0; 227184610Salfred mbufq_drain(&softc->ha_sendq); 228194228Sthompsa m_freem(softc->ha_sending); 229193074Sthompsa softc->ha_sending = NULL; 230193074Sthompsa report = 1; 231213435Shselasky } 232194228Sthompsa if (so) { 233192984Sthompsa SOCKBUF_LOCK(&so->so_rcv); 234194228Sthompsa soupcall_clear(so, SO_RCV); 235194228Sthompsa while (softc->ha_receiving) { 236194228Sthompsa wakeup(&softc->ha_receiving); 237194228Sthompsa msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), 238194228Sthompsa 0, "ha_rx exit", 0); 239192984Sthompsa } 240194228Sthompsa SOCKBUF_UNLOCK(&so->so_rcv); 241207080Sthompsa SOCKBUF_LOCK(&so->so_snd); 242213435Shselasky soupcall_clear(so, SO_SND); 243213435Shselasky SOCKBUF_UNLOCK(&so->so_snd); 244194228Sthompsa softc->ha_so = NULL; 245193644Sthompsa if (softc->ha_connect) 246194228Sthompsa pause("reconnect", hz / 2); 247194228Sthompsa soclose(so); 248194228Sthompsa } 249194228Sthompsa if (report) { 250193045Sthompsa ctl_ha_evt(softc, CTL_HA_CHAN_MAX, CTL_HA_EVT_LINK_CHANGE, 251212134Sthompsa (softc->ha_connect || softc->ha_listen) ? 252194228Sthompsa CTL_HA_LINK_UNKNOWN : CTL_HA_LINK_OFFLINE); 253184610Salfred } 254194230Sthompsa} 255 256static void 257ctl_ha_lclose(struct ha_softc *softc) 258{ 259 260 if (softc->ha_lso) { 261 SOCKBUF_LOCK(&softc->ha_lso->so_rcv); 262 soupcall_clear(softc->ha_lso, SO_RCV); 263 SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); 264 soclose(softc->ha_lso); 265 softc->ha_lso = NULL; 266 } 267} 268 269static void 270ctl_ha_rx_thread(void *arg) 271{ 272 struct ha_softc *softc = arg; 273 struct socket *so = softc->ha_so; 274 struct ha_msg_wire wire_hdr; 275 struct uio uio; 276 struct iovec iov; 277 int error, flags, next; 278 279 bzero(&wire_hdr, sizeof(wire_hdr)); 280 while (1) { 281 if (wire_hdr.length > 0) 282 next = wire_hdr.length; 283 else 284 next = sizeof(wire_hdr); 285 SOCKBUF_LOCK(&so->so_rcv); 286 while (sbavail(&so->so_rcv) < next || softc->ha_disconnect) { 287 if (softc->ha_connected == 0 || softc->ha_disconnect || 288 so->so_error || 289 (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { 290 goto errout; 291 } 292 so->so_rcv.sb_lowat = next; 293 msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), 294 0, "-", 0); 295 } 296 SOCKBUF_UNLOCK(&so->so_rcv); 297 298 if (wire_hdr.length == 0) { 299 iov.iov_base = &wire_hdr; 300 iov.iov_len = sizeof(wire_hdr); 301 uio.uio_iov = &iov; 302 uio.uio_iovcnt = 1; 303 uio.uio_rw = UIO_READ; 304 uio.uio_segflg = UIO_SYSSPACE; 305 uio.uio_td = curthread; 306 uio.uio_resid = sizeof(wire_hdr); 307 flags = MSG_DONTWAIT; 308 error = soreceive(softc->ha_so, NULL, &uio, NULL, 309 NULL, &flags); 310 if (error != 0) { 311 printf("%s: header receive error %d\n", 312 __func__, error); 313 SOCKBUF_LOCK(&so->so_rcv); 314 goto errout; 315 } 316 } else { 317 ctl_ha_evt(softc, wire_hdr.channel, 318 CTL_HA_EVT_MSG_RECV, wire_hdr.length); 319 wire_hdr.length = 0; 320 } 321 } 322 323errout: 324 softc->ha_receiving = 0; 325 wakeup(&softc->ha_receiving); 326 SOCKBUF_UNLOCK(&so->so_rcv); 327 ctl_ha_conn_wake(softc); 328 kthread_exit(); 329} 330 331static void 332ctl_ha_send(struct ha_softc *softc) 333{ 334 struct socket *so = softc->ha_so; 335 int error; 336 337 while (1) { 338 if (softc->ha_sending == NULL) { 339 mtx_lock(&softc->ha_lock); 340 softc->ha_sending = mbufq_dequeue(&softc->ha_sendq); 341 mtx_unlock(&softc->ha_lock); 342 if (softc->ha_sending == NULL) { 343 so->so_snd.sb_lowat = so->so_snd.sb_hiwat + 1; 344 break; 345 } 346 } 347 SOCKBUF_LOCK(&so->so_snd); 348 if (sbspace(&so->so_snd) < softc->ha_sending->m_pkthdr.len) { 349 so->so_snd.sb_lowat = softc->ha_sending->m_pkthdr.len; 350 SOCKBUF_UNLOCK(&so->so_snd); 351 break; 352 } 353 SOCKBUF_UNLOCK(&so->so_snd); 354 error = sosend(softc->ha_so, NULL, NULL, softc->ha_sending, 355 NULL, MSG_DONTWAIT, curthread); 356 softc->ha_sending = NULL; 357 if (error != 0) { 358 printf("%s: sosend() error %d\n", __func__, error); 359 return; 360 } 361 }; 362} 363 364static void 365ctl_ha_sock_setup(struct ha_softc *softc) 366{ 367 struct sockopt opt; 368 struct socket *so = softc->ha_so; 369 int error, val; 370 371 val = 1024 * 1024; 372 error = soreserve(so, val, val); 373 if (error) 374 printf("%s: soreserve failed %d\n", __func__, error); 375 376 SOCKBUF_LOCK(&so->so_rcv); 377 so->so_rcv.sb_lowat = sizeof(struct ha_msg_wire); 378 soupcall_set(so, SO_RCV, ctl_ha_rupcall, softc); 379 SOCKBUF_UNLOCK(&so->so_rcv); 380 SOCKBUF_LOCK(&so->so_snd); 381 so->so_snd.sb_lowat = sizeof(struct ha_msg_wire); 382 soupcall_set(so, SO_SND, ctl_ha_supcall, softc); 383 SOCKBUF_UNLOCK(&so->so_snd); 384 385 bzero(&opt, sizeof(struct sockopt)); 386 opt.sopt_dir = SOPT_SET; 387 opt.sopt_level = SOL_SOCKET; 388 opt.sopt_name = SO_KEEPALIVE; 389 opt.sopt_val = &val; 390 opt.sopt_valsize = sizeof(val); 391 val = 1; 392 error = sosetopt(so, &opt); 393 if (error) 394 printf("%s: KEEPALIVE setting failed %d\n", __func__, error); 395 396 opt.sopt_level = IPPROTO_TCP; 397 opt.sopt_name = TCP_NODELAY; 398 val = 1; 399 error = sosetopt(so, &opt); 400 if (error) 401 printf("%s: NODELAY setting failed %d\n", __func__, error); 402 403 opt.sopt_name = TCP_KEEPINIT; 404 val = 3; 405 error = sosetopt(so, &opt); 406 if (error) 407 printf("%s: KEEPINIT setting failed %d\n", __func__, error); 408 409 opt.sopt_name = TCP_KEEPIDLE; 410 val = 1; 411 error = sosetopt(so, &opt); 412 if (error) 413 printf("%s: KEEPIDLE setting failed %d\n", __func__, error); 414 415 opt.sopt_name = TCP_KEEPINTVL; 416 val = 1; 417 error = sosetopt(so, &opt); 418 if (error) 419 printf("%s: KEEPINTVL setting failed %d\n", __func__, error); 420 421 opt.sopt_name = TCP_KEEPCNT; 422 val = 5; 423 error = sosetopt(so, &opt); 424 if (error) 425 printf("%s: KEEPCNT setting failed %d\n", __func__, error); 426} 427 428static int 429ctl_ha_connect(struct ha_softc *softc) 430{ 431 struct thread *td = curthread; 432 struct socket *so; 433 int error; 434 435 /* Create the socket */ 436 error = socreate(PF_INET, &so, SOCK_STREAM, 437 IPPROTO_TCP, td->td_ucred, td); 438 if (error != 0) { 439 printf("%s: socreate() error %d\n", __func__, error); 440 return (error); 441 } 442 softc->ha_so = so; 443 ctl_ha_sock_setup(softc); 444 445 error = soconnect(so, (struct sockaddr *)&softc->ha_peer_in, td); 446 if (error != 0) { 447 printf("%s: soconnect() error %d\n", __func__, error); 448 goto out; 449 } 450 return (0); 451 452out: 453 ctl_ha_close(softc); 454 return (error); 455} 456 457static int 458ctl_ha_accept(struct ha_softc *softc) 459{ 460 struct socket *so; 461 struct sockaddr *sap; 462 int error; 463 464 ACCEPT_LOCK(); 465 if (softc->ha_lso->so_rcv.sb_state & SBS_CANTRCVMORE) 466 softc->ha_lso->so_error = ECONNABORTED; 467 if (softc->ha_lso->so_error) { 468 error = softc->ha_lso->so_error; 469 softc->ha_lso->so_error = 0; 470 ACCEPT_UNLOCK(); 471 printf("%s: socket error %d\n", __func__, error); 472 goto out; 473 } 474 so = TAILQ_FIRST(&softc->ha_lso->so_comp); 475 if (so == NULL) { 476 ACCEPT_UNLOCK(); 477 return (EWOULDBLOCK); 478 } 479 KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP")); 480 KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP")); 481 482 /* 483 * Before changing the flags on the socket, we have to bump the 484 * reference count. Otherwise, if the protocol calls sofree(), 485 * the socket will be released due to a zero refcount. 486 */ 487 SOCK_LOCK(so); /* soref() and so_state update */ 488 soref(so); /* file descriptor reference */ 489 490 TAILQ_REMOVE(&softc->ha_lso->so_comp, so, so_list); 491 softc->ha_lso->so_qlen--; 492 so->so_state |= SS_NBIO; 493 so->so_qstate &= ~SQ_COMP; 494 so->so_head = NULL; 495 496 SOCK_UNLOCK(so); 497 ACCEPT_UNLOCK(); 498 499 sap = NULL; 500 error = soaccept(so, &sap); 501 if (error != 0) { 502 printf("%s: soaccept() error %d\n", __func__, error); 503 if (sap != NULL) 504 free(sap, M_SONAME); 505 goto out; 506 } 507 if (sap != NULL) 508 free(sap, M_SONAME); 509 softc->ha_so = so; 510 ctl_ha_sock_setup(softc); 511 return (0); 512 513out: 514 ctl_ha_lclose(softc); 515 return (error); 516} 517 518static int 519ctl_ha_listen(struct ha_softc *softc) 520{ 521 struct thread *td = curthread; 522 struct sockopt opt; 523 int error, val; 524 525 /* Create the socket */ 526 if (softc->ha_lso == NULL) { 527 error = socreate(PF_INET, &softc->ha_lso, SOCK_STREAM, 528 IPPROTO_TCP, td->td_ucred, td); 529 if (error != 0) { 530 printf("%s: socreate() error %d\n", __func__, error); 531 return (error); 532 } 533 bzero(&opt, sizeof(struct sockopt)); 534 opt.sopt_dir = SOPT_SET; 535 opt.sopt_level = SOL_SOCKET; 536 opt.sopt_name = SO_REUSEADDR; 537 opt.sopt_val = &val; 538 opt.sopt_valsize = sizeof(val); 539 val = 1; 540 error = sosetopt(softc->ha_lso, &opt); 541 if (error) { 542 printf("%s: REUSEADDR setting failed %d\n", 543 __func__, error); 544 } 545 bzero(&opt, sizeof(struct sockopt)); 546 opt.sopt_dir = SOPT_SET; 547 opt.sopt_level = SOL_SOCKET; 548 opt.sopt_name = SO_REUSEPORT; 549 opt.sopt_val = &val; 550 opt.sopt_valsize = sizeof(val); 551 val = 1; 552 error = sosetopt(softc->ha_lso, &opt); 553 if (error) { 554 printf("%s: REUSEPORT setting failed %d\n", 555 __func__, error); 556 } 557 SOCKBUF_LOCK(&softc->ha_lso->so_rcv); 558 soupcall_set(softc->ha_lso, SO_RCV, ctl_ha_lupcall, softc); 559 SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); 560 } 561 562 error = sobind(softc->ha_lso, (struct sockaddr *)&softc->ha_peer_in, td); 563 if (error != 0) { 564 printf("%s: sobind() error %d\n", __func__, error); 565 goto out; 566 } 567 error = solisten(softc->ha_lso, 1, td); 568 if (error != 0) { 569 printf("%s: solisten() error %d\n", __func__, error); 570 goto out; 571 } 572 return (0); 573 574out: 575 ctl_ha_lclose(softc); 576 return (error); 577} 578 579static void 580ctl_ha_conn_thread(void *arg) 581{ 582 struct ha_softc *softc = arg; 583 int error; 584 585 while (1) { 586 if (softc->ha_disconnect || softc->ha_shutdown) { 587 ctl_ha_close(softc); 588 if (softc->ha_disconnect == 2 || softc->ha_shutdown) 589 ctl_ha_lclose(softc); 590 softc->ha_disconnect = 0; 591 if (softc->ha_shutdown) 592 break; 593 } else if (softc->ha_so != NULL && 594 (softc->ha_so->so_error || 595 softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) 596 ctl_ha_close(softc); 597 if (softc->ha_so == NULL) { 598 if (softc->ha_lso != NULL) 599 ctl_ha_accept(softc); 600 else if (softc->ha_listen) 601 ctl_ha_listen(softc); 602 else if (softc->ha_connect) 603 ctl_ha_connect(softc); 604 } 605 if (softc->ha_so != NULL) { 606 if (softc->ha_connected == 0 && 607 softc->ha_so->so_error == 0 && 608 (softc->ha_so->so_state & SS_ISCONNECTING) == 0) { 609 softc->ha_connected = 1; 610 ctl_ha_evt(softc, CTL_HA_CHAN_MAX, 611 CTL_HA_EVT_LINK_CHANGE, 612 CTL_HA_LINK_ONLINE); 613 softc->ha_receiving = 1; 614 error = kproc_kthread_add(ctl_ha_rx_thread, 615 softc, &softc->ha_ctl_softc->ctl_proc, 616 NULL, 0, 0, "ctl", "ha_rx"); 617 if (error != 0) { 618 printf("Error creating CTL HA rx thread!\n"); 619 softc->ha_receiving = 0; 620 softc->ha_disconnect = 1; 621 } 622 } 623 ctl_ha_send(softc); 624 } 625 mtx_lock(&softc->ha_lock); 626 if (softc->ha_so != NULL && 627 (softc->ha_so->so_error || 628 softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) 629 ; 630 else if (!softc->ha_wakeup) 631 msleep(&softc->ha_wakeup, &softc->ha_lock, 0, "-", hz); 632 softc->ha_wakeup = 0; 633 mtx_unlock(&softc->ha_lock); 634 } 635 mtx_lock(&softc->ha_lock); 636 softc->ha_shutdown = 2; 637 wakeup(&softc->ha_wakeup); 638 mtx_unlock(&softc->ha_lock); 639 kthread_exit(); 640} 641 642static int 643ctl_ha_peer_sysctl(SYSCTL_HANDLER_ARGS) 644{ 645 struct ha_softc *softc = (struct ha_softc *)arg1; 646 struct sockaddr_in *sa; 647 int error, b1, b2, b3, b4, p, num; 648 char buf[128]; 649 650 strlcpy(buf, softc->ha_peer, sizeof(buf)); 651 error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 652 if ((error != 0) || (req->newptr == NULL) || 653 strncmp(buf, softc->ha_peer, sizeof(buf)) == 0) 654 return (error); 655 656 sa = &softc->ha_peer_in; 657 mtx_lock(&softc->ha_lock); 658 if ((num = sscanf(buf, "connect %d.%d.%d.%d:%d", 659 &b1, &b2, &b3, &b4, &p)) >= 4) { 660 softc->ha_connect = 1; 661 softc->ha_listen = 0; 662 } else if ((num = sscanf(buf, "listen %d.%d.%d.%d:%d", 663 &b1, &b2, &b3, &b4, &p)) >= 4) { 664 softc->ha_connect = 0; 665 softc->ha_listen = 1; 666 } else { 667 softc->ha_connect = 0; 668 softc->ha_listen = 0; 669 if (buf[0] != 0) { 670 buf[0] = 0; 671 error = EINVAL; 672 } 673 } 674 strlcpy(softc->ha_peer, buf, sizeof(softc->ha_peer)); 675 if (softc->ha_connect || softc->ha_listen) { 676 memset(sa, 0, sizeof(*sa)); 677 sa->sin_len = sizeof(struct sockaddr_in); 678 sa->sin_family = AF_INET; 679 sa->sin_port = htons((num >= 5) ? p : 999); 680 sa->sin_addr.s_addr = 681 htonl((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); 682 } 683 softc->ha_disconnect = 2; 684 softc->ha_wakeup = 1; 685 mtx_unlock(&softc->ha_lock); 686 wakeup(&softc->ha_wakeup); 687 return (error); 688} 689 690ctl_ha_status 691ctl_ha_msg_register(ctl_ha_channel channel, ctl_evt_handler handler) 692{ 693 struct ha_softc *softc = &ha_softc; 694 695 KASSERT(channel < CTL_HA_CHAN_MAX, 696 ("Wrong CTL HA channel %d", channel)); 697 softc->ha_handler[channel] = handler; 698 return (CTL_HA_STATUS_SUCCESS); 699} 700 701ctl_ha_status 702ctl_ha_msg_deregister(ctl_ha_channel channel) 703{ 704 struct ha_softc *softc = &ha_softc; 705 706 KASSERT(channel < CTL_HA_CHAN_MAX, 707 ("Wrong CTL HA channel %d", channel)); 708 softc->ha_handler[channel] = NULL; 709 return (CTL_HA_STATUS_SUCCESS); 710} 711 712/* 713 * Receive a message of the specified size. 714 */ 715ctl_ha_status 716ctl_ha_msg_recv(ctl_ha_channel channel, void *addr, size_t len, 717 int wait) 718{ 719 struct ha_softc *softc = &ha_softc; 720 struct uio uio; 721 struct iovec iov; 722 int error, flags; 723 724 if (!softc->ha_connected) 725 return (CTL_HA_STATUS_DISCONNECT); 726 727 iov.iov_base = addr; 728 iov.iov_len = len; 729 uio.uio_iov = &iov; 730 uio.uio_iovcnt = 1; 731 uio.uio_rw = UIO_READ; 732 uio.uio_segflg = UIO_SYSSPACE; 733 uio.uio_td = curthread; 734 uio.uio_resid = len; 735 flags = wait ? 0 : MSG_DONTWAIT; 736 error = soreceive(softc->ha_so, NULL, &uio, NULL, NULL, &flags); 737 if (error == 0) 738 return (CTL_HA_STATUS_SUCCESS); 739 740 /* Consider all errors fatal for HA sanity. */ 741 mtx_lock(&softc->ha_lock); 742 if (softc->ha_connected) { 743 softc->ha_disconnect = 1; 744 softc->ha_wakeup = 1; 745 wakeup(&softc->ha_wakeup); 746 } 747 mtx_unlock(&softc->ha_lock); 748 return (CTL_HA_STATUS_ERROR); 749} 750 751/* 752 * Send a message of the specified size. 753 */ 754ctl_ha_status 755ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr, size_t len, 756 const void *addr2, size_t len2, int wait) 757{ 758 struct ha_softc *softc = &ha_softc; 759 struct mbuf *mb, *newmb; 760 struct ha_msg_wire hdr; 761 size_t copylen, off; 762 763 if (!softc->ha_connected) 764 return (CTL_HA_STATUS_DISCONNECT); 765 766 newmb = m_getm2(NULL, sizeof(hdr) + len + len2, wait, MT_DATA, 767 M_PKTHDR); 768 if (newmb == NULL) { 769 /* Consider all errors fatal for HA sanity. */ 770 mtx_lock(&softc->ha_lock); 771 if (softc->ha_connected) { 772 softc->ha_disconnect = 1; 773 softc->ha_wakeup = 1; 774 wakeup(&softc->ha_wakeup); 775 } 776 mtx_unlock(&softc->ha_lock); 777 printf("%s: Can't allocate mbuf chain\n", __func__); 778 return (CTL_HA_STATUS_ERROR); 779 } 780 hdr.channel = channel; 781 hdr.length = len + len2; 782 mb = newmb; 783 memcpy(mtodo(mb, 0), &hdr, sizeof(hdr)); 784 mb->m_len += sizeof(hdr); 785 off = 0; 786 for (; mb != NULL && off < len; mb = mb->m_next) { 787 copylen = min(M_TRAILINGSPACE(mb), len - off); 788 memcpy(mtodo(mb, mb->m_len), (const char *)addr + off, copylen); 789 mb->m_len += copylen; 790 off += copylen; 791 if (off == len) 792 break; 793 } 794 KASSERT(off == len, ("%s: off (%zu) != len (%zu)", __func__, 795 off, len)); 796 off = 0; 797 for (; mb != NULL && off < len2; mb = mb->m_next) { 798 copylen = min(M_TRAILINGSPACE(mb), len2 - off); 799 memcpy(mtodo(mb, mb->m_len), (const char *)addr2 + off, copylen); 800 mb->m_len += copylen; 801 off += copylen; 802 } 803 KASSERT(off == len2, ("%s: off (%zu) != len2 (%zu)", __func__, 804 off, len2)); 805 newmb->m_pkthdr.len = sizeof(hdr) + len + len2; 806 807 mtx_lock(&softc->ha_lock); 808 if (!softc->ha_connected) { 809 mtx_unlock(&softc->ha_lock); 810 m_freem(newmb); 811 return (CTL_HA_STATUS_DISCONNECT); 812 } 813 mbufq_enqueue(&softc->ha_sendq, newmb); 814 softc->ha_wakeup = 1; 815 mtx_unlock(&softc->ha_lock); 816 wakeup(&softc->ha_wakeup); 817 return (CTL_HA_STATUS_SUCCESS); 818} 819 820ctl_ha_status 821ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, size_t len, 822 int wait) 823{ 824 825 return (ctl_ha_msg_send2(channel, addr, len, NULL, 0, wait)); 826} 827 828ctl_ha_status 829ctl_ha_msg_abort(ctl_ha_channel channel) 830{ 831 struct ha_softc *softc = &ha_softc; 832 833 mtx_lock(&softc->ha_lock); 834 softc->ha_disconnect = 1; 835 softc->ha_wakeup = 1; 836 mtx_unlock(&softc->ha_lock); 837 wakeup(&softc->ha_wakeup); 838 return (CTL_HA_STATUS_SUCCESS); 839} 840 841/* 842 * Allocate a data transfer request structure. 843 */ 844struct ctl_ha_dt_req * 845ctl_dt_req_alloc(void) 846{ 847 848 return (malloc(sizeof(struct ctl_ha_dt_req), M_CTL, M_WAITOK | M_ZERO)); 849} 850 851/* 852 * Free a data transfer request structure. 853 */ 854void 855ctl_dt_req_free(struct ctl_ha_dt_req *req) 856{ 857 858 free(req, M_CTL); 859} 860 861/* 862 * Issue a DMA request for a single buffer. 863 */ 864ctl_ha_status 865ctl_dt_single(struct ctl_ha_dt_req *req) 866{ 867 struct ha_softc *softc = &ha_softc; 868 struct ha_dt_msg_wire wire_dt; 869 ctl_ha_status status; 870 871 wire_dt.command = req->command; 872 wire_dt.size = req->size; 873 wire_dt.local = req->local; 874 wire_dt.remote = req->remote; 875 if (req->command == CTL_HA_DT_CMD_READ && req->callback != NULL) { 876 mtx_lock(&softc->ha_lock); 877 TAILQ_INSERT_TAIL(&softc->ha_dts, req, links); 878 mtx_unlock(&softc->ha_lock); 879 ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, sizeof(wire_dt), 880 M_WAITOK); 881 return (CTL_HA_STATUS_WAIT); 882 } 883 if (req->command == CTL_HA_DT_CMD_READ) { 884 status = ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, 885 sizeof(wire_dt), M_WAITOK); 886 } else { 887 status = ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, 888 sizeof(wire_dt), req->local, req->size, M_WAITOK); 889 } 890 return (status); 891} 892 893static void 894ctl_dt_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) 895{ 896 struct ha_softc *softc = &ha_softc; 897 struct ctl_ha_dt_req *req; 898 ctl_ha_status isc_status; 899 900 if (event == CTL_HA_EVT_MSG_RECV) { 901 struct ha_dt_msg_wire wire_dt; 902 uint8_t *tmp; 903 int size; 904 905 size = min(sizeof(wire_dt), param); 906 isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, &wire_dt, 907 size, M_WAITOK); 908 if (isc_status != CTL_HA_STATUS_SUCCESS) { 909 printf("%s: Error receiving message: %d\n", 910 __func__, isc_status); 911 return; 912 } 913 914 if (wire_dt.command == CTL_HA_DT_CMD_READ) { 915 wire_dt.command = CTL_HA_DT_CMD_WRITE; 916 tmp = wire_dt.local; 917 wire_dt.local = wire_dt.remote; 918 wire_dt.remote = tmp; 919 ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, 920 sizeof(wire_dt), wire_dt.local, wire_dt.size, 921 M_WAITOK); 922 } else if (wire_dt.command == CTL_HA_DT_CMD_WRITE) { 923 isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, 924 wire_dt.remote, wire_dt.size, M_WAITOK); 925 mtx_lock(&softc->ha_lock); 926 TAILQ_FOREACH(req, &softc->ha_dts, links) { 927 if (req->local == wire_dt.remote) { 928 TAILQ_REMOVE(&softc->ha_dts, req, links); 929 break; 930 } 931 } 932 mtx_unlock(&softc->ha_lock); 933 if (req) { 934 req->ret = isc_status; 935 req->callback(req); 936 } 937 } 938 } else if (event == CTL_HA_EVT_LINK_CHANGE) { 939 CTL_DEBUG_PRINT(("%s: Link state change to %d\n", __func__, 940 param)); 941 if (param != CTL_HA_LINK_ONLINE) { 942 mtx_lock(&softc->ha_lock); 943 while ((req = TAILQ_FIRST(&softc->ha_dts)) != NULL) { 944 TAILQ_REMOVE(&softc->ha_dts, req, links); 945 mtx_unlock(&softc->ha_lock); 946 req->ret = CTL_HA_STATUS_DISCONNECT; 947 req->callback(req); 948 mtx_lock(&softc->ha_lock); 949 } 950 mtx_unlock(&softc->ha_lock); 951 } 952 } else { 953 printf("%s: Unknown event %d\n", __func__, event); 954 } 955} 956 957 958ctl_ha_status 959ctl_ha_msg_init(struct ctl_softc *ctl_softc) 960{ 961 struct ha_softc *softc = &ha_softc; 962 int error; 963 964 softc->ha_ctl_softc = ctl_softc; 965 mtx_init(&softc->ha_lock, "CTL HA mutex", NULL, MTX_DEF); 966 mbufq_init(&softc->ha_sendq, INT_MAX); 967 TAILQ_INIT(&softc->ha_dts); 968 error = kproc_kthread_add(ctl_ha_conn_thread, softc, 969 &ctl_softc->ctl_proc, NULL, 0, 0, "ctl", "ha_tx"); 970 if (error != 0) { 971 printf("error creating CTL HA connection thread!\n"); 972 mtx_destroy(&softc->ha_lock); 973 return (CTL_HA_STATUS_ERROR); 974 } 975 softc->ha_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, 976 ctl_ha_msg_shutdown, ctl_softc, SHUTDOWN_PRI_FIRST); 977 SYSCTL_ADD_PROC(&ctl_softc->sysctl_ctx, 978 SYSCTL_CHILDREN(ctl_softc->sysctl_tree), 979 OID_AUTO, "ha_peer", CTLTYPE_STRING | CTLFLAG_RWTUN, 980 softc, 0, ctl_ha_peer_sysctl, "A", "HA peer connection method"); 981 982 if (ctl_ha_msg_register(CTL_HA_CHAN_DATA, ctl_dt_event_handler) 983 != CTL_HA_STATUS_SUCCESS) { 984 printf("%s: ctl_ha_msg_register failed.\n", __func__); 985 } 986 987 return (CTL_HA_STATUS_SUCCESS); 988}; 989 990void 991ctl_ha_msg_shutdown(struct ctl_softc *ctl_softc) 992{ 993 struct ha_softc *softc = &ha_softc; 994 995 /* Disconnect and shutdown threads. */ 996 mtx_lock(&softc->ha_lock); 997 if (softc->ha_shutdown < 2) { 998 softc->ha_shutdown = 1; 999 softc->ha_wakeup = 1; 1000 wakeup(&softc->ha_wakeup); 1001 while (softc->ha_shutdown < 2) { 1002 msleep(&softc->ha_wakeup, &softc->ha_lock, 0, 1003 "shutdown", hz); 1004 } 1005 } 1006 mtx_unlock(&softc->ha_lock); 1007}; 1008 1009ctl_ha_status 1010ctl_ha_msg_destroy(struct ctl_softc *ctl_softc) 1011{ 1012 struct ha_softc *softc = &ha_softc; 1013 1014 if (softc->ha_shutdown_eh != NULL) { 1015 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, 1016 softc->ha_shutdown_eh); 1017 softc->ha_shutdown_eh = NULL; 1018 } 1019 1020 ctl_ha_msg_shutdown(ctl_softc); /* Just in case. */ 1021 1022 if (ctl_ha_msg_deregister(CTL_HA_CHAN_DATA) != CTL_HA_STATUS_SUCCESS) 1023 printf("%s: ctl_ha_msg_deregister failed.\n", __func__); 1024 1025 mtx_destroy(&softc->ha_lock); 1026 return (CTL_HA_STATUS_SUCCESS); 1027}; 1028