17ac58230SAlexander Motin /*- 27ac58230SAlexander Motin * Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org> 37ac58230SAlexander Motin * All rights reserved. 47ac58230SAlexander Motin * 57ac58230SAlexander Motin * Redistribution and use in source and binary forms, with or without 67ac58230SAlexander Motin * modification, are permitted provided that the following conditions 77ac58230SAlexander Motin * are met: 87ac58230SAlexander Motin * 1. Redistributions of source code must retain the above copyright 97ac58230SAlexander Motin * notice, this list of conditions and the following disclaimer, 107ac58230SAlexander Motin * without modification, immediately at the beginning of the file. 117ac58230SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 127ac58230SAlexander Motin * notice, this list of conditions and the following disclaimer in the 137ac58230SAlexander Motin * documentation and/or other materials provided with the distribution. 147ac58230SAlexander Motin * 157ac58230SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 167ac58230SAlexander Motin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 177ac58230SAlexander Motin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 187ac58230SAlexander Motin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 197ac58230SAlexander Motin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 207ac58230SAlexander Motin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 217ac58230SAlexander Motin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 227ac58230SAlexander Motin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 237ac58230SAlexander Motin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 247ac58230SAlexander Motin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 257ac58230SAlexander Motin */ 267ac58230SAlexander Motin 277ac58230SAlexander Motin #include <sys/cdefs.h> 287ac58230SAlexander Motin __FBSDID("$FreeBSD$"); 297ac58230SAlexander Motin 307ac58230SAlexander Motin #include <sys/param.h> 317ac58230SAlexander Motin #include <sys/systm.h> 327ac58230SAlexander Motin #include <sys/kernel.h> 337ac58230SAlexander Motin #include <sys/kthread.h> 347ac58230SAlexander Motin #include <sys/types.h> 357ac58230SAlexander Motin #include <sys/limits.h> 367ac58230SAlexander Motin #include <sys/lock.h> 377ac58230SAlexander Motin #include <sys/module.h> 387ac58230SAlexander Motin #include <sys/mutex.h> 397ac58230SAlexander Motin #include <sys/condvar.h> 407ac58230SAlexander Motin #include <sys/malloc.h> 417ac58230SAlexander Motin #include <sys/mbuf.h> 427ac58230SAlexander Motin #include <sys/proc.h> 437ac58230SAlexander Motin #include <sys/conf.h> 447ac58230SAlexander Motin #include <sys/queue.h> 457ac58230SAlexander Motin #include <sys/sysctl.h> 467ac58230SAlexander Motin #include <sys/socket.h> 477ac58230SAlexander Motin #include <sys/socketvar.h> 487ac58230SAlexander Motin #include <sys/uio.h> 497ac58230SAlexander Motin #include <netinet/in.h> 507ac58230SAlexander Motin #include <netinet/tcp.h> 517ac58230SAlexander Motin #include <vm/uma.h> 527ac58230SAlexander Motin 537ac58230SAlexander Motin #include <cam/cam.h> 547ac58230SAlexander Motin #include <cam/scsi/scsi_all.h> 557ac58230SAlexander Motin #include <cam/scsi/scsi_da.h> 567ac58230SAlexander Motin #include <cam/ctl/ctl_io.h> 577ac58230SAlexander Motin #include <cam/ctl/ctl.h> 587ac58230SAlexander Motin #include <cam/ctl/ctl_frontend.h> 597ac58230SAlexander Motin #include <cam/ctl/ctl_util.h> 607ac58230SAlexander Motin #include <cam/ctl/ctl_backend.h> 617ac58230SAlexander Motin #include <cam/ctl/ctl_ioctl.h> 627ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h> 637ac58230SAlexander Motin #include <cam/ctl/ctl_private.h> 647ac58230SAlexander Motin #include <cam/ctl/ctl_debug.h> 657ac58230SAlexander Motin #include <cam/ctl/ctl_error.h> 667ac58230SAlexander Motin 677ac58230SAlexander Motin #if (__FreeBSD_version < 1100000) 687ac58230SAlexander Motin struct mbufq { 697ac58230SAlexander Motin struct mbuf *head; 707ac58230SAlexander Motin struct mbuf *tail; 717ac58230SAlexander Motin }; 727ac58230SAlexander Motin 737ac58230SAlexander Motin static void 747ac58230SAlexander Motin mbufq_init(struct mbufq *q, int limit) 757ac58230SAlexander Motin { 767ac58230SAlexander Motin 777ac58230SAlexander Motin q->head = q->tail = NULL; 787ac58230SAlexander Motin } 797ac58230SAlexander Motin 807ac58230SAlexander Motin static void 817ac58230SAlexander Motin mbufq_drain(struct mbufq *q) 827ac58230SAlexander Motin { 837ac58230SAlexander Motin struct mbuf *m; 847ac58230SAlexander Motin 857ac58230SAlexander Motin while ((m = q->head) != NULL) { 867ac58230SAlexander Motin q->head = m->m_nextpkt; 877ac58230SAlexander Motin m_freem(m); 887ac58230SAlexander Motin } 897ac58230SAlexander Motin q->tail = NULL; 907ac58230SAlexander Motin } 917ac58230SAlexander Motin 927ac58230SAlexander Motin static struct mbuf * 937ac58230SAlexander Motin mbufq_dequeue(struct mbufq *q) 947ac58230SAlexander Motin { 957ac58230SAlexander Motin struct mbuf *m; 967ac58230SAlexander Motin 977ac58230SAlexander Motin m = q->head; 987ac58230SAlexander Motin if (m) { 997ac58230SAlexander Motin if (q->tail == m) 1007ac58230SAlexander Motin q->tail = NULL; 1017ac58230SAlexander Motin q->head = m->m_nextpkt; 1027ac58230SAlexander Motin m->m_nextpkt = NULL; 1037ac58230SAlexander Motin } 1047ac58230SAlexander Motin return (m); 1057ac58230SAlexander Motin } 1067ac58230SAlexander Motin 1077ac58230SAlexander Motin static void 1087ac58230SAlexander Motin mbufq_enqueue(struct mbufq *q, struct mbuf *m) 1097ac58230SAlexander Motin { 1107ac58230SAlexander Motin 1117ac58230SAlexander Motin m->m_nextpkt = NULL; 1127ac58230SAlexander Motin if (q->tail) 1137ac58230SAlexander Motin q->tail->m_nextpkt = m; 1147ac58230SAlexander Motin else 1157ac58230SAlexander Motin q->head = m; 1167ac58230SAlexander Motin q->tail = m; 1177ac58230SAlexander Motin } 1187ac58230SAlexander Motin 1197ac58230SAlexander Motin static u_int 1207ac58230SAlexander Motin sbavail(struct sockbuf *sb) 1217ac58230SAlexander Motin { 1227ac58230SAlexander Motin return (sb->sb_cc); 1237ac58230SAlexander Motin } 1247ac58230SAlexander Motin 1257ac58230SAlexander Motin #if (__FreeBSD_version < 1000000) 1267ac58230SAlexander Motin #define mtodo(m, o) ((void *)(((m)->m_data) + (o))) 1277ac58230SAlexander Motin #endif 1287ac58230SAlexander Motin #endif 1297ac58230SAlexander Motin 1307ac58230SAlexander Motin struct ha_msg_wire { 1317ac58230SAlexander Motin uint32_t channel; 1327ac58230SAlexander Motin uint32_t length; 1337ac58230SAlexander Motin }; 1347ac58230SAlexander Motin 1357ac58230SAlexander Motin struct ha_dt_msg_wire { 1367ac58230SAlexander Motin ctl_ha_dt_cmd command; 1377ac58230SAlexander Motin uint32_t size; 1387ac58230SAlexander Motin uint8_t *local; 1397ac58230SAlexander Motin uint8_t *remote; 1407ac58230SAlexander Motin }; 1417ac58230SAlexander Motin 1427ac58230SAlexander Motin struct ha_softc { 1437ac58230SAlexander Motin struct ctl_softc *ha_ctl_softc; 1447ac58230SAlexander Motin ctl_evt_handler ha_handler[CTL_HA_CHAN_MAX]; 1457ac58230SAlexander Motin char ha_peer[128]; 1467ac58230SAlexander Motin struct sockaddr_in ha_peer_in; 1477ac58230SAlexander Motin struct socket *ha_lso; 1487ac58230SAlexander Motin struct socket *ha_so; 1497ac58230SAlexander Motin struct mbufq ha_sendq; 1507ac58230SAlexander Motin struct mbuf *ha_sending; 1517ac58230SAlexander Motin struct mtx ha_lock; 1527ac58230SAlexander Motin int ha_connect; 1537ac58230SAlexander Motin int ha_listen; 1547ac58230SAlexander Motin int ha_connected; 1557ac58230SAlexander Motin int ha_receiving; 1567ac58230SAlexander Motin int ha_wakeup; 1577ac58230SAlexander Motin int ha_disconnect; 15859bb97a9SAlexander Motin int ha_shutdown; 15959bb97a9SAlexander Motin eventhandler_tag ha_shutdown_eh; 1607ac58230SAlexander Motin TAILQ_HEAD(, ctl_ha_dt_req) ha_dts; 1617ac58230SAlexander Motin } ha_softc; 1627ac58230SAlexander Motin 1637ac58230SAlexander Motin static void 1647ac58230SAlexander Motin ctl_ha_conn_wake(struct ha_softc *softc) 1657ac58230SAlexander Motin { 1667ac58230SAlexander Motin 1677ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 1687ac58230SAlexander Motin softc->ha_wakeup = 1; 1697ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 1707ac58230SAlexander Motin wakeup(&softc->ha_wakeup); 1717ac58230SAlexander Motin } 1727ac58230SAlexander Motin 1737ac58230SAlexander Motin static int 1747ac58230SAlexander Motin ctl_ha_lupcall(struct socket *so, void *arg, int waitflag) 1757ac58230SAlexander Motin { 1767ac58230SAlexander Motin struct ha_softc *softc = arg; 1777ac58230SAlexander Motin 1787ac58230SAlexander Motin ctl_ha_conn_wake(softc); 1797ac58230SAlexander Motin return (SU_OK); 1807ac58230SAlexander Motin } 1817ac58230SAlexander Motin 1827ac58230SAlexander Motin static int 1837ac58230SAlexander Motin ctl_ha_rupcall(struct socket *so, void *arg, int waitflag) 1847ac58230SAlexander Motin { 1857ac58230SAlexander Motin struct ha_softc *softc = arg; 1867ac58230SAlexander Motin 1877ac58230SAlexander Motin wakeup(&softc->ha_receiving); 1887ac58230SAlexander Motin return (SU_OK); 1897ac58230SAlexander Motin } 1907ac58230SAlexander Motin 1917ac58230SAlexander Motin static int 1927ac58230SAlexander Motin ctl_ha_supcall(struct socket *so, void *arg, int waitflag) 1937ac58230SAlexander Motin { 1947ac58230SAlexander Motin struct ha_softc *softc = arg; 1957ac58230SAlexander Motin 1967ac58230SAlexander Motin ctl_ha_conn_wake(softc); 1977ac58230SAlexander Motin return (SU_OK); 1987ac58230SAlexander Motin } 1997ac58230SAlexander Motin 2007ac58230SAlexander Motin static void 2017ac58230SAlexander Motin ctl_ha_evt(struct ha_softc *softc, ctl_ha_channel ch, ctl_ha_event evt, 2027ac58230SAlexander Motin int param) 2037ac58230SAlexander Motin { 2047ac58230SAlexander Motin int i; 2057ac58230SAlexander Motin 2067ac58230SAlexander Motin if (ch < CTL_HA_CHAN_MAX) { 2077ac58230SAlexander Motin if (softc->ha_handler[ch]) 2087ac58230SAlexander Motin softc->ha_handler[ch](ch, evt, param); 2097ac58230SAlexander Motin return; 2107ac58230SAlexander Motin } 2117ac58230SAlexander Motin for (i = 0; i < CTL_HA_CHAN_MAX; i++) { 2127ac58230SAlexander Motin if (softc->ha_handler[i]) 2137ac58230SAlexander Motin softc->ha_handler[i](i, evt, param); 2147ac58230SAlexander Motin } 2157ac58230SAlexander Motin } 2167ac58230SAlexander Motin 2177ac58230SAlexander Motin static void 2187ac58230SAlexander Motin ctl_ha_close(struct ha_softc *softc) 2197ac58230SAlexander Motin { 2207ac58230SAlexander Motin struct socket *so = softc->ha_so; 2217ac58230SAlexander Motin int report = 0; 2227ac58230SAlexander Motin 2237ac58230SAlexander Motin if (softc->ha_connected || softc->ha_disconnect) { 2247ac58230SAlexander Motin softc->ha_connected = 0; 2257ac58230SAlexander Motin mbufq_drain(&softc->ha_sendq); 2267ac58230SAlexander Motin m_freem(softc->ha_sending); 2277ac58230SAlexander Motin softc->ha_sending = NULL; 2287ac58230SAlexander Motin report = 1; 2297ac58230SAlexander Motin } 2307ac58230SAlexander Motin if (so) { 2317ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_rcv); 2327ac58230SAlexander Motin soupcall_clear(so, SO_RCV); 2337ac58230SAlexander Motin while (softc->ha_receiving) { 2347ac58230SAlexander Motin wakeup(&softc->ha_receiving); 2357ac58230SAlexander Motin msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), 2367ac58230SAlexander Motin 0, "ha_rx exit", 0); 2377ac58230SAlexander Motin } 2387ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_rcv); 2397ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_snd); 2407ac58230SAlexander Motin soupcall_clear(so, SO_SND); 2417ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_snd); 2427ac58230SAlexander Motin softc->ha_so = NULL; 2437ac58230SAlexander Motin if (softc->ha_connect) 2447ac58230SAlexander Motin pause("reconnect", hz / 2); 2457ac58230SAlexander Motin soclose(so); 2467ac58230SAlexander Motin } 2477ac58230SAlexander Motin if (report) { 2487ac58230SAlexander Motin ctl_ha_evt(softc, CTL_HA_CHAN_MAX, CTL_HA_EVT_LINK_CHANGE, 2497ac58230SAlexander Motin (softc->ha_connect || softc->ha_listen) ? 2507ac58230SAlexander Motin CTL_HA_LINK_UNKNOWN : CTL_HA_LINK_OFFLINE); 2517ac58230SAlexander Motin } 2527ac58230SAlexander Motin } 2537ac58230SAlexander Motin 2547ac58230SAlexander Motin static void 2557ac58230SAlexander Motin ctl_ha_lclose(struct ha_softc *softc) 2567ac58230SAlexander Motin { 2577ac58230SAlexander Motin 2587ac58230SAlexander Motin if (softc->ha_lso) { 2597ac58230SAlexander Motin SOCKBUF_LOCK(&softc->ha_lso->so_rcv); 2607ac58230SAlexander Motin soupcall_clear(softc->ha_lso, SO_RCV); 2617ac58230SAlexander Motin SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); 2627ac58230SAlexander Motin soclose(softc->ha_lso); 2637ac58230SAlexander Motin softc->ha_lso = NULL; 2647ac58230SAlexander Motin } 2657ac58230SAlexander Motin } 2667ac58230SAlexander Motin 2677ac58230SAlexander Motin static void 2687ac58230SAlexander Motin ctl_ha_rx_thread(void *arg) 2697ac58230SAlexander Motin { 2707ac58230SAlexander Motin struct ha_softc *softc = arg; 2717ac58230SAlexander Motin struct socket *so = softc->ha_so; 2727ac58230SAlexander Motin struct ha_msg_wire wire_hdr; 2737ac58230SAlexander Motin struct uio uio; 2747ac58230SAlexander Motin struct iovec iov; 2757ac58230SAlexander Motin int error, flags, next; 2767ac58230SAlexander Motin 2777ac58230SAlexander Motin bzero(&wire_hdr, sizeof(wire_hdr)); 2787ac58230SAlexander Motin while (1) { 2797ac58230SAlexander Motin if (wire_hdr.length > 0) 2807ac58230SAlexander Motin next = wire_hdr.length; 2817ac58230SAlexander Motin else 2827ac58230SAlexander Motin next = sizeof(wire_hdr); 2837ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_rcv); 284a85700a9SAlexander Motin while (sbavail(&so->so_rcv) < next || softc->ha_disconnect) { 285a85700a9SAlexander Motin if (softc->ha_connected == 0 || softc->ha_disconnect || 286a85700a9SAlexander Motin so->so_error || 2877ac58230SAlexander Motin (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { 2887ac58230SAlexander Motin goto errout; 2897ac58230SAlexander Motin } 2907ac58230SAlexander Motin so->so_rcv.sb_lowat = next; 2917ac58230SAlexander Motin msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), 2927ac58230SAlexander Motin 0, "-", 0); 2937ac58230SAlexander Motin } 2947ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_rcv); 2957ac58230SAlexander Motin 2967ac58230SAlexander Motin if (wire_hdr.length == 0) { 2977ac58230SAlexander Motin iov.iov_base = &wire_hdr; 2987ac58230SAlexander Motin iov.iov_len = sizeof(wire_hdr); 2997ac58230SAlexander Motin uio.uio_iov = &iov; 3007ac58230SAlexander Motin uio.uio_iovcnt = 1; 3017ac58230SAlexander Motin uio.uio_rw = UIO_READ; 3027ac58230SAlexander Motin uio.uio_segflg = UIO_SYSSPACE; 3037ac58230SAlexander Motin uio.uio_td = curthread; 3047ac58230SAlexander Motin uio.uio_resid = sizeof(wire_hdr); 3057ac58230SAlexander Motin flags = MSG_DONTWAIT; 3067ac58230SAlexander Motin error = soreceive(softc->ha_so, NULL, &uio, NULL, 3077ac58230SAlexander Motin NULL, &flags); 3087ac58230SAlexander Motin if (error != 0) { 3097ac58230SAlexander Motin printf("%s: header receive error %d\n", 3107ac58230SAlexander Motin __func__, error); 3117ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_rcv); 3127ac58230SAlexander Motin goto errout; 3137ac58230SAlexander Motin } 3147ac58230SAlexander Motin } else { 3157ac58230SAlexander Motin ctl_ha_evt(softc, wire_hdr.channel, 3167ac58230SAlexander Motin CTL_HA_EVT_MSG_RECV, wire_hdr.length); 3177ac58230SAlexander Motin wire_hdr.length = 0; 3187ac58230SAlexander Motin } 3197ac58230SAlexander Motin } 3207ac58230SAlexander Motin 3217ac58230SAlexander Motin errout: 3227ac58230SAlexander Motin softc->ha_receiving = 0; 3237ac58230SAlexander Motin wakeup(&softc->ha_receiving); 3247ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_rcv); 3257ac58230SAlexander Motin ctl_ha_conn_wake(softc); 3267ac58230SAlexander Motin kthread_exit(); 3277ac58230SAlexander Motin } 3287ac58230SAlexander Motin 3297ac58230SAlexander Motin static void 3307ac58230SAlexander Motin ctl_ha_send(struct ha_softc *softc) 3317ac58230SAlexander Motin { 3327ac58230SAlexander Motin struct socket *so = softc->ha_so; 3337ac58230SAlexander Motin int error; 3347ac58230SAlexander Motin 3357ac58230SAlexander Motin while (1) { 3367ac58230SAlexander Motin if (softc->ha_sending == NULL) { 3377ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 3387ac58230SAlexander Motin softc->ha_sending = mbufq_dequeue(&softc->ha_sendq); 3397ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 3407ac58230SAlexander Motin if (softc->ha_sending == NULL) { 3417ac58230SAlexander Motin so->so_snd.sb_lowat = so->so_snd.sb_hiwat + 1; 3427ac58230SAlexander Motin break; 3437ac58230SAlexander Motin } 3447ac58230SAlexander Motin } 3457ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_snd); 3467ac58230SAlexander Motin if (sbspace(&so->so_snd) < softc->ha_sending->m_pkthdr.len) { 3477ac58230SAlexander Motin so->so_snd.sb_lowat = softc->ha_sending->m_pkthdr.len; 3487ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_snd); 3497ac58230SAlexander Motin break; 3507ac58230SAlexander Motin } 3517ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_snd); 3527ac58230SAlexander Motin error = sosend(softc->ha_so, NULL, NULL, softc->ha_sending, 3537ac58230SAlexander Motin NULL, MSG_DONTWAIT, curthread); 3547ac58230SAlexander Motin softc->ha_sending = NULL; 3557ac58230SAlexander Motin if (error != 0) { 3567ac58230SAlexander Motin printf("%s: sosend() error %d\n", __func__, error); 3577ac58230SAlexander Motin return; 3587ac58230SAlexander Motin } 3597ac58230SAlexander Motin }; 3607ac58230SAlexander Motin } 3617ac58230SAlexander Motin 3627ac58230SAlexander Motin static void 3637ac58230SAlexander Motin ctl_ha_sock_setup(struct ha_softc *softc) 3647ac58230SAlexander Motin { 3657ac58230SAlexander Motin struct sockopt opt; 3667ac58230SAlexander Motin struct socket *so = softc->ha_so; 3677ac58230SAlexander Motin int error, val; 3687ac58230SAlexander Motin 3697ac58230SAlexander Motin val = 1024 * 1024; 3707ac58230SAlexander Motin error = soreserve(so, val, val); 3717ac58230SAlexander Motin if (error) 3727ac58230SAlexander Motin printf("%s: soreserve failed %d\n", __func__, error); 3737ac58230SAlexander Motin 3747ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_rcv); 3757ac58230SAlexander Motin so->so_rcv.sb_lowat = sizeof(struct ha_msg_wire); 3767ac58230SAlexander Motin soupcall_set(so, SO_RCV, ctl_ha_rupcall, softc); 3777ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_rcv); 3787ac58230SAlexander Motin SOCKBUF_LOCK(&so->so_snd); 3797ac58230SAlexander Motin so->so_snd.sb_lowat = sizeof(struct ha_msg_wire); 3807ac58230SAlexander Motin soupcall_set(so, SO_SND, ctl_ha_supcall, softc); 3817ac58230SAlexander Motin SOCKBUF_UNLOCK(&so->so_snd); 3827ac58230SAlexander Motin 3837ac58230SAlexander Motin bzero(&opt, sizeof(struct sockopt)); 3847ac58230SAlexander Motin opt.sopt_dir = SOPT_SET; 3857ac58230SAlexander Motin opt.sopt_level = SOL_SOCKET; 3867ac58230SAlexander Motin opt.sopt_name = SO_KEEPALIVE; 3877ac58230SAlexander Motin opt.sopt_val = &val; 3887ac58230SAlexander Motin opt.sopt_valsize = sizeof(val); 3897ac58230SAlexander Motin val = 1; 3907ac58230SAlexander Motin error = sosetopt(so, &opt); 3917ac58230SAlexander Motin if (error) 3927ac58230SAlexander Motin printf("%s: KEEPALIVE setting failed %d\n", __func__, error); 3937ac58230SAlexander Motin 3947ac58230SAlexander Motin opt.sopt_level = IPPROTO_TCP; 3957ac58230SAlexander Motin opt.sopt_name = TCP_NODELAY; 3967ac58230SAlexander Motin val = 1; 3977ac58230SAlexander Motin error = sosetopt(so, &opt); 3987ac58230SAlexander Motin if (error) 3997ac58230SAlexander Motin printf("%s: NODELAY setting failed %d\n", __func__, error); 4007ac58230SAlexander Motin 4017ac58230SAlexander Motin opt.sopt_name = TCP_KEEPINIT; 4027ac58230SAlexander Motin val = 3; 4037ac58230SAlexander Motin error = sosetopt(so, &opt); 4047ac58230SAlexander Motin if (error) 4057ac58230SAlexander Motin printf("%s: KEEPINIT setting failed %d\n", __func__, error); 4067ac58230SAlexander Motin 4077ac58230SAlexander Motin opt.sopt_name = TCP_KEEPIDLE; 4087ac58230SAlexander Motin val = 1; 4097ac58230SAlexander Motin error = sosetopt(so, &opt); 4107ac58230SAlexander Motin if (error) 4117ac58230SAlexander Motin printf("%s: KEEPIDLE setting failed %d\n", __func__, error); 4127ac58230SAlexander Motin 4137ac58230SAlexander Motin opt.sopt_name = TCP_KEEPINTVL; 4147ac58230SAlexander Motin val = 1; 4157ac58230SAlexander Motin error = sosetopt(so, &opt); 4167ac58230SAlexander Motin if (error) 4177ac58230SAlexander Motin printf("%s: KEEPINTVL setting failed %d\n", __func__, error); 4187ac58230SAlexander Motin 4197ac58230SAlexander Motin opt.sopt_name = TCP_KEEPCNT; 4207ac58230SAlexander Motin val = 5; 4217ac58230SAlexander Motin error = sosetopt(so, &opt); 4227ac58230SAlexander Motin if (error) 4237ac58230SAlexander Motin printf("%s: KEEPCNT setting failed %d\n", __func__, error); 4247ac58230SAlexander Motin } 4257ac58230SAlexander Motin 4267ac58230SAlexander Motin static int 4277ac58230SAlexander Motin ctl_ha_connect(struct ha_softc *softc) 4287ac58230SAlexander Motin { 4297ac58230SAlexander Motin struct thread *td = curthread; 430*0bb9989cSAlexander Motin struct sockaddr_in sa; 4317ac58230SAlexander Motin struct socket *so; 4327ac58230SAlexander Motin int error; 4337ac58230SAlexander Motin 4347ac58230SAlexander Motin /* Create the socket */ 4357ac58230SAlexander Motin error = socreate(PF_INET, &so, SOCK_STREAM, 4367ac58230SAlexander Motin IPPROTO_TCP, td->td_ucred, td); 4377ac58230SAlexander Motin if (error != 0) { 4387ac58230SAlexander Motin printf("%s: socreate() error %d\n", __func__, error); 4397ac58230SAlexander Motin return (error); 4407ac58230SAlexander Motin } 4417ac58230SAlexander Motin softc->ha_so = so; 4427ac58230SAlexander Motin ctl_ha_sock_setup(softc); 4437ac58230SAlexander Motin 444*0bb9989cSAlexander Motin memcpy(&sa, &softc->ha_peer_in, sizeof(sa)); 445*0bb9989cSAlexander Motin error = soconnect(so, (struct sockaddr *)&sa, td); 4467ac58230SAlexander Motin if (error != 0) { 4477ac58230SAlexander Motin printf("%s: soconnect() error %d\n", __func__, error); 4487ac58230SAlexander Motin goto out; 4497ac58230SAlexander Motin } 4507ac58230SAlexander Motin return (0); 4517ac58230SAlexander Motin 4527ac58230SAlexander Motin out: 4537ac58230SAlexander Motin ctl_ha_close(softc); 4547ac58230SAlexander Motin return (error); 4557ac58230SAlexander Motin } 4567ac58230SAlexander Motin 4577ac58230SAlexander Motin static int 4587ac58230SAlexander Motin ctl_ha_accept(struct ha_softc *softc) 4597ac58230SAlexander Motin { 4607ac58230SAlexander Motin struct socket *so; 4617ac58230SAlexander Motin struct sockaddr *sap; 4627ac58230SAlexander Motin int error; 4637ac58230SAlexander Motin 4647ac58230SAlexander Motin ACCEPT_LOCK(); 4657ac58230SAlexander Motin if (softc->ha_lso->so_rcv.sb_state & SBS_CANTRCVMORE) 4667ac58230SAlexander Motin softc->ha_lso->so_error = ECONNABORTED; 4677ac58230SAlexander Motin if (softc->ha_lso->so_error) { 4687ac58230SAlexander Motin error = softc->ha_lso->so_error; 4697ac58230SAlexander Motin softc->ha_lso->so_error = 0; 4707ac58230SAlexander Motin ACCEPT_UNLOCK(); 4717ac58230SAlexander Motin printf("%s: socket error %d\n", __func__, error); 4727ac58230SAlexander Motin goto out; 4737ac58230SAlexander Motin } 4747ac58230SAlexander Motin so = TAILQ_FIRST(&softc->ha_lso->so_comp); 4757ac58230SAlexander Motin if (so == NULL) { 4767ac58230SAlexander Motin ACCEPT_UNLOCK(); 4777ac58230SAlexander Motin return (EWOULDBLOCK); 4787ac58230SAlexander Motin } 4797ac58230SAlexander Motin KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP")); 4807ac58230SAlexander Motin KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP")); 4817ac58230SAlexander Motin 4827ac58230SAlexander Motin /* 4837ac58230SAlexander Motin * Before changing the flags on the socket, we have to bump the 4847ac58230SAlexander Motin * reference count. Otherwise, if the protocol calls sofree(), 4857ac58230SAlexander Motin * the socket will be released due to a zero refcount. 4867ac58230SAlexander Motin */ 4877ac58230SAlexander Motin SOCK_LOCK(so); /* soref() and so_state update */ 4887ac58230SAlexander Motin soref(so); /* file descriptor reference */ 4897ac58230SAlexander Motin 4907ac58230SAlexander Motin TAILQ_REMOVE(&softc->ha_lso->so_comp, so, so_list); 4917ac58230SAlexander Motin softc->ha_lso->so_qlen--; 4927ac58230SAlexander Motin so->so_state |= SS_NBIO; 4937ac58230SAlexander Motin so->so_qstate &= ~SQ_COMP; 4947ac58230SAlexander Motin so->so_head = NULL; 4957ac58230SAlexander Motin 4967ac58230SAlexander Motin SOCK_UNLOCK(so); 4977ac58230SAlexander Motin ACCEPT_UNLOCK(); 4987ac58230SAlexander Motin 4997ac58230SAlexander Motin sap = NULL; 5007ac58230SAlexander Motin error = soaccept(so, &sap); 5017ac58230SAlexander Motin if (error != 0) { 5027ac58230SAlexander Motin printf("%s: soaccept() error %d\n", __func__, error); 5037ac58230SAlexander Motin if (sap != NULL) 5047ac58230SAlexander Motin free(sap, M_SONAME); 5057ac58230SAlexander Motin goto out; 5067ac58230SAlexander Motin } 5077ac58230SAlexander Motin if (sap != NULL) 5087ac58230SAlexander Motin free(sap, M_SONAME); 5097ac58230SAlexander Motin softc->ha_so = so; 5107ac58230SAlexander Motin ctl_ha_sock_setup(softc); 5117ac58230SAlexander Motin return (0); 5127ac58230SAlexander Motin 5137ac58230SAlexander Motin out: 5147ac58230SAlexander Motin ctl_ha_lclose(softc); 5157ac58230SAlexander Motin return (error); 5167ac58230SAlexander Motin } 5177ac58230SAlexander Motin 5187ac58230SAlexander Motin static int 5197ac58230SAlexander Motin ctl_ha_listen(struct ha_softc *softc) 5207ac58230SAlexander Motin { 5217ac58230SAlexander Motin struct thread *td = curthread; 522*0bb9989cSAlexander Motin struct sockaddr_in sa; 5237ac58230SAlexander Motin struct sockopt opt; 5247ac58230SAlexander Motin int error, val; 5257ac58230SAlexander Motin 5267ac58230SAlexander Motin /* Create the socket */ 5277ac58230SAlexander Motin if (softc->ha_lso == NULL) { 5287ac58230SAlexander Motin error = socreate(PF_INET, &softc->ha_lso, SOCK_STREAM, 5297ac58230SAlexander Motin IPPROTO_TCP, td->td_ucred, td); 5307ac58230SAlexander Motin if (error != 0) { 5317ac58230SAlexander Motin printf("%s: socreate() error %d\n", __func__, error); 5327ac58230SAlexander Motin return (error); 5337ac58230SAlexander Motin } 5347ac58230SAlexander Motin bzero(&opt, sizeof(struct sockopt)); 5357ac58230SAlexander Motin opt.sopt_dir = SOPT_SET; 5367ac58230SAlexander Motin opt.sopt_level = SOL_SOCKET; 5377ac58230SAlexander Motin opt.sopt_name = SO_REUSEADDR; 5387ac58230SAlexander Motin opt.sopt_val = &val; 5397ac58230SAlexander Motin opt.sopt_valsize = sizeof(val); 5407ac58230SAlexander Motin val = 1; 5417ac58230SAlexander Motin error = sosetopt(softc->ha_lso, &opt); 5427ac58230SAlexander Motin if (error) { 5437ac58230SAlexander Motin printf("%s: REUSEADDR setting failed %d\n", 5447ac58230SAlexander Motin __func__, error); 5457ac58230SAlexander Motin } 546a85700a9SAlexander Motin bzero(&opt, sizeof(struct sockopt)); 547a85700a9SAlexander Motin opt.sopt_dir = SOPT_SET; 548a85700a9SAlexander Motin opt.sopt_level = SOL_SOCKET; 549a85700a9SAlexander Motin opt.sopt_name = SO_REUSEPORT; 550a85700a9SAlexander Motin opt.sopt_val = &val; 551a85700a9SAlexander Motin opt.sopt_valsize = sizeof(val); 552a85700a9SAlexander Motin val = 1; 553a85700a9SAlexander Motin error = sosetopt(softc->ha_lso, &opt); 554a85700a9SAlexander Motin if (error) { 555a85700a9SAlexander Motin printf("%s: REUSEPORT setting failed %d\n", 556a85700a9SAlexander Motin __func__, error); 557a85700a9SAlexander Motin } 5587ac58230SAlexander Motin SOCKBUF_LOCK(&softc->ha_lso->so_rcv); 5597ac58230SAlexander Motin soupcall_set(softc->ha_lso, SO_RCV, ctl_ha_lupcall, softc); 5607ac58230SAlexander Motin SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); 5617ac58230SAlexander Motin } 5627ac58230SAlexander Motin 563*0bb9989cSAlexander Motin memcpy(&sa, &softc->ha_peer_in, sizeof(sa)); 564*0bb9989cSAlexander Motin error = sobind(softc->ha_lso, (struct sockaddr *)&sa, td); 5657ac58230SAlexander Motin if (error != 0) { 5667ac58230SAlexander Motin printf("%s: sobind() error %d\n", __func__, error); 5677ac58230SAlexander Motin goto out; 5687ac58230SAlexander Motin } 5697ac58230SAlexander Motin error = solisten(softc->ha_lso, 1, td); 5707ac58230SAlexander Motin if (error != 0) { 5717ac58230SAlexander Motin printf("%s: solisten() error %d\n", __func__, error); 5727ac58230SAlexander Motin goto out; 5737ac58230SAlexander Motin } 5747ac58230SAlexander Motin return (0); 5757ac58230SAlexander Motin 5767ac58230SAlexander Motin out: 5777ac58230SAlexander Motin ctl_ha_lclose(softc); 5787ac58230SAlexander Motin return (error); 5797ac58230SAlexander Motin } 5807ac58230SAlexander Motin 5817ac58230SAlexander Motin static void 5827ac58230SAlexander Motin ctl_ha_conn_thread(void *arg) 5837ac58230SAlexander Motin { 5847ac58230SAlexander Motin struct ha_softc *softc = arg; 5857ac58230SAlexander Motin int error; 5867ac58230SAlexander Motin 5877ac58230SAlexander Motin while (1) { 58859bb97a9SAlexander Motin if (softc->ha_disconnect || softc->ha_shutdown) { 5897ac58230SAlexander Motin ctl_ha_close(softc); 590a85700a9SAlexander Motin if (softc->ha_disconnect == 2 || softc->ha_shutdown) 5917ac58230SAlexander Motin ctl_ha_lclose(softc); 5927ac58230SAlexander Motin softc->ha_disconnect = 0; 59359bb97a9SAlexander Motin if (softc->ha_shutdown) 59459bb97a9SAlexander Motin break; 5957ac58230SAlexander Motin } else if (softc->ha_so != NULL && 5967ac58230SAlexander Motin (softc->ha_so->so_error || 5977ac58230SAlexander Motin softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) 5987ac58230SAlexander Motin ctl_ha_close(softc); 5997ac58230SAlexander Motin if (softc->ha_so == NULL) { 6007ac58230SAlexander Motin if (softc->ha_lso != NULL) 6017ac58230SAlexander Motin ctl_ha_accept(softc); 6027ac58230SAlexander Motin else if (softc->ha_listen) 6037ac58230SAlexander Motin ctl_ha_listen(softc); 6047ac58230SAlexander Motin else if (softc->ha_connect) 6057ac58230SAlexander Motin ctl_ha_connect(softc); 6067ac58230SAlexander Motin } 6077ac58230SAlexander Motin if (softc->ha_so != NULL) { 6087ac58230SAlexander Motin if (softc->ha_connected == 0 && 6097ac58230SAlexander Motin softc->ha_so->so_error == 0 && 6107ac58230SAlexander Motin (softc->ha_so->so_state & SS_ISCONNECTING) == 0) { 6117ac58230SAlexander Motin softc->ha_connected = 1; 6127ac58230SAlexander Motin ctl_ha_evt(softc, CTL_HA_CHAN_MAX, 6137ac58230SAlexander Motin CTL_HA_EVT_LINK_CHANGE, 6147ac58230SAlexander Motin CTL_HA_LINK_ONLINE); 6157ac58230SAlexander Motin softc->ha_receiving = 1; 6167ac58230SAlexander Motin error = kproc_kthread_add(ctl_ha_rx_thread, 6177ac58230SAlexander Motin softc, &softc->ha_ctl_softc->ctl_proc, 6187ac58230SAlexander Motin NULL, 0, 0, "ctl", "ha_rx"); 6197ac58230SAlexander Motin if (error != 0) { 6207ac58230SAlexander Motin printf("Error creating CTL HA rx thread!\n"); 6217ac58230SAlexander Motin softc->ha_receiving = 0; 6227ac58230SAlexander Motin softc->ha_disconnect = 1; 6237ac58230SAlexander Motin } 6247ac58230SAlexander Motin } 6257ac58230SAlexander Motin ctl_ha_send(softc); 6267ac58230SAlexander Motin } 6277ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 6287ac58230SAlexander Motin if (softc->ha_so != NULL && 6297ac58230SAlexander Motin (softc->ha_so->so_error || 6307ac58230SAlexander Motin softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) 6317ac58230SAlexander Motin ; 6327ac58230SAlexander Motin else if (!softc->ha_wakeup) 6337ac58230SAlexander Motin msleep(&softc->ha_wakeup, &softc->ha_lock, 0, "-", hz); 6347ac58230SAlexander Motin softc->ha_wakeup = 0; 6357ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 6367ac58230SAlexander Motin } 63759bb97a9SAlexander Motin mtx_lock(&softc->ha_lock); 63859bb97a9SAlexander Motin softc->ha_shutdown = 2; 63959bb97a9SAlexander Motin wakeup(&softc->ha_wakeup); 64059bb97a9SAlexander Motin mtx_unlock(&softc->ha_lock); 64159bb97a9SAlexander Motin kthread_exit(); 6427ac58230SAlexander Motin } 6437ac58230SAlexander Motin 6447ac58230SAlexander Motin static int 6457ac58230SAlexander Motin ctl_ha_peer_sysctl(SYSCTL_HANDLER_ARGS) 6467ac58230SAlexander Motin { 6477ac58230SAlexander Motin struct ha_softc *softc = (struct ha_softc *)arg1; 6487ac58230SAlexander Motin struct sockaddr_in *sa; 6497ac58230SAlexander Motin int error, b1, b2, b3, b4, p, num; 650e2c3044bSAlexander Motin char buf[128]; 6517ac58230SAlexander Motin 652e2c3044bSAlexander Motin strlcpy(buf, softc->ha_peer, sizeof(buf)); 653e2c3044bSAlexander Motin error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 654e2c3044bSAlexander Motin if ((error != 0) || (req->newptr == NULL) || 655e2c3044bSAlexander Motin strncmp(buf, softc->ha_peer, sizeof(buf)) == 0) 6567ac58230SAlexander Motin return (error); 6577ac58230SAlexander Motin 6587ac58230SAlexander Motin sa = &softc->ha_peer_in; 6597ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 660e2c3044bSAlexander Motin if ((num = sscanf(buf, "connect %d.%d.%d.%d:%d", 6617ac58230SAlexander Motin &b1, &b2, &b3, &b4, &p)) >= 4) { 6627ac58230SAlexander Motin softc->ha_connect = 1; 6637ac58230SAlexander Motin softc->ha_listen = 0; 664e2c3044bSAlexander Motin } else if ((num = sscanf(buf, "listen %d.%d.%d.%d:%d", 6657ac58230SAlexander Motin &b1, &b2, &b3, &b4, &p)) >= 4) { 6667ac58230SAlexander Motin softc->ha_connect = 0; 6677ac58230SAlexander Motin softc->ha_listen = 1; 6687ac58230SAlexander Motin } else { 6697ac58230SAlexander Motin softc->ha_connect = 0; 6707ac58230SAlexander Motin softc->ha_listen = 0; 671e2c3044bSAlexander Motin if (buf[0] != 0) { 672e2c3044bSAlexander Motin buf[0] = 0; 6737ac58230SAlexander Motin error = EINVAL; 6747ac58230SAlexander Motin } 675e2c3044bSAlexander Motin } 676e2c3044bSAlexander Motin strlcpy(softc->ha_peer, buf, sizeof(softc->ha_peer)); 6777ac58230SAlexander Motin if (softc->ha_connect || softc->ha_listen) { 6787ac58230SAlexander Motin memset(sa, 0, sizeof(*sa)); 6797ac58230SAlexander Motin sa->sin_len = sizeof(struct sockaddr_in); 6807ac58230SAlexander Motin sa->sin_family = AF_INET; 6817ac58230SAlexander Motin sa->sin_port = htons((num >= 5) ? p : 999); 6827ac58230SAlexander Motin sa->sin_addr.s_addr = 6837ac58230SAlexander Motin htonl((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); 6847ac58230SAlexander Motin } 685a85700a9SAlexander Motin softc->ha_disconnect = 2; 6867ac58230SAlexander Motin softc->ha_wakeup = 1; 6877ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 6887ac58230SAlexander Motin wakeup(&softc->ha_wakeup); 6897ac58230SAlexander Motin return (error); 6907ac58230SAlexander Motin } 6917ac58230SAlexander Motin 6927ac58230SAlexander Motin ctl_ha_status 6937ac58230SAlexander Motin ctl_ha_msg_register(ctl_ha_channel channel, ctl_evt_handler handler) 6947ac58230SAlexander Motin { 6957ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 6967ac58230SAlexander Motin 6977ac58230SAlexander Motin KASSERT(channel < CTL_HA_CHAN_MAX, 6987ac58230SAlexander Motin ("Wrong CTL HA channel %d", channel)); 6997ac58230SAlexander Motin softc->ha_handler[channel] = handler; 7007ac58230SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 7017ac58230SAlexander Motin } 7027ac58230SAlexander Motin 7037ac58230SAlexander Motin ctl_ha_status 7047ac58230SAlexander Motin ctl_ha_msg_deregister(ctl_ha_channel channel) 7057ac58230SAlexander Motin { 7067ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 7077ac58230SAlexander Motin 7087ac58230SAlexander Motin KASSERT(channel < CTL_HA_CHAN_MAX, 7097ac58230SAlexander Motin ("Wrong CTL HA channel %d", channel)); 7107ac58230SAlexander Motin softc->ha_handler[channel] = NULL; 7117ac58230SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 7127ac58230SAlexander Motin } 7137ac58230SAlexander Motin 7147ac58230SAlexander Motin /* 7157ac58230SAlexander Motin * Receive a message of the specified size. 7167ac58230SAlexander Motin */ 7177ac58230SAlexander Motin ctl_ha_status 7187ac58230SAlexander Motin ctl_ha_msg_recv(ctl_ha_channel channel, void *addr, size_t len, 7197ac58230SAlexander Motin int wait) 7207ac58230SAlexander Motin { 7217ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 7227ac58230SAlexander Motin struct uio uio; 7237ac58230SAlexander Motin struct iovec iov; 7247ac58230SAlexander Motin int error, flags; 7257ac58230SAlexander Motin 7267ac58230SAlexander Motin if (!softc->ha_connected) 7277ac58230SAlexander Motin return (CTL_HA_STATUS_DISCONNECT); 7287ac58230SAlexander Motin 7297ac58230SAlexander Motin iov.iov_base = addr; 7307ac58230SAlexander Motin iov.iov_len = len; 7317ac58230SAlexander Motin uio.uio_iov = &iov; 7327ac58230SAlexander Motin uio.uio_iovcnt = 1; 7337ac58230SAlexander Motin uio.uio_rw = UIO_READ; 7347ac58230SAlexander Motin uio.uio_segflg = UIO_SYSSPACE; 7357ac58230SAlexander Motin uio.uio_td = curthread; 7367ac58230SAlexander Motin uio.uio_resid = len; 7377ac58230SAlexander Motin flags = wait ? 0 : MSG_DONTWAIT; 7387ac58230SAlexander Motin error = soreceive(softc->ha_so, NULL, &uio, NULL, NULL, &flags); 7397ac58230SAlexander Motin if (error == 0) 7407ac58230SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 7417ac58230SAlexander Motin 7427ac58230SAlexander Motin /* Consider all errors fatal for HA sanity. */ 7437ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 7447ac58230SAlexander Motin if (softc->ha_connected) { 7457ac58230SAlexander Motin softc->ha_disconnect = 1; 7467ac58230SAlexander Motin softc->ha_wakeup = 1; 7477ac58230SAlexander Motin wakeup(&softc->ha_wakeup); 7487ac58230SAlexander Motin } 7497ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 7507ac58230SAlexander Motin return (CTL_HA_STATUS_ERROR); 7517ac58230SAlexander Motin } 7527ac58230SAlexander Motin 7537ac58230SAlexander Motin /* 7547ac58230SAlexander Motin * Send a message of the specified size. 7557ac58230SAlexander Motin */ 7567ac58230SAlexander Motin ctl_ha_status 7577ac58230SAlexander Motin ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr, size_t len, 7587ac58230SAlexander Motin const void *addr2, size_t len2, int wait) 7597ac58230SAlexander Motin { 7607ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 7617ac58230SAlexander Motin struct mbuf *mb, *newmb; 7627ac58230SAlexander Motin struct ha_msg_wire hdr; 7637ac58230SAlexander Motin size_t copylen, off; 7647ac58230SAlexander Motin 7657ac58230SAlexander Motin if (!softc->ha_connected) 7667ac58230SAlexander Motin return (CTL_HA_STATUS_DISCONNECT); 7677ac58230SAlexander Motin 7687ac58230SAlexander Motin newmb = m_getm2(NULL, sizeof(hdr) + len + len2, wait, MT_DATA, 7697ac58230SAlexander Motin M_PKTHDR); 7707ac58230SAlexander Motin if (newmb == NULL) { 7717ac58230SAlexander Motin /* Consider all errors fatal for HA sanity. */ 7727ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 7737ac58230SAlexander Motin if (softc->ha_connected) { 7747ac58230SAlexander Motin softc->ha_disconnect = 1; 7757ac58230SAlexander Motin softc->ha_wakeup = 1; 7767ac58230SAlexander Motin wakeup(&softc->ha_wakeup); 7777ac58230SAlexander Motin } 7787ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 7797ac58230SAlexander Motin printf("%s: Can't allocate mbuf chain\n", __func__); 7807ac58230SAlexander Motin return (CTL_HA_STATUS_ERROR); 7817ac58230SAlexander Motin } 7827ac58230SAlexander Motin hdr.channel = channel; 7837ac58230SAlexander Motin hdr.length = len + len2; 7847ac58230SAlexander Motin mb = newmb; 7857ac58230SAlexander Motin memcpy(mtodo(mb, 0), &hdr, sizeof(hdr)); 7867ac58230SAlexander Motin mb->m_len += sizeof(hdr); 7877ac58230SAlexander Motin off = 0; 7887ac58230SAlexander Motin for (; mb != NULL && off < len; mb = mb->m_next) { 7897ac58230SAlexander Motin copylen = min(M_TRAILINGSPACE(mb), len - off); 7907ac58230SAlexander Motin memcpy(mtodo(mb, mb->m_len), (const char *)addr + off, copylen); 7917ac58230SAlexander Motin mb->m_len += copylen; 7927ac58230SAlexander Motin off += copylen; 7937ac58230SAlexander Motin if (off == len) 7947ac58230SAlexander Motin break; 7957ac58230SAlexander Motin } 7967ac58230SAlexander Motin KASSERT(off == len, ("%s: off (%zu) != len (%zu)", __func__, 7977ac58230SAlexander Motin off, len)); 7987ac58230SAlexander Motin off = 0; 7997ac58230SAlexander Motin for (; mb != NULL && off < len2; mb = mb->m_next) { 8007ac58230SAlexander Motin copylen = min(M_TRAILINGSPACE(mb), len2 - off); 8017ac58230SAlexander Motin memcpy(mtodo(mb, mb->m_len), (const char *)addr2 + off, copylen); 8027ac58230SAlexander Motin mb->m_len += copylen; 8037ac58230SAlexander Motin off += copylen; 8047ac58230SAlexander Motin } 8057ac58230SAlexander Motin KASSERT(off == len2, ("%s: off (%zu) != len2 (%zu)", __func__, 8067ac58230SAlexander Motin off, len2)); 8077ac58230SAlexander Motin newmb->m_pkthdr.len = sizeof(hdr) + len + len2; 8087ac58230SAlexander Motin 8097ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 8107ac58230SAlexander Motin if (!softc->ha_connected) { 8117ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 8127ac58230SAlexander Motin m_freem(newmb); 8137ac58230SAlexander Motin return (CTL_HA_STATUS_DISCONNECT); 8147ac58230SAlexander Motin } 8157ac58230SAlexander Motin mbufq_enqueue(&softc->ha_sendq, newmb); 8167ac58230SAlexander Motin softc->ha_wakeup = 1; 8177ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 8187ac58230SAlexander Motin wakeup(&softc->ha_wakeup); 8197ac58230SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 8207ac58230SAlexander Motin } 8217ac58230SAlexander Motin 8227ac58230SAlexander Motin ctl_ha_status 8237ac58230SAlexander Motin ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, size_t len, 8247ac58230SAlexander Motin int wait) 8257ac58230SAlexander Motin { 8267ac58230SAlexander Motin 8277ac58230SAlexander Motin return (ctl_ha_msg_send2(channel, addr, len, NULL, 0, wait)); 8287ac58230SAlexander Motin } 8297ac58230SAlexander Motin 830a85700a9SAlexander Motin ctl_ha_status 831a85700a9SAlexander Motin ctl_ha_msg_abort(ctl_ha_channel channel) 832a85700a9SAlexander Motin { 833a85700a9SAlexander Motin struct ha_softc *softc = &ha_softc; 834a85700a9SAlexander Motin 835a85700a9SAlexander Motin mtx_lock(&softc->ha_lock); 836a85700a9SAlexander Motin softc->ha_disconnect = 1; 837a85700a9SAlexander Motin softc->ha_wakeup = 1; 838a85700a9SAlexander Motin mtx_unlock(&softc->ha_lock); 839a85700a9SAlexander Motin wakeup(&softc->ha_wakeup); 840a85700a9SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 841a85700a9SAlexander Motin } 842a85700a9SAlexander Motin 8437ac58230SAlexander Motin /* 8447ac58230SAlexander Motin * Allocate a data transfer request structure. 8457ac58230SAlexander Motin */ 8467ac58230SAlexander Motin struct ctl_ha_dt_req * 8477ac58230SAlexander Motin ctl_dt_req_alloc(void) 8487ac58230SAlexander Motin { 8497ac58230SAlexander Motin 8507ac58230SAlexander Motin return (malloc(sizeof(struct ctl_ha_dt_req), M_CTL, M_WAITOK | M_ZERO)); 8517ac58230SAlexander Motin } 8527ac58230SAlexander Motin 8537ac58230SAlexander Motin /* 8547ac58230SAlexander Motin * Free a data transfer request structure. 8557ac58230SAlexander Motin */ 8567ac58230SAlexander Motin void 8577ac58230SAlexander Motin ctl_dt_req_free(struct ctl_ha_dt_req *req) 8587ac58230SAlexander Motin { 8597ac58230SAlexander Motin 8607ac58230SAlexander Motin free(req, M_CTL); 8617ac58230SAlexander Motin } 8627ac58230SAlexander Motin 8637ac58230SAlexander Motin /* 8647ac58230SAlexander Motin * Issue a DMA request for a single buffer. 8657ac58230SAlexander Motin */ 8667ac58230SAlexander Motin ctl_ha_status 8677ac58230SAlexander Motin ctl_dt_single(struct ctl_ha_dt_req *req) 8687ac58230SAlexander Motin { 8697ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 8707ac58230SAlexander Motin struct ha_dt_msg_wire wire_dt; 8717ac58230SAlexander Motin ctl_ha_status status; 8727ac58230SAlexander Motin 8737ac58230SAlexander Motin wire_dt.command = req->command; 8747ac58230SAlexander Motin wire_dt.size = req->size; 8757ac58230SAlexander Motin wire_dt.local = req->local; 8767ac58230SAlexander Motin wire_dt.remote = req->remote; 8777ac58230SAlexander Motin if (req->command == CTL_HA_DT_CMD_READ && req->callback != NULL) { 8787ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 8797ac58230SAlexander Motin TAILQ_INSERT_TAIL(&softc->ha_dts, req, links); 8807ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 8817ac58230SAlexander Motin ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, sizeof(wire_dt), 8827ac58230SAlexander Motin M_WAITOK); 8837ac58230SAlexander Motin return (CTL_HA_STATUS_WAIT); 8847ac58230SAlexander Motin } 8857ac58230SAlexander Motin if (req->command == CTL_HA_DT_CMD_READ) { 8867ac58230SAlexander Motin status = ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, 8877ac58230SAlexander Motin sizeof(wire_dt), M_WAITOK); 8887ac58230SAlexander Motin } else { 8897ac58230SAlexander Motin status = ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, 8907ac58230SAlexander Motin sizeof(wire_dt), req->local, req->size, M_WAITOK); 8917ac58230SAlexander Motin } 8927ac58230SAlexander Motin return (status); 8937ac58230SAlexander Motin } 8947ac58230SAlexander Motin 8957ac58230SAlexander Motin static void 8967ac58230SAlexander Motin ctl_dt_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) 8977ac58230SAlexander Motin { 8987ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 8997ac58230SAlexander Motin struct ctl_ha_dt_req *req; 9007ac58230SAlexander Motin ctl_ha_status isc_status; 9017ac58230SAlexander Motin 9027ac58230SAlexander Motin if (event == CTL_HA_EVT_MSG_RECV) { 9037ac58230SAlexander Motin struct ha_dt_msg_wire wire_dt; 9047ac58230SAlexander Motin uint8_t *tmp; 9057ac58230SAlexander Motin int size; 9067ac58230SAlexander Motin 9077ac58230SAlexander Motin size = min(sizeof(wire_dt), param); 9087ac58230SAlexander Motin isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, &wire_dt, 9097ac58230SAlexander Motin size, M_WAITOK); 9107ac58230SAlexander Motin if (isc_status != CTL_HA_STATUS_SUCCESS) { 9117ac58230SAlexander Motin printf("%s: Error receiving message: %d\n", 9127ac58230SAlexander Motin __func__, isc_status); 9137ac58230SAlexander Motin return; 9147ac58230SAlexander Motin } 9157ac58230SAlexander Motin 9167ac58230SAlexander Motin if (wire_dt.command == CTL_HA_DT_CMD_READ) { 9177ac58230SAlexander Motin wire_dt.command = CTL_HA_DT_CMD_WRITE; 9187ac58230SAlexander Motin tmp = wire_dt.local; 9197ac58230SAlexander Motin wire_dt.local = wire_dt.remote; 9207ac58230SAlexander Motin wire_dt.remote = tmp; 9217ac58230SAlexander Motin ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, 9227ac58230SAlexander Motin sizeof(wire_dt), wire_dt.local, wire_dt.size, 9237ac58230SAlexander Motin M_WAITOK); 9247ac58230SAlexander Motin } else if (wire_dt.command == CTL_HA_DT_CMD_WRITE) { 9257ac58230SAlexander Motin isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, 9267ac58230SAlexander Motin wire_dt.remote, wire_dt.size, M_WAITOK); 9277ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 9287ac58230SAlexander Motin TAILQ_FOREACH(req, &softc->ha_dts, links) { 9297ac58230SAlexander Motin if (req->local == wire_dt.remote) { 9307ac58230SAlexander Motin TAILQ_REMOVE(&softc->ha_dts, req, links); 9317ac58230SAlexander Motin break; 9327ac58230SAlexander Motin } 9337ac58230SAlexander Motin } 9347ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 9357ac58230SAlexander Motin if (req) { 9367ac58230SAlexander Motin req->ret = isc_status; 9377ac58230SAlexander Motin req->callback(req); 9387ac58230SAlexander Motin } 9397ac58230SAlexander Motin } 9407ac58230SAlexander Motin } else if (event == CTL_HA_EVT_LINK_CHANGE) { 9417ac58230SAlexander Motin CTL_DEBUG_PRINT(("%s: Link state change to %d\n", __func__, 9427ac58230SAlexander Motin param)); 9437ac58230SAlexander Motin if (param != CTL_HA_LINK_ONLINE) { 9447ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 9457ac58230SAlexander Motin while ((req = TAILQ_FIRST(&softc->ha_dts)) != NULL) { 9467ac58230SAlexander Motin TAILQ_REMOVE(&softc->ha_dts, req, links); 9477ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 9487ac58230SAlexander Motin req->ret = CTL_HA_STATUS_DISCONNECT; 9497ac58230SAlexander Motin req->callback(req); 9507ac58230SAlexander Motin mtx_lock(&softc->ha_lock); 9517ac58230SAlexander Motin } 9527ac58230SAlexander Motin mtx_unlock(&softc->ha_lock); 9537ac58230SAlexander Motin } 9547ac58230SAlexander Motin } else { 9557ac58230SAlexander Motin printf("%s: Unknown event %d\n", __func__, event); 9567ac58230SAlexander Motin } 9577ac58230SAlexander Motin } 9587ac58230SAlexander Motin 9597ac58230SAlexander Motin 9607ac58230SAlexander Motin ctl_ha_status 9617ac58230SAlexander Motin ctl_ha_msg_init(struct ctl_softc *ctl_softc) 9627ac58230SAlexander Motin { 9637ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 9647ac58230SAlexander Motin int error; 9657ac58230SAlexander Motin 9667ac58230SAlexander Motin softc->ha_ctl_softc = ctl_softc; 9677ac58230SAlexander Motin mtx_init(&softc->ha_lock, "CTL HA mutex", NULL, MTX_DEF); 9687ac58230SAlexander Motin mbufq_init(&softc->ha_sendq, INT_MAX); 9697ac58230SAlexander Motin TAILQ_INIT(&softc->ha_dts); 9707ac58230SAlexander Motin error = kproc_kthread_add(ctl_ha_conn_thread, softc, 9717ac58230SAlexander Motin &ctl_softc->ctl_proc, NULL, 0, 0, "ctl", "ha_tx"); 9727ac58230SAlexander Motin if (error != 0) { 9737ac58230SAlexander Motin printf("error creating CTL HA connection thread!\n"); 9747ac58230SAlexander Motin mtx_destroy(&softc->ha_lock); 9757ac58230SAlexander Motin return (CTL_HA_STATUS_ERROR); 9767ac58230SAlexander Motin } 97759bb97a9SAlexander Motin softc->ha_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, 97859bb97a9SAlexander Motin ctl_ha_msg_shutdown, ctl_softc, SHUTDOWN_PRI_FIRST); 9797ac58230SAlexander Motin SYSCTL_ADD_PROC(&ctl_softc->sysctl_ctx, 9807ac58230SAlexander Motin SYSCTL_CHILDREN(ctl_softc->sysctl_tree), 9817ac58230SAlexander Motin OID_AUTO, "ha_peer", CTLTYPE_STRING | CTLFLAG_RWTUN, 9827ac58230SAlexander Motin softc, 0, ctl_ha_peer_sysctl, "A", "HA peer connection method"); 9837ac58230SAlexander Motin 9847ac58230SAlexander Motin if (ctl_ha_msg_register(CTL_HA_CHAN_DATA, ctl_dt_event_handler) 9857ac58230SAlexander Motin != CTL_HA_STATUS_SUCCESS) { 9867ac58230SAlexander Motin printf("%s: ctl_ha_msg_register failed.\n", __func__); 9877ac58230SAlexander Motin } 9887ac58230SAlexander Motin 9897ac58230SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 9907ac58230SAlexander Motin }; 9917ac58230SAlexander Motin 99259bb97a9SAlexander Motin void 9937ac58230SAlexander Motin ctl_ha_msg_shutdown(struct ctl_softc *ctl_softc) 9947ac58230SAlexander Motin { 9957ac58230SAlexander Motin struct ha_softc *softc = &ha_softc; 9967ac58230SAlexander Motin 99759bb97a9SAlexander Motin /* Disconnect and shutdown threads. */ 99859bb97a9SAlexander Motin mtx_lock(&softc->ha_lock); 99959bb97a9SAlexander Motin if (softc->ha_shutdown < 2) { 100059bb97a9SAlexander Motin softc->ha_shutdown = 1; 100159bb97a9SAlexander Motin softc->ha_wakeup = 1; 100259bb97a9SAlexander Motin wakeup(&softc->ha_wakeup); 100359bb97a9SAlexander Motin while (softc->ha_shutdown < 2) { 100459bb97a9SAlexander Motin msleep(&softc->ha_wakeup, &softc->ha_lock, 0, 100559bb97a9SAlexander Motin "shutdown", hz); 10067ac58230SAlexander Motin } 100759bb97a9SAlexander Motin } 100859bb97a9SAlexander Motin mtx_unlock(&softc->ha_lock); 100959bb97a9SAlexander Motin }; 101059bb97a9SAlexander Motin 101159bb97a9SAlexander Motin ctl_ha_status 101259bb97a9SAlexander Motin ctl_ha_msg_destroy(struct ctl_softc *ctl_softc) 101359bb97a9SAlexander Motin { 101459bb97a9SAlexander Motin struct ha_softc *softc = &ha_softc; 101559bb97a9SAlexander Motin 101659bb97a9SAlexander Motin if (softc->ha_shutdown_eh != NULL) { 101759bb97a9SAlexander Motin EVENTHANDLER_DEREGISTER(shutdown_pre_sync, 101859bb97a9SAlexander Motin softc->ha_shutdown_eh); 101959bb97a9SAlexander Motin softc->ha_shutdown_eh = NULL; 102059bb97a9SAlexander Motin } 102159bb97a9SAlexander Motin 102259bb97a9SAlexander Motin ctl_ha_msg_shutdown(ctl_softc); /* Just in case. */ 102359bb97a9SAlexander Motin 102459bb97a9SAlexander Motin if (ctl_ha_msg_deregister(CTL_HA_CHAN_DATA) != CTL_HA_STATUS_SUCCESS) 102559bb97a9SAlexander Motin printf("%s: ctl_ha_msg_deregister failed.\n", __func__); 10267ac58230SAlexander Motin 10277ac58230SAlexander Motin mtx_destroy(&softc->ha_lock); 10287ac58230SAlexander Motin return (CTL_HA_STATUS_SUCCESS); 10297ac58230SAlexander Motin }; 1030